Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-dollar-replacement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@node-core/doc-kit-legacy': patch
'@node-core/doc-kit': patch
'@doc-kit/generator-react': patch
---

Fix `$$`, `$&`, `` $` `` and `$'` in page content being treated as `String.prototype.replace` replacement patterns instead of literal text. This affected the legacy HTML generator's page and navigation content, the man page generator's options/environment sections, and the sitemap generator's URL entries.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

import assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';

import { setConfig } from '@doc-kit/core/utils/configuration/index.mjs';

import { replaceTemplateValues } from '../replaceTemplateValues.mjs';

describe('replaceTemplateValues', () => {
before(() => setConfig({}));

const baseValues = {
path: '/test',
api: 'test',
added: undefined,
section: 'section',
toc: [],
nav: 'nav',
content: 'content',
};

const config = { version: { version: '1.0.0' }, changelog: [] };

it('does not treat `$$`, `$&`, "$`" and `$\'` in content as replacement patterns', () => {
const template = '<main>__CONTENT__</main><nav>__GTOC__</nav>';

const dollarContent = 'dirname "$$(command -v node)" $& $` $\'';

const output = replaceTemplateValues(
template,
{ ...baseValues, content: dollarContent },
config,
{ skipGitHub: true }
);

assert.match(
output,
/<main>dirname "\$\$\(command -v node\)" \$& \$` \$'<\/main>/
);
});

it('does not treat `$$`, `$&`, "$`" and `$\'` in nav as replacement patterns', () => {
const template = '<main>__CONTENT__</main><nav>__GTOC__</nav>';

const dollarNav = "nav $$ $& $` $'";

const output = replaceTemplateValues(
template,
{ ...baseValues, nav: dollarNav },
config,
{ skipGitHub: true }
);

assert.match(output, /<nav>nav \$\$ \$& \$` \$'<\/nav>/);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ export const replaceTemplateValues = (
return apiTemplate
.replace('__ID__', api)
.replace(/__FILENAME__/g, api)
.replace('__SECTION__', section)
.replace('__SECTION__', () => section)
.replace(/__VERSION__/g, `v${config.version.version}`)
.replace(/__TOC__/g, tableOfContents.wrapToC(toc))
.replace(/__GTOC__/g, nav)
.replace('__CONTENT__', content)
.replace(/__TOC_PICKER__/g, buildToC(toc))
.replace(/__GTOC_PICKER__/g, skipGtocPicker ? '' : buildNavigation(nav))
.replace('__ALTDOCS__', buildVersions(path, added, config.changelog))
.replace(
'__EDIT_ON_GITHUB__',
.replace(/__TOC__/g, () => tableOfContents.wrapToC(toc))
.replace(/__GTOC__/g, () => nav)
.replace('__CONTENT__', () => content)
.replace(/__TOC_PICKER__/g, () => buildToC(toc))
.replace(/__GTOC_PICKER__/g, () =>
skipGtocPicker ? '' : buildNavigation(nav)
)
.replace('__ALTDOCS__', () => buildVersions(path, added, config.changelog))
.replace('__EDIT_ON_GITHUB__', () =>
skipGitHub
? ''
: buildGitHub(populate(config.editURL, { ...config, path }))
Expand Down
4 changes: 2 additions & 2 deletions packages/node/src/man-page/generate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export async function generate(input) {
const template = await readFile(config.templatePath, 'utf-8');

const filledTemplate = template
.replace('__OPTIONS__', output.options)
.replace('__ENVIRONMENT__', output.env);
.replace('__OPTIONS__', () => output.options)
.replace('__ENVIRONMENT__', () => output.env);

if (config.output) {
await writeFile(join(config.output, config.fileName), filledTemplate);
Expand Down
10 changes: 5 additions & 5 deletions packages/react/src/sitemap/generate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ export async function generate(entries) {
const urlset = apiPages
.map(page =>
entryTemplate
.replace('__LOC__', page.loc)
.replace('__LASTMOD__', page.lastmod)
.replace('__CHANGEFREQ__', page.changefreq)
.replace('__PRIORITY__', page.priority)
.replace('__LOC__', () => page.loc)
.replace('__LASTMOD__', () => page.lastmod)
.replace('__CHANGEFREQ__', () => page.changefreq)
.replace('__PRIORITY__', () => page.priority)
)
.join('');

const sitemap = template.replace('__URLSET__', urlset);
const sitemap = template.replace('__URLSET__', () => urlset);

if (config.output) {
await writeFile(join(config.output, 'sitemap.xml'), sitemap, 'utf-8');
Expand Down