diff --git a/internal/check-locale-reachable.mjs b/internal/check-locale-reachable.mjs index e0d777eb9..ab2a18bf6 100644 --- a/internal/check-locale-reachable.mjs +++ b/internal/check-locale-reachable.mjs @@ -31,9 +31,40 @@ const SUPPORTED = (src.match(/SUPPORTED_LOCALES = \[([^\]]*)\]/) || [])[1] // Evaluate the SHIPPED detectLocale rather than reimplementing it — a gate that // reimplements the thing it tests only ever proves the copy agrees with itself. -const body = src.slice(src.indexOf('export function detectLocale'), src.indexOf('export function createAppI18n')) +// ★ TAKE THE FUNCTION, NOT THE GAP BETWEEN TWO LANDMARKS. +// This used to slice from `export function detectLocale` to `export function createAppI18n` and eval +// whatever lay between. That is a promise about the ORDER OF A FILE the gate does not own: the day +// someone exported a helper between those two lines, the slice carried a bare `export` into +// new Function() and this gate died with "Unexpected token 'export'" — twice, once for a helper I +// added myself. It was then "fixed" by moving the helper, which only re-armed the trap for the next +// person. Extract detectLocale by matching its own braces, and strip any export keyword that +// survives, so the gate reads the function it names and nothing else. +function extractFunction(source, name) { + const start = source.search(new RegExp('(export\\s+)?function\\s+' + name + '\\s*\\(')) + if (start < 0) return '' + const open = source.indexOf('{', start) + if (open < 0) return '' + let depth = 0 + for (let i = open; i < source.length; i++) { + const ch = source[i] + if (ch === '{') depth++ + else if (ch === '}') { + depth-- + if (depth === 0) return source.slice(start, i + 1) + } + } + return '' +} +const body = extractFunction(src, 'detectLocale').replace(/\bexport\s+/g, '') +if (!body) { + console.error('LOCALE-REACHABLE: FAIL — could not find detectLocale() in library/i18n/index.js.') + console.error(' The gate evaluates the SHIPPED function rather than reimplementing it, so if the') + console.error(' function is renamed this must be updated — silence here would be a gate that') + console.error(' stopped testing anything.') + process.exit(1) +} const make = new Function('SUPPORTED_LOCALES', 'window', 'document', - `${body.replace('export function', 'return function')}\n; return detectLocale;`) + `${body}\n; return detectLocale;`) const detect = (search, htmlLang) => make(SUPPORTED, { location: { search } }, { documentElement: { lang: htmlLang } })()