import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { describe, expect, it } from 'vitest'; import { getNestedValue, interpolate } from './index.svelte'; /** * Benchmark gate for the `t()` hot path: the split-path cache in * `getNestedValue` and the `{{` guard in `interpolate`. * * Audit finding: the locale dicts are nested, so every `t('a.b.c')` call * re-split its key into a fresh array and walked the tree, and `interpolate` * ran its global-regex `.replace` scan even though the vast majority of UI * strings carry no `{{placeholder}}`. A rendered list row calls `t()` ~10×, * so a 40-row paint pays ~400 walk+split-allocs + regex scans. The fix * caches the resolved value per (dict, key) — dicts are load-once-immutable * and the key set is the app's finite static strings — and skips the regex * when the string has no `{{`. * * Gates: byte-identical results vs the pre-fix reference implementations * across the real shipped en.json (nested keys, flat keys, underscore * fallback, missing keys, placeholder strings — cold AND warm, so a stale or * poisoned cache entry fails loudly), and a ≥1.5x speedup on a mixed * 20k-call workload. */ type Dict = { [key: string]: string | Dict }; const enDict = JSON.parse( readFileSync(resolve(__dirname, '../../../static/locales/en.json'), 'utf8') ) as Dict; /** Pre-fix `getNestedValue`, verbatim: fresh `split('.')` on every call. */ function referenceGetNestedValue(obj: Dict | undefined, path: string): string | null { if (obj && typeof obj === 'object' && path in obj) { const value = obj[path]; return typeof value === 'string' ? value : null; } const keys = path.split('.'); let current: unknown = obj; for (const key of keys) { if (current && typeof current === 'object' && key in (current as Dict)) { current = (current as Dict)[key]; } else { if (path.includes('_') && !path.includes('.')) { const [prefix, ...parts] = path.split('_'); const suffix = parts.join('_'); const branch = obj?.[prefix]; if (branch && typeof branch === 'object' && suffix in (branch as Dict)) { const v = (branch as Dict)[suffix]; return typeof v === 'string' ? v : null; } } return null; } } return typeof current === 'string' ? current : null; } /** Pre-fix `interpolate`, verbatim: unconditional regex `.replace`. */ function referenceInterpolate(text: string, params: Record): string { return text.replace(/{{\s*([^}]+)\s*}}/g, (_, key: string) => { const k = key.trim(); return params[k] !== undefined ? String(params[k]) : `{{${key}}}`; }); } /** Every dotted leaf path in the dict (the app's real key population). */ function collectKeys(obj: Dict, prefix = '', out: string[] = []): string[] { for (const [k, v] of Object.entries(obj)) { const path = prefix ? `${prefix}.${k}` : k; if (typeof v === 'string') out.push(path); else collectKeys(v, path, out); } return out; } const allKeys = collectKeys(enDict); // A workload mix mirroring real renders: mostly present nested keys, plus // underscore-fallback forms, flat keys, and misses. const workload: string[] = [ ...allKeys, 'errors_loadFailed', // underscore fallback form 'groupby_modifiedAt', 'nav.files', 'this.key.does.not.exist', 'nokey', 'files.deeply.missing.leaf' ]; const PARAMS = { n: 42, count: 7, email: 'x@y.z', name: 'Ada' }; describe('t() hot path: split cache + interpolate guard (benchmark gate)', () => { it('getNestedValue is byte-identical to the split-per-call reference on every real key', () => { expect(allKeys.length).toBeGreaterThan(300); for (const key of workload) { expect(getNestedValue(enDict, key), key).toBe(referenceGetNestedValue(enDict, key)); } // Repeat with the cache warm — a poisoned/shared split array would show here. for (const key of workload) { expect(getNestedValue(enDict, key), `warm:${key}`).toBe(referenceGetNestedValue(enDict, key)); } }); it('interpolate is byte-identical to the unguarded reference', () => { const texts = [ // Keys whose segments contain literal dots aren't resolvable via a // dotted path — drop the nulls (both implementations agree on them, // covered by the lookup-equivalence test above). ...allKeys .map((k) => referenceGetNestedValue(enDict, k)) .filter((v): v is string => v !== null), 'Move {{n}} items to trash?', '{{ n }} spaced', // padded placeholder '{{unknown}} stays intact', 'no placeholders at all', 'brace but not double { x }', '{{n}}{{count}}back-to-back', '' ]; let withPlaceholders = 0; for (const text of texts) { if (text.includes('{{')) withPlaceholders++; expect(interpolate(text, PARAMS), JSON.stringify(text)).toBe( referenceInterpolate(text, PARAMS) ); expect(interpolate(text, {}), `noparams:${JSON.stringify(text)}`).toBe( referenceInterpolate(text, {}) ); } // The workload genuinely exercises both branches of the guard. expect(withPlaceholders).toBeGreaterThan(50); expect(withPlaceholders).toBeLessThan(texts.length / 2); }); it('20k mixed lookups+interpolations run ≥1.5x faster (perf gate)', { timeout: 30_000 }, () => { const N = 20_000; // The t() body for a hit: nested lookup then interpolate the result. const after = (key: string): string => { const v = getNestedValue(enDict, key); return v === null ? key : interpolate(v, PARAMS); }; const before = (key: string): string => { const v = referenceGetNestedValue(enDict, key); return v === null ? key : referenceInterpolate(v, PARAMS); }; let sink = 0; for (let i = 0; i < 2_000; i++) { sink += after(workload[i % workload.length]).length; sink += before(workload[i % workload.length]).length; } const t0 = performance.now(); for (let i = 0; i < N; i++) sink += after(workload[i % workload.length]).length; const afterMs = performance.now() - t0; const t1 = performance.now(); for (let i = 0; i < N; i++) sink += before(workload[i % workload.length]).length; const beforeMs = performance.now() - t1; expect(sink).toBeGreaterThan(0); console.info( `t() hot path x ${N}: cached+guarded ${afterMs.toFixed(1)} ms vs split+regex-per-call ${beforeMs.toFixed(1)} ms (${(beforeMs / afterMs).toFixed(2)}x)` ); expect(afterMs).toBeLessThan(beforeMs / 1.5); }); });