mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
Round 2 fixes, all five folded here.
1. Deleted terminal-webview-html-source.test-support.ts.
`readTerminalWebViewHtmlSource()` had no consumers left once the behavioural
tests moved to the generated document, and it was the last thing that built a
document-shaped string by concatenating module sources — its filter admitted
`.test-support.ts` files too, so it could have grown one. Confirmed by grep
that the only occurrence of either name in the repository was its own
declaration.
2. New document-module-order.test.ts asserts both directions: the non-test,
non-test-support `.ts` files under `document/` are exactly
`{document-scope} + TERMINAL_DOCUMENT_MODULE_ORDER + {document-constants}`,
and no name is listed twice. `document-constants` is the one exception
because it is never emitted: its exports are substituted into the modules
that import them as literals, so the document carries its values without
carrying the module. A module added here and forgotten there would be dead
code that reads as live; a name left after its file goes makes the generator
throw at build time rather than at review time.
3. terminal-document-flip.test.ts's docstring now carries the retirement policy
from ruling 18: the test is the proof of the flip and holds only while no
module changes, the first lane that must change one retires it together with
`terminal-document-pre-flip-script.txt`, and the standing pin from then on is
`terminal-document-identity.test.ts`, whose fixture regeneration is a review
event. Comment only.
4. terminal-document-equivalence.test-support.ts said 57 reassigned variables
and "Four classes and no others". It now says 73 declaration sites and eight
classes, with each class's measured figure named. Two doc comments sat above
the wrong declaration and were moved onto what they describe: the
`NUMBER_GLOBALS` one down to that constant, and the printing one down to
`significantTokens`, with `STRICT_DIRECTIVE` given its own line.
5. build-terminal-document-script.mjs substituted constants with
`replaceAll(regexp, literal)`, where `$&`, `` $` ``, `$'` and `$n` in a
constant's value are read as replacement patterns. The substitution is now
`substituteDocumentConstants`, exported so it can be tested directly, and
replaces with a function.
Controls, each verified to have changed its input first, all red, tree green
after restore:
plant document/zz-planted-module.ts -> order guard, "+ zz-planted-module"
drop 'wheel-scroll' from the order -> order guard, "+ wheel-scroll"
revert to the string replacer -> 4 failed, "a $& b" became "a marker b"
The `$n` case is deliberately absent from that table: the pattern has no capture
group, so `$1` is already literal under either form and a case for it could not
tell them apart.
The document did not move. The byte golden, the digest and the flip test's class
table are all unchanged.
Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
106 lines
4.2 KiB
TypeScript
106 lines
4.2 KiB
TypeScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
import {
|
|
emitTerminalDocumentModule,
|
|
substituteDocumentConstants
|
|
} from './build-terminal-document-script.mjs'
|
|
import { terminalBackgroundFallback } from '../src/terminal/document/document-constants'
|
|
|
|
/**
|
|
* What the generator drops, what it keeps, and how it puts a module back into the document.
|
|
*
|
|
* The per-group tests compare a real module against the string the document carries, which says
|
|
* the two agree; these say why, on inputs small enough to read. The import and export cases are
|
|
* the ones that bit: esbuild wraps a long list across lines, and skipping only the first line
|
|
* leaves the rest of the names loose in the document.
|
|
*/
|
|
let directory: string
|
|
|
|
async function emit(source: string): Promise<string> {
|
|
const path = join(directory, `module-${Math.random().toString(36).slice(2)}.ts`)
|
|
await writeFile(path, source)
|
|
return emitTerminalDocumentModule(path)
|
|
}
|
|
|
|
beforeAll(async () => {
|
|
directory = await mkdtemp(join(tmpdir(), 'orca-terminal-document-'))
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await rm(directory, { recursive: true, force: true })
|
|
})
|
|
|
|
describe('emitting one terminal document module', () => {
|
|
it('unmarks an export and indents it into the document scope', async () => {
|
|
expect(await emit('export function f() {\n return 1\n}\n')).toBe(
|
|
' function f() {\n return 1;\n }'
|
|
)
|
|
})
|
|
|
|
it('drops an import that fits on one line', async () => {
|
|
expect(await emit("import { a } from './x'\nexport const b = 1\n")).toBe(' const b = 1;')
|
|
})
|
|
|
|
it('drops an import esbuild wrapped across lines', async () => {
|
|
// The case that produced an unparseable document: the names after the first line stayed.
|
|
const source =
|
|
"import { alpha, beta, gamma, delta, epsilon, zeta, eta, theta } from './document-externals'\n" +
|
|
'export const b = alpha\n'
|
|
expect(await emit(source)).toBe(' const b = alpha;')
|
|
})
|
|
|
|
it('drops the trailing export block esbuild prints, not just its keyword', async () => {
|
|
// Left behind it is a bare block statement, which parses and does nothing.
|
|
const emitted = await emit('function f() {}\nfunction g() {}\nexport { f, g }\n')
|
|
expect(emitted).not.toContain('{ f, g }')
|
|
expect(emitted).toBe(' function f() {\n }\n function g() {\n }')
|
|
})
|
|
|
|
it('erases types without touching the program', async () => {
|
|
expect(
|
|
await emit(
|
|
'export type T = { a: number }\nexport function f(v: T): number {\n return v.a\n}\n'
|
|
)
|
|
).toBe(' function f(v) {\n return v.a;\n }')
|
|
})
|
|
|
|
it('substitutes a build-time constant the document carries as a literal', async () => {
|
|
const emitted = await emit(
|
|
"import { terminalBackgroundFallback } from '../src/terminal/document/document-constants'\n" +
|
|
'export function paint() {\n' +
|
|
' return terminalBackgroundFallback\n' +
|
|
'}\n'
|
|
)
|
|
expect(emitted).toContain(JSON.stringify(terminalBackgroundFallback))
|
|
expect(emitted).not.toContain('terminalBackgroundFallback')
|
|
})
|
|
|
|
it('drops a lint directive rather than let it parenthesise the expression it guards', async () => {
|
|
expect(
|
|
await emit(
|
|
'export const R =\n' + ' // oxlint-disable-next-line no-useless-escape\n' + ' /a/g\n'
|
|
)
|
|
).toBe(' const R = /a/g;')
|
|
})
|
|
})
|
|
|
|
describe('substituting a build-time constant', () => {
|
|
it('writes a value containing a replacement pattern out as it stands', () => {
|
|
// `$&` is the matched text to `String.replaceAll`'s string form, which would splice the
|
|
// constant's own name in here and ship a document that says something else.
|
|
const literal = JSON.stringify('a $& b')
|
|
expect(substituteDocumentConstants('const v = marker;', { marker: literal })).toBe(
|
|
'const v = "a $& b";'
|
|
)
|
|
})
|
|
|
|
// `$n` is not listed: the pattern has no capture group, so it is already literal under either
|
|
// form and a case for it could not tell them apart.
|
|
it.each([['$&'], ["$'"], ['$`']])('is not read as the replacement pattern %s', (pattern) => {
|
|
const literal = JSON.stringify(`x${pattern}y`)
|
|
expect(substituteDocumentConstants('marker', { marker: literal })).toBe(literal)
|
|
})
|
|
})
|