Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
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
188 changes: 187 additions & 1 deletion scripts/__tests__/check-i18n-dead-keys.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { sweep, textFootprint } from '../check-i18n-dead-keys.mjs';
import { propertyChainProbe, sweep, textFootprint } from '../check-i18n-dead-keys.mjs';

/**
* objectui#4658 — the behaviour test for `scripts/check-i18n-dead-keys.mjs`,
Expand DownExpand Up@@ -216,6 +216,192 @@ describe('textFootprint()', () => {
});
});

/**
* objectui#6666 — the property-chain leg.
*
* A consumer that imports a locale PACK OBJECT and reads it by property access
* spells neither a `t()` call nor the dotted key, so BOTH of the gate's legs
* were blind to it and the key landed in CONFIRMED — the tier documented as
* the safest thing to delete — with a shipping screen rendering it.
*
* What is pinned below is not "the leg detects things" but that it
* DISCRIMINATES: a key a pack-object consumer really reads is found, and a key
* with no reader at all is still reported CONFIRMED. A leg that demoted
* everything would pass a detection-only test while destroying the top tier,
* which is the failure mode this file exists to make impossible to ship.
*/

/** A pack shaped like the real bootstrap case: a namespace read through a
* local binding, siblings that nobody reads, and the two shapes the leg's own
* boundaries turn on (a two-segment key, and a leaf that PREFIXES a longer
* sibling leaf). */
const PACK_READER_EN = `const en = {
splash: {
steps: { connecting: 'Connecting', loadingConfig: 'Loading configuration', connect: 'Connect' },
failure: { unreachable: 'Server unreachable', giveUp: 'Giving up' },
},
short: { ok: 'OK' },
} as const;
export default en;
`;

/** The LoadingScreen shape: imports the pack object, binds a namespace to a
* local, reads leaves off it. No `t()`/`tt()` call anywhere, so the AST pass
* visits nothing; the dotted key is never spelled, so the full-key probe
* finds nothing. `response.ok` is the two-segment trap — the chain of
* `short.ok` is exactly `.ok`, and it is present in this source. */
const PACK_PROPERTY_READER = `
import { en as enLocale } from '${I18N_PKG}';
export function Splash(response: { ok: boolean }) {
const strings = enLocale.splash;
if (!response.ok) return null;
return [strings.steps.connecting, strings.steps.loadingConfig];
}
`;

function packReaderRoot() {
return repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/Splash.tsx': PACK_PROPERTY_READER,
});
}

describe('propertyChainProbe()', () => {
it('drops the leading namespace segment and keeps the dot', () => {
expect(propertyChainProbe('ns.group.leaf')).toBe('.group.leaf');
expect(propertyChainProbe('ns.a.b.c')).toBe('.a.b.c');
});

it('returns null below three segments — the leg must NOT apply to two-segment keys', () => {
// A two-segment key's chain is a single generic word (`.ok`, `.no`,
// `.empty`). Probing on it would demote most of the pack on incidental
// property accesses and hollow out CONFIRMED instead of correcting it.
// Two-segment keys are checked against the enumerated importer list in the
// script header by hand — see objectui#6662, which did exactly that.
expect(propertyChainProbe('ns.leaf')).toBeNull();
expect(propertyChainProbe('leaf')).toBeNull();
});
});

describe('the property-chain leg discriminates (objectui#6666)', () => {
it('POSITIVE control: a key read only by property access is no longer CONFIRMED', () => {
const { confirmed, needsReview } = sweep(packReaderRoot());
expect(confirmed).not.toContain('splash.steps.connecting');
expect(confirmed).not.toContain('splash.steps.loadingConfig');
const entry = needsReview.find((f) => f.key === 'splash.steps.connecting');
expect(entry, 'splash.steps.connecting should be in needsReview').toBeDefined();
expect(entry!.hits).toEqual(['packages/x/src/Splash.tsx (via property chain)']);
});

it('NEGATIVE control: a key with no reader at all is STILL CONFIRMED', () => {
// The half that makes this a discriminator rather than a blanket
// demotion. These two live in the same pack, under a sibling namespace of
// the one the consumer binds, and nothing reads them by any route.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.failure.unreachable');
expect(confirmed).toContain('splash.failure.giveUp');
});

it('does not demote a two-segment key whose one-word chain IS present in source', () => {
// `short.ok`'s chain would be `.ok`, and `PACK_PROPERTY_READER` spells
// `response.ok`. If the leg ever starts applying below three segments this
// is the assertion that catches it.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('short.ok');
});

it('does not demote a leaf merely because a LONGER sibling leaf is read', () => {
// `splash.steps.connect`'s chain `.steps.connect` is a prefix of the
// `.steps.connecting` the consumer actually reads. Without the
// property-boundary check, reading one leaf would demote the other.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed).toContain('splash.steps.connect');
});

it('does not shrink the CONFIRMED tier to nothing', () => {
// The blunt guard against "make the tool conservative by demoting
// everything": that would pass every detection assertion above while
// making the strongest tier meaningless.
const { confirmed } = sweep(packReaderRoot());
expect(confirmed.length).toBeGreaterThan(0);
});
});

describe('textFootprint() marks a chain-only hit so the report cannot mislead', () => {
it('suffixes a file the full key does not appear in', () => {
const result = textFootprint(packReaderRoot(), ['splash.steps.connecting']);
expect(result.get('splash.steps.connecting')).toEqual([
'packages/x/src/Splash.tsx (via property chain)',
]);
});

it('reports a file plainly when the literal key appears in it, even if the chain also does', () => {
// The literal spelling is the stronger evidence and needs no explanation;
// a suffix there would send the reader looking for a property access that
// is not the reason the file matched.
const root = repoWith({
'packages/i18n/src/locales/en.ts': PACK_READER_EN,
'packages/x/src/config.ts': `export const C = [{ labelKey: 'splash.steps.connecting' }];`,
});
expect(textFootprint(root, ['splash.steps.connecting']).get('splash.steps.connecting')).toEqual([
'packages/x/src/config.ts',
]);
});
});

describe('both control groups from the card, measured on THIS repository (objectui#6666)', () => {
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');

/**
* Assembled from segments rather than written as dotted strings ON PURPOSE,
* and it must stay that way. `textFootprint()` greps the whole repo
* including `scripts/`, so a dotted key spelled here would make THIS FILE a
* textual hit for it — the negative controls below would stop being
* reader-less because the test asserting they are reader-less mentioned
* them. `check-i18n-dead-keys.mjs` records the same trap on
* `textFootprint()` itself, where an earlier draft self-polluted a real key.
* Joining on the segment boundary keeps BOTH probes' spellings out of this
* file: neither the dotted key nor its property chain occurs contiguously.
*/
const key = (group: string, leaf: string) => ['console', group, leaf].join('.');

/** Read by `packages/app-shell/src/chrome/LoadingScreen.tsx` through a local
* binding — the five the card measured, plus two more the leg turned up
* that the card did not list (the same file reads them the same way). */
const READ_BY_PROPERTY_ACCESS = [
key('loadingSteps', 'connecting'),
key('loadingSteps', 'loadingConfig'),
key('loadingSteps', 'preparingWorkspace'),
key('error', 'connectionFailed'),
key('error', 'checkServer'),
key('actions', 'retry'),
key('actions', 'retrying'),
];

/** Sibling keys under the same namespace with no reader by any route. */
const READ_BY_NOBODY = [key('error', 'serverUnreachable'), key('error', 'timeout')];

it('POSITIVE: every property-access-read key names LoadingScreen.tsx as a hit', () => {
const found = textFootprint(repoRoot, READ_BY_PROPERTY_ACCESS);
for (const k of READ_BY_PROPERTY_ACCESS) {
expect(
found.get(k),
`${k} is rendered by LoadingScreen.tsx through a local binding, and the property-chain leg ` +
'is the only probe that can see that read',
).toContain('packages/app-shell/src/chrome/LoadingScreen.tsx (via property chain)');
}
});

it('NEGATIVE: keys nothing reads still have no textual footprint at all', () => {
// The half that keeps the leg honest on the real tree. If someone
// "hardens" it into a blanket demotion this is what fails. If it ever
// fails honestly — a real reader for one of these appeared — the fix is to
// pick a still-reader-less sibling, never to loosen the assertion.
const found = textFootprint(repoRoot, READ_BY_NOBODY);
for (const k of READ_BY_NOBODY) expect(found.get(k), `${k} must have no reader`).toEqual([]);
});
});

describe('the collapse guard lives in the CLI block, not in sweep() itself', () => {
it('sweep() runs against a small synthetic fixture without throwing', () => {
// Unlike the CLI entry point (which exits 1 below ~2000 keys on the REAL
Expand Down
Loading
Loading