fix(doc-gates): review findings — scan every merge block, any quote style, .tsx too; self-check the scan
ds-review-bot round: the backstop stopped at a file's first declare-module block while the projection it guards reads them all; the textual prefilter matched only single quotes; .tsx sources escaped the glob. All three are the silent-vanish class the scan exists to prevent. contextMergeFiles now yields one entry per block (quote-agnostic prefilter, ts+tsx patterns), and a third partition direction requires everything rendered to be scan-visible, so a future scan regression is a hard error. Spec fixture made projection- consistent; the partially superseded 2026-07-28 regions note is rewritten to the current mechanism and cross-linked both ways.
This commit is contained in:
@@ -61,12 +61,33 @@ describe('walkPartitionProblems', () => {
|
||||
|
||||
it('rejects an event exemption whose event the projection renders', () => {
|
||||
const { input, maps } = baseline()
|
||||
const rendered = { ...input, renderedEventNames: new Set(['llm/request', 'theme/change']) }
|
||||
expect(walkPartitionProblems(rendered, maps)).toEqual([
|
||||
// A projection that renders theme/change necessarily renders the theme
|
||||
// scope too; the fixture models that and maps the scope so the only
|
||||
// violation is the stale exemption.
|
||||
const rendered = {
|
||||
...input,
|
||||
renderedScopes: new Set(['llm', 'theme']),
|
||||
renderedEventNames: new Set(['llm/request', 'theme/change']),
|
||||
}
|
||||
const mapped = { ...maps, eventScopePage: { llm: 'llm-streaming.md', theme: 'client-modules.md' } }
|
||||
expect(walkPartitionProblems(rendered, mapped)).toEqual([
|
||||
expect.stringContaining("event 'theme/change' is rendered by the projection but still listed in EVENT_WALK_EXEMPTIONS"),
|
||||
])
|
||||
})
|
||||
|
||||
it('rejects rendered surface the independent scan cannot see, naming the scan as the defect', () => {
|
||||
const { input, maps } = baseline()
|
||||
const blind = {
|
||||
...input,
|
||||
declaredKeys: new Map([['theme', 'packages/client/ui-theme/src/client/index.ts']]),
|
||||
declaredEvents: new Map([['theme/change', 'packages/client/ui-theme/src/client/index.ts']]),
|
||||
}
|
||||
expect(walkPartitionProblems(blind, maps)).toEqual([
|
||||
expect.stringContaining('ctx.llm is rendered by the projection but the independent scan finds no Context merge declaring it'),
|
||||
expect.stringContaining("event 'llm/request' is rendered by the projection but the independent scan finds no Events merge declaring it"),
|
||||
])
|
||||
})
|
||||
|
||||
it('rejects an event exemption no Events merge declares', () => {
|
||||
const { input, maps } = baseline()
|
||||
const stale = { ...maps, eventWalkExemptions: { ...maps.eventWalkExemptions, 'gone/away': 'nothing owns this' } }
|
||||
@@ -123,6 +144,49 @@ describe('cordis-walk scan reach', () => {
|
||||
expect([...contextKeyMap(only.body, only.sf).keys()]).toEqual([])
|
||||
})
|
||||
|
||||
it('yields every merge block of a multi-block file, double-quoted heads, and .tsx sources', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'cordis-walk-'))
|
||||
roots.push(root)
|
||||
const dir = join(root, 'packages/client/ui-x/src')
|
||||
mkdirSync(dir, { recursive: true })
|
||||
// The Typert analyzer reads every cordis module block in a file; the
|
||||
// backstop must not stop at the first one, skip the double-quoted legal
|
||||
// form, or ignore .tsx sources.
|
||||
writeFileSync(join(dir, 'split.ts'), [
|
||||
"declare module 'cordis' {",
|
||||
' interface Context {',
|
||||
' first: FirstService',
|
||||
' }',
|
||||
'}',
|
||||
'declare module "cordis" {',
|
||||
' interface Events {',
|
||||
" 'second/changed'(): void",
|
||||
' }',
|
||||
'}',
|
||||
'export {}',
|
||||
'',
|
||||
].join('\n'))
|
||||
writeFileSync(join(dir, 'view.tsx'), [
|
||||
"declare module 'cordis' {",
|
||||
' interface Context {',
|
||||
' fromTsx: TsxService',
|
||||
' }',
|
||||
'}',
|
||||
'export {}',
|
||||
'',
|
||||
].join('\n'))
|
||||
const merges = contextMergeFiles(root, ['packages/*/*/src/**/*.ts', 'packages/*/*/src/**/*.tsx'])
|
||||
expect(merges.map(m => m.rel)).toEqual([
|
||||
'packages/client/ui-x/src/split.ts',
|
||||
'packages/client/ui-x/src/split.ts',
|
||||
'packages/client/ui-x/src/view.tsx',
|
||||
])
|
||||
const keys = merges.flatMap(m => [...contextKeyMap(m.body, m.sf).keys()])
|
||||
const events = merges.flatMap(m => eventNameList(m.body, m.sf))
|
||||
expect(keys).toEqual(['first', 'fromTsx'])
|
||||
expect(events).toEqual(['second/changed'])
|
||||
})
|
||||
|
||||
it('reads string-literal and identifier member names from an Events merge', () => {
|
||||
const sf = ts.createSourceFile('x.ts', [
|
||||
"declare module 'cordis' {",
|
||||
|
||||
Reference in New Issue
Block a user