parseman 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +34 -19
  2. package/dist/analysis/duplication.d.ts +421 -0
  3. package/dist/analysis/duplication.d.ts.map +1 -0
  4. package/dist/analysis/gating.d.ts +25 -0
  5. package/dist/analysis/gating.d.ts.map +1 -1
  6. package/dist/analysis/grammar.d.ts +12 -0
  7. package/dist/analysis/grammar.d.ts.map +1 -0
  8. package/dist/combinators/expect.d.ts +12 -0
  9. package/dist/combinators/expect.d.ts.map +1 -1
  10. package/dist/combinators/parser.d.ts +26 -0
  11. package/dist/combinators/parser.d.ts.map +1 -1
  12. package/dist/compiler/build-arity.d.ts +12 -0
  13. package/dist/compiler/build-arity.d.ts.map +1 -1
  14. package/dist/compiler/codegen.d.ts +43 -1
  15. package/dist/compiler/codegen.d.ts.map +1 -1
  16. package/dist/compiler/linker.d.ts +64 -7
  17. package/dist/compiler/linker.d.ts.map +1 -1
  18. package/dist/cst/host-mode.d.ts +43 -0
  19. package/dist/cst/host-mode.d.ts.map +1 -0
  20. package/dist/functional/doc.d.ts.map +1 -1
  21. package/dist/functional/run.d.ts.map +1 -1
  22. package/dist/index.cjs +1621 -55
  23. package/dist/index.cjs.map +4 -4
  24. package/dist/index.d.ts +6 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1621 -55
  27. package/dist/index.js.map +4 -4
  28. package/dist/language-service/index.cjs +37 -1
  29. package/dist/language-service/index.cjs.map +3 -3
  30. package/dist/language-service/index.js +37 -1
  31. package/dist/language-service/index.js.map +3 -3
  32. package/dist/oracle/corpus.d.ts +32 -0
  33. package/dist/oracle/corpus.d.ts.map +1 -0
  34. package/dist/oracle/digest.d.ts +21 -0
  35. package/dist/oracle/digest.d.ts.map +1 -0
  36. package/dist/oracle/identity.d.ts +117 -0
  37. package/dist/oracle/identity.d.ts.map +1 -0
  38. package/dist/oracle/index.cjs +423 -0
  39. package/dist/oracle/index.cjs.map +7 -0
  40. package/dist/oracle/index.d.ts +37 -0
  41. package/dist/oracle/index.d.ts.map +1 -0
  42. package/dist/oracle/index.js +400 -0
  43. package/dist/oracle/index.js.map +7 -0
  44. package/dist/plugin/index.cjs +1628 -62
  45. package/dist/plugin/index.cjs.map +4 -4
  46. package/dist/plugin/index.d.ts.map +1 -1
  47. package/dist/plugin/index.js +1628 -62
  48. package/dist/plugin/index.js.map +4 -4
  49. package/dist/run/index.cjs +23 -0
  50. package/dist/run/index.cjs.map +3 -3
  51. package/dist/run/index.js +23 -0
  52. package/dist/run/index.js.map +3 -3
  53. package/dist/spec/index.cjs +2977 -56
  54. package/dist/spec/index.cjs.map +4 -4
  55. package/dist/spec/index.js +2977 -56
  56. package/dist/spec/index.js.map +4 -4
  57. package/dist/spec/model.d.ts.map +1 -1
  58. package/dist/types.d.ts +7 -0
  59. package/dist/types.d.ts.map +1 -1
  60. package/dist/version.d.ts +1 -1
  61. package/package.json +10 -3
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/oracle/digest.ts", "../../src/oracle/identity.ts", "../../src/oracle/corpus.ts"],
4
+ "sourcesContent": ["/**\n * The canonical projection and the hashing the identity oracle is built on.\n *\n * Everything here exists to make ONE claim trustworthy: \"this grammar change did\n * not move the tree.\" That claim is only worth as much as the projection behind\n * it, so the rules below are stated rather than left to `JSON.stringify`, which\n * silently collapses several distinctions a grammar refactor can actually move:\n *\n * | value | `JSON.stringify` | here |\n * |------------------------|------------------|-----------------|\n * | `{ a: undefined }` | `{}` | distinct from `{}` |\n * | `NaN` / `\u00B1Infinity` | `null` | each distinct |\n * | `-0` | `0` | distinct from `0` |\n * | `new Map([[1, 2]])` | `{}` | entries, in order |\n * | `new Set([1])` | `{}` | members, in order |\n * | `new Foo({ x: 1 })` | `{\"x\":1}` | tagged `Foo` |\n *\n * A refactor that starts emitting `undefined` where it used to omit a key, or\n * that swaps one node class for another with the same fields, is a tree move.\n * An oracle that cannot see it is worse than no oracle, because it certifies.\n *\n * ## Key order does not matter; array and Map/Set order does\n *\n * Object keys are sorted, so property INSERTION order \u2014 which a refactor churns\n * constantly and which no consumer observes \u2014 never moves a digest. Array\n * elements and Map/Set entries keep their order, because those orders are the\n * output.\n *\n * ## Sharing is not a cycle\n *\n * A node reachable by two paths is written out twice, in full. Only a genuine\n * back-edge into the CURRENT path is abbreviated, and it records the DISTANCE to\n * the ancestor it points at, so a self-reference and a reference to the root are\n * different digests. (Marking every repeat as a cycle \u2014 the easy version \u2014 makes\n * the digest depend on traversal order for any DAG, which parse trees with\n * interned or shared subtrees routinely are.)\n *\n * ## Own ENUMERABLE keys only\n *\n * `Object.keys`, deliberately, not `getOwnPropertyNames`. The oracle answers \"did\n * the OUTPUT move\" and non-enumerable properties are engine bookkeeping a\n * consumer never sees \u2014 parseman's own carried CST pieces among them. Hashing\n * them would make a consumer's grammar digest move when parseman's internals\n * change, which is precisely the wrong sensitivity for a grammar-refactor gate.\n *\n * ## Tokens, not concatenation\n *\n * Every value writes one or more self-contained tokens joined by NUL. Writing\n * `#1` then `#2` into a single buffer would be indistinguishable from `#12`; a\n * projection with an ambiguity in it is a projection that can be made to lie.\n * Strings are JSON-escaped, so no token can contain a raw NUL.\n */\nimport { createHash } from 'node:crypto'\n\n/**\n * Bump when the token grammar below changes in a way that alters output for any\n * input. It is a coarse, human-readable companion to the behavioural harness\n * digest \u2014 the harness digest is what actually enforces this, but a reader\n * comparing two reports should not have to diff hex to see that the format moved.\n */\nexport const DIGEST_FORMAT = 1\n\nconst str = (s: string): string => JSON.stringify(s)\n\nconst tagOf = (v: object): string => {\n const ctor = (v as { constructor?: unknown }).constructor\n return typeof ctor === 'function' && typeof ctor.name === 'string' ? ctor.name : ''\n}\n\nfunction writeScalar(v: unknown, out: string[]): void {\n switch (typeof v) {\n case 'undefined':\n out.push('u')\n return\n case 'boolean':\n out.push(v ? 'T' : 'F')\n return\n case 'bigint':\n out.push(`n${v}`)\n return\n case 'string':\n out.push(`s${str(v)}`)\n return\n // TODO(oracle-callable-identity): a callable is projected by NAME and a symbol by\n // DESCRIPTION, so two distinct same-named functions \u2014 or two same-description\n // symbols \u2014 digest identically, and a change between them reads as \"identical\".\n // This is a real hole in a tool whose whole claim is paranoia, and it is left open\n // deliberately: closing it means either hashing `Function.prototype.toString()`,\n // which flips the digest on a comment edit inside a builder, or REFUSING to digest\n // any value carrying a callable, which rejects legitimate ASTs that park a callback\n // on a node. Both are worse than the hole for some caller, and picking between them\n // is a product decision, not a bug fix. Documented under \"What it is not\" in\n // `docs/guide/identity-oracle.md` so no reader infers a guarantee that is not here.\n case 'symbol':\n out.push(`y${str(v.description ?? '')}`)\n return\n case 'function':\n out.push(`f${str(v.name)}`)\n return\n case 'number':\n if (Number.isNaN(v)) out.push('#nan')\n else if (v === Number.POSITIVE_INFINITY) out.push('#inf')\n else if (v === Number.NEGATIVE_INFINITY) out.push('#-inf')\n else if (Object.is(v, -0)) out.push('#-0')\n // Number\u2192string is exact and round-trips in JS, so this loses nothing.\n else out.push(`#${v}`)\n return\n default:\n // `typeof null`. Distinct from `undefined`, which is `'u'`.\n out.push('z')\n }\n}\n\nfunction write(v: unknown, path: Map<object, number>, depth: number, out: string[]): void {\n // Everything that is not a live object reference is written here, so the rest\n // of the function has `v: object` and needs no assertion to index or key on it.\n if (typeof v !== 'object' || v === null) {\n writeScalar(v, out)\n return\n }\n\n const seenAt = path.get(v)\n if (seenAt !== undefined) {\n // Distance to the ancestor, not its identity: a self-reference and a\n // reference to the root must not hash the same.\n out.push(`^${depth - seenAt}`)\n return\n }\n path.set(v, depth)\n\n if (Array.isArray(v)) {\n out.push('[')\n // `for..of` rather than indexing so a sparse hole reads as the `undefined`\n // it is, consistently with a present `undefined` \u2014 the distinction between\n // a hole and an explicit undefined is not observable output.\n for (const item of v) write(item, path, depth + 1, out)\n out.push(']')\n } else if (v instanceof Map) {\n out.push('M')\n for (const [k, val] of v) {\n write(k, path, depth + 1, out)\n write(val, path, depth + 1, out)\n }\n out.push('}')\n } else if (v instanceof Set) {\n out.push('S')\n for (const item of v) write(item, path, depth + 1, out)\n out.push('}')\n } else if (v instanceof Date) {\n out.push(`D${v.getTime()}`)\n } else if (v instanceof RegExp) {\n out.push(`R${str(v.source)}${str(v.flags)}`)\n } else {\n const tag = tagOf(v)\n out.push(`{${str(tag === 'Object' ? '' : tag)}`)\n for (const k of Object.keys(v).sort()) {\n out.push(`k${str(k)}`)\n write((v as Record<string, unknown>)[k], path, depth + 1, out)\n }\n out.push('}')\n }\n\n path.delete(v)\n}\n\n/**\n * The canonical token string for a value. Exported because a moved digest is\n * only actionable if you can see WHAT moved: diff two canonical strings and the\n * answer is a line, not a hex mismatch.\n */\nexport function canonicalize(value: unknown): string {\n const out: string[] = []\n write(value, new Map(), 0, out)\n return out.join('\\u0000')\n}\n\n/** Full 64-hex sha256 of a string. */\nexport function hash(payload: string): string {\n return createHash('sha256').update(payload).digest('hex')\n}\n\n/**\n * Per-entry fingerprint width. 64 bits over any realistic corpus is far below\n * the collision floor, and a report a human has to read stays readable.\n */\nexport const FINGERPRINT_HEX = 16\n", "/**\n * The AST-identity oracle: an accept/reject gate for grammar refactors.\n *\n * ## What it is for\n *\n * \"Collapse these two near-duplicate rules\" is a judgement call until something\n * can answer \"did the tree move?\" mechanically. This answers it: run a corpus\n * through your parse entry points before and after the change, digest the\n * results, compare. Identical digests mean the refactor is output-neutral and can\n * land on its own merits. Different digests mean it is not a refactor \u2014 it is a\n * semantics change, and needs the decision that goes with one.\n *\n * It is a differential, not a correctness check. It says the output did not move;\n * it says nothing about whether the output was right to begin with.\n *\n * ## Failures are part of the contract\n *\n * A parse that throws, and a parse that returns a failure result, are both\n * hashed. Error behaviour IS behaviour: a change that turns a hard rejection into\n * a silent accept has moved the grammar's contract as surely as one that renames\n * a node. A corpus with a healthy number of rejections in it is a FEATURE \u2014 feed\n * it your invalid inputs on purpose. What matters is that the throw counts and\n * the digests do not move.\n *\n * ## Measure what SHIPS\n *\n * Digest the artifact your consumers get. For a macro-compiled grammar that means\n * the BUILT output, rebuilt between edits \u2014 a macro-fallback build runs the\n * interpreter, and the interpreter and the compiled artifact are not guaranteed\n * to agree on every tree. A digest taken on a fallback build certifies something\n * nobody runs. This module cannot check that for you; your build can, and should.\n *\n * ## The harness cannot drift silently\n *\n * A digest that moves because the HARNESS changed, rather than the grammar, is\n * worse than no oracle: it either invents a regression or, far worse, hides one.\n * Three things prevent it:\n *\n * 1. Every report carries {@link HARNESS_DIGEST} \u2014 a behavioural fingerprint of\n * this harness, produced by running it over a frozen canary corpus that\n * exercises every payload-shaping decision it makes.\n * 2. {@link compareReports} REFUSES to compare two reports whose harness\n * digests differ. It returns `incomparable`, never `identical` and never\n * `moved`. A drifted harness produces an error, not a verdict.\n * 3. Parseman's own suite pins `HARNESS_DIGEST` to a literal constant, so\n * changing the projection requires editing that constant in a reviewed diff.\n * There is no edit to this file that changes a digest and stays quiet.\n *\n * ## Nondeterminism is caught, not hashed\n *\n * A grammar whose output depends on `Map` iteration over object identity, a\n * timestamp, or a counter produces a digest that moves every run \u2014 which reads\n * exactly like a regression. {@link digestCorpus} re-parses a sample of the\n * corpus and fails loudly if any entry does not reproduce. An oracle that cannot\n * be trusted should say so rather than emit a number.\n */\nimport { canonicalize, hash, DIGEST_FORMAT, FINGERPRINT_HEX } from './digest.ts'\n\n/**\n * One parse entry point under test.\n *\n * Declare EVERY shipped surface, not just the one you are editing. A refactor\n * that touches one grammar should move neither, and the untouched surface is a\n * free control: if it moves too, the harness or the corpus moved, not the rule\n * you edited.\n */\nexport type Surface = {\n /** Stable identifier. Renaming a surface changes its aggregate, deliberately. */\n name: string\n /** Called once per corpus entry. May return anything, and may throw. */\n parse: (source: string, id: string) => unknown\n}\n\nexport type CorpusEntry = {\n /**\n * Stable, RELATIVE identifier \u2014 a path relative to a base, not an absolute\n * one. An absolute path makes the digest depend on the checkout directory,\n * which means two machines can never agree.\n */\n id: string\n source: string\n}\n\nexport type SurfaceReport = {\n name: string\n /** sha256 over every entry's fingerprint, in id order. The gate. */\n aggregate: string\n /** How many entries threw. Expected to be non-zero; expected not to MOVE. */\n threw: number\n}\n\nexport type IdentityReport = {\n format: number\n /** Behavioural fingerprint of the harness that produced this report. */\n harness: string\n entries: number\n surfaces: SurfaceReport[]\n /** entry id \u2192 surface name \u2192 16-hex fingerprint. Diff this to localise a move. */\n perEntry: Record<string, Record<string, string>>\n}\n\nexport type DigestOptions = {\n /**\n * Project a thrown value into something hashable. The default keeps an Error's\n * `name` and `message`.\n *\n * Override when your messages embed anything machine-specific \u2014 an absolute\n * path, a wall-clock time, a memory address. Those make a digest that cannot\n * be compared across machines, and the symptom is a gate that fails for\n * everyone except its author.\n */\n projectError?: (thrown: unknown, id: string, surface: string) => unknown\n /**\n * How many entries to re-parse to prove the grammar is deterministic. Sampled\n * evenly across the corpus, not from the front. `0` disables the check; do that\n * only if you have another reason to trust it.\n */\n determinismSample?: number\n}\n\nconst defaultProjectError = (thrown: unknown): unknown =>\n thrown instanceof Error ? { name: thrown.name, message: thrown.message } : { thrown }\n\n/**\n * The `OK:` / `ERR:` discriminator.\n *\n * Not decoration, and not droppable: it keeps a successful parse and a thrown\n * error in disjoint hash spaces. Without it a surface that returns exactly the\n * projected error shape hashes identically to one that threw it, and the single\n * most important thing this oracle detects \u2014 an error becoming an accept \u2014 is\n * the thing it stops detecting.\n */\nfunction payload(surface: Surface, entry: CorpusEntry, options: DigestOptions): { text: string; threw: boolean } {\n try {\n return { text: `OK:${canonicalize(surface.parse(entry.source, entry.id))}`, threw: false }\n } catch (thrown) {\n const project = options.projectError ?? defaultProjectError\n return { text: `ERR:${canonicalize(project(thrown, entry.id, surface.name))}`, threw: true }\n }\n}\n\nconst fingerprint = (text: string): string => hash(text).slice(0, FINGERPRINT_HEX)\n\n/**\n * Run every surface over every entry and produce the report.\n *\n * The corpus is sorted by id, so the aggregate does not depend on the order the\n * caller happened to list files in. The aggregate covers the ids as well as the\n * fingerprints, so a corpus that quietly SHRANK \u2014 a root that stopped resolving,\n * a glob that stopped matching \u2014 moves the aggregate instead of producing a\n * smaller, greener gate. {@link compareReports} then tells you it was the corpus.\n */\nexport function digestCorpus(\n surfaces: readonly Surface[],\n corpus: readonly CorpusEntry[],\n options: DigestOptions = {},\n): IdentityReport {\n if (surfaces.length === 0) throw new Error('digestCorpus: no surfaces \u2014 there is nothing to compare.')\n const names = new Set<string>()\n for (const s of surfaces) {\n if (names.has(s.name)) throw new Error(`digestCorpus: duplicate surface name ${JSON.stringify(s.name)}.`)\n names.add(s.name)\n }\n\n const entries = [...corpus].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))\n for (let n = 1; n < entries.length; n++) {\n if (entries[n]!.id === entries[n - 1]!.id) {\n throw new Error(`digestCorpus: duplicate corpus id ${JSON.stringify(entries[n]!.id)}.`)\n }\n }\n\n const perEntry: Record<string, Record<string, string>> = {}\n const threw: Record<string, number> = {}\n const texts: Map<string, string>[] = []\n for (const s of surfaces) threw[s.name] = 0\n\n for (const entry of entries) {\n const row: Record<string, string> = {}\n const rowTexts = new Map<string, string>()\n for (const s of surfaces) {\n const result = payload(s, entry, options)\n if (result.threw) threw[s.name]!++\n row[s.name] = fingerprint(result.text)\n rowTexts.set(s.name, result.text)\n }\n perEntry[entry.id] = row\n texts.push(rowTexts)\n }\n\n verifyDeterminism(surfaces, entries, texts, options)\n\n return {\n format: DIGEST_FORMAT,\n harness: HARNESS_DIGEST,\n entries: entries.length,\n surfaces: surfaces.map(s => ({\n name: s.name,\n // The surface NAME is inside its own aggregate: two surfaces that happen\n // to agree on every entry must still have distinct aggregates, or a\n // report that swapped them would compare equal.\n aggregate: hash(\n [`surface:${s.name}`, ...entries.map(e => `${e.id}:${perEntry[e.id]![s.name]}`)].join('\\n'),\n ),\n threw: threw[s.name]!,\n })),\n perEntry,\n }\n}\n\nfunction verifyDeterminism(\n surfaces: readonly Surface[],\n entries: readonly CorpusEntry[],\n texts: ReadonlyArray<Map<string, string>>,\n options: DigestOptions,\n): void {\n const want = options.determinismSample ?? 32\n if (want <= 0 || entries.length === 0) return\n const stride = Math.max(1, Math.floor(entries.length / Math.min(want, entries.length)))\n for (let n = 0; n < entries.length; n += stride) {\n const entry = entries[n]!\n for (const s of surfaces) {\n if (payload(s, entry, options).text === texts[n]!.get(s.name)) continue\n throw new Error(\n `digestCorpus: surface ${JSON.stringify(s.name)} is NOT DETERMINISTIC on ${JSON.stringify(entry.id)} \u2014 `\n + 'two parses of the same source produced different output. Every digest from this grammar would move on '\n + 'its own, so a comparison against it cannot mean anything. Usual causes: a timestamp or counter in the '\n + 'output, iteration over a keyed-by-object Map, or a node carrying a reference to mutable shared state.',\n )\n }\n }\n}\n\nexport type SurfaceComparison = {\n name: string\n before: string | null\n after: string | null\n equal: boolean\n /** Entry ids whose fingerprint moved on this surface. Empty when equal. */\n moved: string[]\n beforeThrew: number | null\n afterThrew: number | null\n}\n\nexport type IdentityComparison = {\n /**\n * `identical` \u2014 output-neutral, the refactor is accepted.\n * `moved` \u2014 the output changed; this is not a refactor.\n * `incomparable` \u2014 the two reports cannot be compared at all. Never a pass.\n */\n verdict: 'identical' | 'moved' | 'incomparable'\n reason: string | null\n addedEntries: string[]\n removedEntries: string[]\n surfaces: SurfaceComparison[]\n}\n\n/**\n * Compare two reports.\n *\n * Refuses \u2014 `incomparable`, with a reason \u2014 when the two were not produced by the\n * same harness over comparable inputs. That is the whole point: the failure mode\n * this guards against is a harness change that quietly re-baselines every recorded\n * digest, and the only defence is that mismatched provenance can never come out\n * as a verdict about the grammar.\n *\n * A corpus that gained or lost entries is reported but is NOT by itself\n * incomparable \u2014 the surviving entries still carry a real signal, and telling you\n * \"1 entry disappeared, the other 4,300 are unchanged\" is more useful than\n * refusing. The verdict still reflects the difference.\n */\nexport function compareReports(before: IdentityReport, after: IdentityReport): IdentityComparison {\n if (before.harness !== after.harness) {\n return incomparable(\n `harness drift: reports were produced by DIFFERENT versions of the identity harness `\n + `(${before.harness.slice(0, 12)}\u2026 vs ${after.harness.slice(0, 12)}\u2026). Their digests are not comparable, `\n + `and treating them as such would either invent a regression or hide one. Re-run BOTH sides on one harness.`,\n )\n }\n if (before.format !== after.format) {\n return incomparable(`digest format ${before.format} vs ${after.format} \u2014 re-run both sides on one version.`)\n }\n\n const beforeIds = new Set(Object.keys(before.perEntry))\n const afterIds = new Set(Object.keys(after.perEntry))\n const addedEntries = [...afterIds].filter(id => !beforeIds.has(id)).sort()\n const removedEntries = [...beforeIds].filter(id => !afterIds.has(id)).sort()\n const shared = [...beforeIds].filter(id => afterIds.has(id)).sort()\n\n const byName = new Map<string, { before?: SurfaceReport; after?: SurfaceReport }>()\n for (const s of before.surfaces) byName.set(s.name, { ...byName.get(s.name), before: s })\n for (const s of after.surfaces) byName.set(s.name, { ...byName.get(s.name), after: s })\n\n const surfaces: SurfaceComparison[] = [...byName.entries()]\n .sort(([a], [b]) => (a < b ? -1 : 1))\n .map(([name, pair]) => {\n const moved = pair.before && pair.after\n ? shared.filter(id => before.perEntry[id]![name] !== after.perEntry[id]![name])\n : []\n return {\n name,\n before: pair.before?.aggregate ?? null,\n after: pair.after?.aggregate ?? null,\n equal: pair.before !== undefined && pair.after !== undefined && pair.before.aggregate === pair.after.aggregate,\n moved,\n beforeThrew: pair.before?.threw ?? null,\n afterThrew: pair.after?.threw ?? null,\n }\n })\n\n const identical =\n addedEntries.length === 0 && removedEntries.length === 0 && surfaces.every(s => s.equal)\n return { verdict: identical ? 'identical' : 'moved', reason: null, addedEntries, removedEntries, surfaces }\n}\n\nfunction incomparable(reason: string): IdentityComparison {\n return { verdict: 'incomparable', reason, addedEntries: [], removedEntries: [], surfaces: [] }\n}\n\n/** Human-readable rendering of a comparison, for a CLI or a CI log. */\nexport function formatComparison(c: IdentityComparison, options: { maxMoved?: number } = {}): string {\n if (c.verdict === 'incomparable') return `INCOMPARABLE \u2014 ${c.reason ?? 'unknown reason'}`\n const max = options.maxMoved ?? 10\n const lines: string[] = []\n for (const s of c.surfaces) {\n if (s.before === null) lines.push(` + surface ${s.name} (added)`)\n else if (s.after === null) lines.push(` - surface ${s.name} (removed)`)\n else if (s.equal) lines.push(` = ${s.name} ${s.before.slice(0, 16)}\u2026 threw=${s.afterThrew}`)\n else {\n lines.push(\n ` ! ${s.name} ${s.before.slice(0, 16)}\u2026 -> ${s.after.slice(0, 16)}\u2026 `\n + `threw ${s.beforeThrew} -> ${s.afterThrew} (${s.moved.length} entries moved)`,\n )\n for (const id of s.moved.slice(0, max)) lines.push(` ${id}`)\n if (s.moved.length > max) lines.push(` \u2026 and ${s.moved.length - max} more`)\n }\n }\n if (c.addedEntries.length > 0) lines.push(` corpus GAINED ${c.addedEntries.length} entries`)\n if (c.removedEntries.length > 0) {\n lines.push(\n ` corpus LOST ${c.removedEntries.length} entries \u2014 a differential over a SMALLER corpus is a weaker gate, `\n + `not a passing one`,\n )\n }\n return [c.verdict === 'identical' ? 'IDENTICAL \u2014 output-neutral' : 'MOVED \u2014 this is not a refactor', ...lines]\n .join('\\n')\n}\n\n/**\n * The frozen canary.\n *\n * One entry per decision {@link canonicalize} and {@link payload} make. Any edit\n * that changes what this harness produces for ANY input changes what it produces\n * for one of these, and therefore changes {@link HARNESS_DIGEST}.\n *\n * It deliberately builds its values by hand rather than by parsing anything: the\n * harness fingerprint must move when the HARNESS moves and at no other time. If\n * it ran a real grammar, every combinator change in this repo would re-baseline\n * it, and a fingerprint that moves for unrelated reasons is one people learn to\n * update without reading.\n */\nfunction canaryReport(): IdentityReport {\n class Tagged {\n x: number\n constructor(x: number) {\n this.x = x\n }\n }\n const shared = { shared: true }\n const cyclic: Record<string, unknown> = { name: 'root' }\n cyclic.self = cyclic\n cyclic.child = { up: cyclic }\n\n const values: Record<string, unknown> = {\n 'a/scalars': [0, -0, 1.5, Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, 10n, true, false, null],\n 'b/absent': [{ a: undefined }, {}, { a: null }, [undefined], []],\n 'c/key-order': [{ a: 1, b: 2 }, { b: 2, a: 1 }],\n 'd/collections': [new Map([['k', 1], ['j', 2]]), new Set([1, 2]), new Date(0), /ab+c/giu],\n 'e/tagged': [new Tagged(1), { x: 1 }],\n 'f/sharing': { left: shared, right: shared },\n 'g/cycle': cyclic,\n 'h/text': ['', 'a\\u0000b', 'a b', '\"quoted\"', '\\\\'],\n 'i/callable': [function named() {}, Symbol('sym')],\n }\n\n const surfaces: Surface[] = [\n { name: 'value', parse: (_source, id) => values[id] },\n {\n name: 'thrower',\n parse: (_source, id) => {\n if (id === 'a/scalars') throw new TypeError('canary')\n if (id === 'b/absent') throw 'a bare string' // eslint-disable-line no-throw-literal\n return { id }\n },\n },\n ]\n\n const corpus: CorpusEntry[] = Object.keys(values).map(id => ({ id, source: id }))\n // Built inline rather than through digestCorpus() so the harness digest does\n // not have to exist before it is computed.\n const perEntry: Record<string, Record<string, string>> = {}\n const threw: Record<string, number> = { value: 0, thrower: 0 }\n for (const entry of [...corpus].sort((a, b) => (a.id < b.id ? -1 : 1))) {\n const row: Record<string, string> = {}\n for (const s of surfaces) {\n const result = payload(s, entry, {})\n if (result.threw) threw[s.name]!++\n row[s.name] = fingerprint(result.text)\n }\n perEntry[entry.id] = row\n }\n const ids = Object.keys(perEntry).sort()\n return {\n format: DIGEST_FORMAT,\n harness: '',\n entries: ids.length,\n surfaces: surfaces.map(s => ({\n name: s.name,\n aggregate: hash([`surface:${s.name}`, ...ids.map(id => `${id}:${perEntry[id]![s.name]}`)].join('\\n')),\n threw: threw[s.name]!,\n })),\n perEntry,\n }\n}\n\n/**\n * Behavioural fingerprint of this harness, embedded in every report it produces.\n *\n * Parseman's suite pins this to a literal. If you change the projection, that\n * test fails and the constant has to be updated in the same diff \u2014 which is the\n * point. There is no quiet edit here.\n */\nexport const HARNESS_DIGEST: string = (() => {\n const canary = canaryReport()\n return hash(\n [`format:${DIGEST_FORMAT}`, ...canary.surfaces.map(s => `${s.name}:${s.aggregate}:${s.threw}`)].join('\\n'),\n )\n})()\n", "/**\n * Loading a file corpus for the identity oracle.\n *\n * Small, and here rather than left to each consumer, because the two ways to get\n * this wrong both produce a gate that looks fine:\n *\n * - **Absolute ids.** An id derived from an absolute path bakes the checkout\n * directory into every digest, so two machines \u2014 or one machine and its CI \u2014\n * can never agree, and the first cross-machine comparison reads as a total\n * regression. Ids here are always relative to an explicit `base`.\n * - **A root that silently is not there.** A corpus root behind an optional\n * dependency, or a path that moved, yields a SMALLER corpus and therefore a\n * different-but-plausible aggregate. Missing roots throw by default; opt out\n * and you get them listed back so the report can record what was skipped.\n *\n * Symlinks are followed (a workspace corpus usually lives behind one), with\n * realpath cycle detection, and the listing is sorted, so the result does not\n * depend on directory order.\n */\nimport { readdirSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { join, relative, resolve, sep } from 'node:path'\nimport type { CorpusEntry } from './identity.ts'\n\nexport type LoadCorpusOptions = {\n /** Ids are relative to this directory. Required \u2014 see the note above. */\n base: string\n /** Directories to walk, relative to `base` (or absolute). */\n roots: readonly string[]\n /** File extensions to include, with the dot: `['.less', '.css']`. */\n extensions: readonly string[]\n /**\n * Skip files larger than this. A handful of enormous generated fixtures can\n * dominate the runtime of a gate meant to be run on every edit.\n */\n maxBytes?: number\n /**\n * Directories never descended into. An entry with no `/` matches a directory\n * NAME anywhere; an entry containing `/` matches a path suffix, in POSIX form,\n * relative to the root being walked \u2014 so `node_modules/.cache` skips the cache\n * without skipping the package tree around it.\n */\n ignoreDirs?: readonly string[]\n /** Tolerate a root that does not exist, reporting it in `missingRoots`. */\n allowMissingRoots?: boolean\n}\n\nexport type LoadedCorpus = {\n entries: CorpusEntry[]\n /** Roots that did not resolve. Non-empty only with `allowMissingRoots`. */\n missingRoots: string[]\n /** Files skipped for exceeding `maxBytes`, by id. */\n skippedLarge: string[]\n}\n\nconst DEFAULT_IGNORE = ['.git', 'node_modules/.cache']\n\nexport function loadCorpus(options: LoadCorpusOptions): LoadedCorpus {\n const base = resolve(options.base)\n const ignoreDirs = options.ignoreDirs ?? DEFAULT_IGNORE\n // A NAME pattern matches any directory so called; a PATH pattern (one containing\n // a separator) matches a suffix of the path relative to the root. Splitting them\n // here rather than testing `Set.has(item.name)` is the whole fix for a default\n // that read `node_modules/.cache` and matched nothing: a basename is never equal\n // to a path, so the declared exclusion silently admitted every cache file it\n // named \u2014 and a digest that includes a local build cache is exactly the\n // filesystem-dependent reading this module exists to prevent.\n const ignoreNames = new Set(ignoreDirs.filter(d => !d.includes('/')))\n const ignorePaths = ignoreDirs\n .filter(d => d.includes('/'))\n .map(d => d.replace(/^\\.?\\/+/, '').replace(/\\/+$/, ''))\n const maxBytes = options.maxBytes ?? Number.POSITIVE_INFINITY\n const exts = new Set(options.extensions.map(e => e.toLowerCase()))\n\n const missingRoots: string[] = []\n const skippedLarge: string[] = []\n // Keyed by REALPATH, so one physical file reached through two aliased roots is\n // one entry. The value is the id we keep; see the tie-break at the insert site.\n const files = new Map<string, string>()\n\n const isIgnored = (name: string, relFromRoot: string): boolean => {\n if (ignoreNames.has(name)) return true\n return ignorePaths.some(p => relFromRoot === p || relFromRoot.endsWith(`/${p}`))\n }\n\n const walk = (dir: string, root: string, visited: Set<string>): void => {\n let real: string\n try {\n real = realpathSync(dir)\n } catch {\n return\n }\n // Cycle detection only, and scoped to THIS root's traversal. A set shared across\n // roots made the second of two aliased roots return here immediately, so it\n // contributed nothing and swapping the root order changed every id it owned.\n if (visited.has(real)) return\n visited.add(real)\n for (const item of readdirSync(dir, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))) {\n const full = join(dir, item.name)\n if (isIgnored(item.name, relative(root, full).split(sep).join('/'))) continue\n // A symlink reports neither isDirectory nor isFile, so stat through it.\n let isDir = item.isDirectory()\n let isFile = item.isFile()\n let size = 0\n if (item.isSymbolicLink() || (!isDir && !isFile)) {\n try {\n const st = statSync(full)\n isDir = st.isDirectory()\n isFile = st.isFile()\n size = st.size\n } catch {\n continue\n }\n }\n if (isDir) {\n walk(full, root, visited)\n continue\n }\n if (!isFile) continue\n const dot = item.name.lastIndexOf('.')\n if (dot < 0 || !exts.has(item.name.slice(dot).toLowerCase())) continue\n if (size === 0) {\n try {\n size = statSync(full).size\n } catch {\n continue\n }\n }\n if (size > maxBytes) {\n skippedLarge.push(idOf(base, full))\n continue\n }\n // One physical file can be reached through several aliased roots. Keep the\n // SMALLEST id rather than the first one seen, so the corpus is a function of\n // the files and the base alone \u2014 not of the order `roots` happens to be in.\n let realFile: string\n try {\n realFile = realpathSync(full)\n } catch {\n continue\n }\n const id = idOf(base, full)\n const existing = files.get(realFile)\n if (existing === undefined || id < existing) files.set(realFile, id)\n }\n }\n\n for (const root of options.roots) {\n const full = resolve(base, root)\n try {\n if (!statSync(full).isDirectory()) throw new Error('not a directory')\n } catch {\n if (!options.allowMissingRoots) {\n throw new Error(\n `loadCorpus: root ${JSON.stringify(root)} does not resolve to a directory (${full}). A corpus that `\n + 'quietly shrank produces a different aggregate that looks like a grammar change. Fix the root, or pass '\n + 'allowMissingRoots and record `missingRoots` alongside the digest.',\n )\n }\n missingRoots.push(root)\n continue\n }\n walk(full, full, new Set())\n }\n\n const entries = [...files.values()]\n .sort()\n .map(id => ({ id, source: readFileSync(resolve(base, id), 'utf8') }))\n return { entries, missingRoots, skippedLarge: skippedLarge.sort() }\n}\n\n/** Always POSIX-separated, so a Windows run and a POSIX run agree. */\nfunction idOf(base: string, full: string): string {\n return relative(base, full).split(sep).join('/')\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["payload"]
7
+ }