diff --git a/src/generators/web/utils/__tests__/processing.test.mjs b/src/generators/web/utils/__tests__/processing.test.mjs index afbc64c3..c2aa4469 100644 --- a/src/generators/web/utils/__tests__/processing.test.mjs +++ b/src/generators/web/utils/__tests__/processing.test.mjs @@ -1,7 +1,22 @@ import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; -import { populateWithEvaluation } from '../processing.mjs'; +import { + default as getConfig, + setConfig, +} from '../../../../utils/configuration/index.mjs'; +import { populateWithEvaluation, resolvePageRoot } from '../processing.mjs'; + +await setConfig({ + version: 'v22.0.0', + changelog: [], + generators: { + web: { + useAbsoluteURLs: false, + baseURL: 'https://nodejs.org/docs', + }, + }, +}); describe('populateWithEvaluation', () => { it('substitutes simple ${variable} placeholders', () => { @@ -61,3 +76,30 @@ describe('populateWithEvaluation', () => { assert.strictEqual(result, 'count: 42'); }); }); + +describe('resolvePageRoot', () => { + it('keeps relative roots for regular pages', () => { + const result = resolvePageRoot({ path: '/api/fs' }); + assert.strictEqual(result, '../'); + }); + + it('uses the server root for synthetic pages', () => { + const result = resolvePageRoot({ + path: '/404', + synthetic: true, + }); + assert.strictEqual(result, '/'); + }); + + it('uses the configured base URL for synthetic pages with absolute URLs', async () => { + getConfig('web').useAbsoluteURLs = true; + + const result = resolvePageRoot({ + path: '/404', + synthetic: true, + }); + assert.strictEqual(result, 'https://nodejs.org/docs/'); + + getConfig('web').useAbsoluteURLs = false; + }); +}); diff --git a/src/generators/web/utils/processing.mjs b/src/generators/web/utils/processing.mjs index 5b528ff5..d09191b6 100644 --- a/src/generators/web/utils/processing.mjs +++ b/src/generators/web/utils/processing.mjs @@ -31,6 +31,20 @@ export const populateWithEvaluation = (template, config) => { return fn(...values); }; +/** + * @param {import('../../metadata/types').MetadataEntry} data + * @returns {string} + */ +export const resolvePageRoot = data => { + if (data.synthetic === true) { + const { baseURL, useAbsoluteURLs } = getConfig('web'); + return useAbsoluteURLs ? String(baseURL).replace(/\/?$/, '/') : '/'; + } + + const unresolvedRoot = relativeOrAbsolute('/', data.path); + return unresolvedRoot.endsWith('/') ? unresolvedRoot : `${unresolvedRoot}/`; +}; + /** * Converts JSX AST entries to server and client JavaScript code. * @@ -131,10 +145,7 @@ export async function processJSXEntries( // Step 3: Render final HTML pages const results = await Promise.all( entries.map(async ({ data }) => { - const unresolvedRoot = relativeOrAbsolute('/', data.path); - const root = unresolvedRoot.endsWith('/') - ? unresolvedRoot - : `${unresolvedRoot}/`; + const root = resolvePageRoot(data); // Replace template placeholders with actual content const renderedHtml = populateWithEvaluation(template, {