@ybotok/loam 0.1.0-beta.1 → 0.1.0-beta.2

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 (115) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +6 -1
  3. package/dist/cli.js +4 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/adopt.js +17 -3
  6. package/dist/commands/adopt.js.map +1 -1
  7. package/dist/commands/archive.js +24 -8
  8. package/dist/commands/archive.js.map +1 -1
  9. package/dist/commands/delta.js +74 -47
  10. package/dist/commands/delta.js.map +1 -1
  11. package/dist/commands/dependencies.js +7 -2
  12. package/dist/commands/dependencies.js.map +1 -1
  13. package/dist/commands/docs-repo-gate.js +104 -0
  14. package/dist/commands/docs-repo-gate.js.map +1 -0
  15. package/dist/commands/explore.js +195 -0
  16. package/dist/commands/explore.js.map +1 -0
  17. package/dist/commands/format.js +17 -0
  18. package/dist/commands/format.js.map +1 -0
  19. package/dist/commands/gherkin.js +87 -48
  20. package/dist/commands/gherkin.js.map +1 -1
  21. package/dist/commands/init.js +3 -3
  22. package/dist/commands/init.js.map +1 -1
  23. package/dist/commands/instructions.js +70 -0
  24. package/dist/commands/instructions.js.map +1 -0
  25. package/dist/commands/list.js +6 -76
  26. package/dist/commands/list.js.map +1 -1
  27. package/dist/commands/migrate-openspec.js +45 -28
  28. package/dist/commands/migrate-openspec.js.map +1 -1
  29. package/dist/commands/new.js +35 -34
  30. package/dist/commands/new.js.map +1 -1
  31. package/dist/commands/rebase.js +2 -4
  32. package/dist/commands/rebase.js.map +1 -1
  33. package/dist/commands/show.js +26 -31
  34. package/dist/commands/show.js.map +1 -1
  35. package/dist/commands/status.js +8 -24
  36. package/dist/commands/status.js.map +1 -1
  37. package/dist/commands/unarchive.js +12 -5
  38. package/dist/commands/unarchive.js.map +1 -1
  39. package/dist/commands/validate.js +115 -133
  40. package/dist/commands/validate.js.map +1 -1
  41. package/dist/commands/verify.js +33 -17
  42. package/dist/commands/verify.js.map +1 -1
  43. package/dist/commands/vouch.js +77 -59
  44. package/dist/commands/vouch.js.map +1 -1
  45. package/dist/core/agent.js +273 -31
  46. package/dist/core/agent.js.map +1 -1
  47. package/dist/core/arch.js +28 -2
  48. package/dist/core/arch.js.map +1 -1
  49. package/dist/core/brief.js +3 -3
  50. package/dist/core/brief.js.map +1 -1
  51. package/dist/core/coherence.js +37 -13
  52. package/dist/core/coherence.js.map +1 -1
  53. package/dist/core/concurrency.js +51 -0
  54. package/dist/core/concurrency.js.map +1 -0
  55. package/dist/core/config.js +10 -2
  56. package/dist/core/config.js.map +1 -1
  57. package/dist/core/delta.js +21 -2
  58. package/dist/core/delta.js.map +1 -1
  59. package/dist/core/dependencies.js +46 -42
  60. package/dist/core/dependencies.js.map +1 -1
  61. package/dist/core/docs.js +2 -1
  62. package/dist/core/docs.js.map +1 -1
  63. package/dist/core/doctor.js +41 -26
  64. package/dist/core/doctor.js.map +1 -1
  65. package/dist/core/document-bytes.js +59 -0
  66. package/dist/core/document-bytes.js.map +1 -0
  67. package/dist/core/explore.js +225 -0
  68. package/dist/core/explore.js.map +1 -0
  69. package/dist/core/fleet-context.js +16 -63
  70. package/dist/core/fleet-context.js.map +1 -1
  71. package/dist/core/frontmatter.js +1 -5
  72. package/dist/core/frontmatter.js.map +1 -1
  73. package/dist/core/gherkin.js +3 -61
  74. package/dist/core/gherkin.js.map +1 -1
  75. package/dist/core/health.js +1 -5
  76. package/dist/core/health.js.map +1 -1
  77. package/dist/core/ids.js +34 -5
  78. package/dist/core/ids.js.map +1 -1
  79. package/dist/core/json.js +8 -1
  80. package/dist/core/json.js.map +1 -1
  81. package/dist/core/likec4.js +6 -1
  82. package/dist/core/likec4.js.map +1 -1
  83. package/dist/core/maturity.js +66 -0
  84. package/dist/core/maturity.js.map +1 -0
  85. package/dist/core/openapi-merge.js +39 -6
  86. package/dist/core/openapi-merge.js.map +1 -1
  87. package/dist/core/openapi.js +17 -5
  88. package/dist/core/openapi.js.map +1 -1
  89. package/dist/core/openspec-inventory.js +64 -27
  90. package/dist/core/openspec-inventory.js.map +1 -1
  91. package/dist/core/path-safety.js +59 -0
  92. package/dist/core/path-safety.js.map +1 -1
  93. package/dist/core/provenance.js +35 -10
  94. package/dist/core/provenance.js.map +1 -1
  95. package/dist/core/records.js +33 -0
  96. package/dist/core/records.js.map +1 -0
  97. package/dist/core/repo.js +75 -1
  98. package/dist/core/repo.js.map +1 -1
  99. package/dist/core/report.js +9 -0
  100. package/dist/core/report.js.map +1 -1
  101. package/dist/core/results.js +1 -3
  102. package/dist/core/results.js.map +1 -1
  103. package/dist/core/spec.js +3 -3
  104. package/dist/core/spec.js.map +1 -1
  105. package/dist/core/staging.js +124 -17
  106. package/dist/core/staging.js.map +1 -1
  107. package/dist/core/status.js +122 -33
  108. package/dist/core/status.js.map +1 -1
  109. package/dist/core/steps.js +72 -0
  110. package/dist/core/steps.js.map +1 -0
  111. package/dist/core/verify.js +18 -4
  112. package/dist/core/verify.js.map +1 -1
  113. package/dist/core/version.js +17 -1
  114. package/dist/core/version.js.map +1 -1
  115. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"likec4.js","sourceRoot":"","sources":["../../src/core/likec4.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { LikeC4 } from \"likec4\";\n\n/** A parse/validation issue reported by LikeC4. */\nexport interface LikeC4Error {\n message: string;\n line?: number;\n sourceFsPath?: string;\n}\n\n/** loam-neutral element view (flattened from the LikeC4 parsed model). */\nexport interface Elem {\n id: string;\n kind: string;\n title: string;\n description?: string;\n /**\n * The `services/<id>` directory this element stands for, from the element's\n * `metadata { service '...' }`. Absent on the elements nobody has bound —\n * see `elementService` for the fallback.\n */\n service?: string;\n tags: string[];\n}\n\n/**\n * The service directory an element stands for: an explicit\n * `metadata { service '<id>' }` binding wins, the title is the fallback.\n *\n * The fallback is what every docs repo written before the binding existed relies\n * on, and it is also the trap the binding exists to close: matching on the title\n * means renaming a box in a diagram silently unlinks it from its service, and\n * every check that joined the two just stops finding anything.\n */\nexport function elementService(e: Elem): string {\n return e.service ?? e.title;\n}\n\n/**\n * Every id an endpoint may be filed under, nearest first: `a.b.c`, `a.b`, `a`.\n *\n * A landscape does not have to draw a service as one opaque box. The moment\n * somebody models its containers — `paymentService.api`, `paymentService.worker`\n * — an edge drawn INTO a container is still an edge into the service, and every\n * join that groups by service has to know that. Resolving only the exact id is\n * what made those edges invisible: the spine check silently skipped them, and\n * the no-openapi grace treated a service with a dozen inbound container calls as\n * one nobody calls at all.\n */\nfunction ancestorIds(id: string): string[] {\n const out = [id];\n for (let dot = id.lastIndexOf(\".\"); dot !== -1; dot = id.lastIndexOf(\".\", dot - 1)) {\n out.push(id.slice(0, dot));\n }\n return out;\n}\n\n/**\n * A memoized `id -> service` resolver over one document.\n *\n * Resolution order, and why it is this order:\n *\n * 1. the nearest ancestor (the id itself first) carrying an explicit\n * `metadata { service '<id>' }` — a binding is a claim somebody wrote down,\n * so it outranks every guess;\n * 2. the nearest ancestor whose title names a REAL `services/<id>/` directory —\n * positive evidence from the filesystem, available only to callers that\n * hand in `known`;\n * 3. the element's own title, and finally the raw id — today's fallback, kept\n * LAST because it is the one that lies: it happily resolves\n * `paymentService.api` to \"api\", a service that has never existed.\n *\n * Built once per document and shared, because it is called inside loops over\n * every relationship and the walk up the ancestor chain is not free.\n */\nexport function serviceResolver(\n elements: Elem[],\n known?: ReadonlySet<string>,\n): (id: string) => string {\n const byId = new Map(elements.map((e) => [e.id, e]));\n const memo = new Map<string, string>();\n return (id: string): string => {\n const hit = memo.get(id);\n if (hit !== undefined) return hit;\n let answer: string | undefined;\n for (const candidate of ancestorIds(id)) {\n const e = byId.get(candidate);\n if (e?.service !== undefined) {\n answer = e.service;\n break;\n }\n }\n if (answer === undefined && known !== undefined) {\n for (const candidate of ancestorIds(id)) {\n const e = byId.get(candidate);\n if (e !== undefined && known.has(e.title)) {\n answer = e.title;\n break;\n }\n }\n }\n if (answer === undefined) {\n const self = byId.get(id);\n answer = self ? elementService(self) : id;\n }\n memo.set(id, answer);\n return answer;\n };\n}\n\n/**\n * The service a relationship endpoint belongs to. An id that names no element\n * resolves to itself, so a partial document degrades to the id rather than\n * throwing.\n *\n * `known` is the set of service directories that actually exist; pass it\n * wherever the caller has enumerated `services/`, so an edge into a modelled\n * container resolves to the service that owns it instead of to the container's\n * own title. Callers with a single document and no repository in hand omit it\n * and keep the pre-existing behaviour.\n */\nexport function serviceOf(elements: Elem[], id: string, known?: ReadonlySet<string>): string {\n return serviceResolver(elements, known)(id);\n}\n\n/** loam-neutral relationship view. */\nexport interface Rel {\n source: string;\n target: string;\n title?: string;\n /** OpenAPI operationId this call uses, from the relationship's `metadata { op '...' }`. */\n op?: string;\n tags: string[];\n}\n\nexport interface LoadedDoc {\n errors: LikeC4Error[];\n elements: Elem[];\n relationships: Rel[];\n}\n\n/**\n * The slice of a LikeC4 model loam reads: elements and relationships, and on\n * each of those only id/kind/title/description/tags/metadata.\n *\n * It is a type of its own, rather than an inline cast at the one call site,\n * because BOTH of LikeC4's model stages expose exactly this slice — which is\n * what makes the cheap stage a safe substitute for the expensive one. The\n * substitution is pinned in test/likec4-model-parity.test.ts, which flattens\n * both stages through `flattenModel` below and compares the results.\n */\nexport interface ReadableModel {\n elements: () => Iterable<{\n id: string;\n kind: string;\n title: string;\n description?: unknown;\n tags?: readonly string[];\n metadata?: unknown;\n }>;\n relationships: () => Iterable<{\n source: { id: string };\n target: { id: string };\n title?: string | null;\n tags?: readonly string[];\n metadata?: unknown;\n }>;\n}\n\n/** Flatten a LikeC4 model into loam's neutral `Elem`/`Rel` view. */\nexport function flattenModel(model: ReadableModel): { elements: Elem[]; relationships: Rel[] } {\n const elements: Elem[] = [...model.elements()].map((e) => ({\n id: e.id,\n kind: e.kind,\n title: e.title,\n description: descText(e.description),\n service: metaKey(e.metadata, \"service\"),\n tags: [...(e.tags ?? [])],\n }));\n const relationships: Rel[] = [...model.relationships()].map((r) => ({\n source: r.source.id,\n target: r.target.id,\n // LikeC4 reports an untitled edge as title: null — normalize to the declared `title?: string`.\n title: r.title ?? undefined,\n op: metaKey(r.metadata, \"op\"),\n tags: [...(r.tags ?? [])],\n }));\n return { elements, relationships };\n}\n\n/**\n * Load and validate a single self-contained `.likec4` document, in-process\n * (no external tool, no JVM). Returns validation errors and, if clean, the\n * flattened elements + relationships.\n */\nexport async function loadFile(path: string): Promise<LoadedDoc> {\n return loadSource(await readFile(path, \"utf8\"));\n}\n\n/**\n * `loadFile` for text that is not (yet) on disk — what the archive merge uses\n * to prove a computed landscape parses BEFORE anything is written.\n */\nexport async function loadSource(src: string): Promise<LoadedDoc> {\n // LikeC4 owns a Langium workspace and registers a process-exit listener for\n // it. Validation creates many short-lived instances, so every acquired\n // instance must be disposed even on an invalid document or a failed model\n // computation. Its logger is disabled because diagnostics are returned in\n // LoadedDoc instead of being written out-of-band to stderr.\n const likec4 = await LikeC4.fromSource(src, { logger: false });\n try {\n const errors = (likec4.getErrors() as LikeC4Error[]) ?? [];\n if (errors.length > 0) {\n return { errors, elements: [], relationships: [] };\n }\n\n // `parsedModel`, not `computedModel`: the computed stage additionally\n // computes every VIEW the document declares (and a default one when it\n // declares none), which loam never reads — it renders nothing. That work is\n // superlinear in the number of RELATIONSHIPS, so a landscape at fleet shape\n // turned `loam list` from under a second into minutes. The elements and\n // relationships below are identical either way.\n const model = (await likec4.parsedModel()) as ReadableModel;\n return { errors, ...flattenModel(model) };\n } finally {\n await likec4.dispose();\n }\n}\n\n/**\n * Read one string key out of a LikeC4 `metadata { ... }` block. Two keys carry\n * loam's spines: `op` on a relationship (the OpenAPI operationId it calls) and\n * `service` on an element (the services/<id> directory it stands for). Elements\n * with no metadata come back as `{}`, so a missing key is indistinguishable from\n * a missing block — both mean \"not bound\".\n */\nfunction metaKey(m: unknown, key: string): string | undefined {\n if (m && typeof m === \"object\") {\n const v = (m as Record<string, unknown>)[key];\n if (typeof v === \"string\") return v;\n }\n return undefined;\n}\n\n/** LikeC4 descriptions can be a string or a rich-text object ({ txt } / { text } / { md }). */\nfunction descText(d: unknown): string | undefined {\n if (typeof d === \"string\") return d;\n if (d && typeof d === \"object\") {\n const o = d as Record<string, unknown>;\n for (const key of [\"txt\", \"text\", \"md\", \"value\"]) {\n const v = o[key];\n if (typeof v === \"string\") return v;\n }\n }\n return undefined;\n}\n\n/* ------------------------------------------------------------------ */\n/* Source scanning — the text-level view the archive merge splices from */\n/* ------------------------------------------------------------------ */\n\n/** A string literal in LikeC4 source: its span in the text, and its unescaped value. */\nexport interface SourceLiteral {\n start: number;\n end: number;\n value: string;\n}\n\n/**\n * A LikeC4 source with everything that is not code blanked out: string\n * interiors and comments become spaces, newlines survive, and the result is\n * exactly as long as the input — so structure (braces, arrows, `#tags`) can be\n * read with plain string operations at offsets that are valid in the original.\n */\nexport interface MaskedSource {\n code: string;\n literals: SourceLiteral[];\n}\n\nexport function maskSource(text: string): MaskedSource {\n const out = text.split(\"\");\n const literals: SourceLiteral[] = [];\n type State = \"code\" | \"squote\" | \"dquote\" | \"lineComment\" | \"blockComment\";\n let state: State = \"code\";\n let litStart = -1;\n let lit = \"\";\n for (let i = 0; i < text.length; i += 1) {\n const ch = text[i]!;\n const next = text[i + 1];\n switch (state) {\n case \"code\":\n if (ch === \"'\" || ch === '\"') {\n state = ch === \"'\" ? \"squote\" : \"dquote\";\n litStart = i;\n lit = \"\";\n out[i] = \" \";\n } else if (ch === \"/\" && next === \"/\") {\n state = \"lineComment\";\n out[i] = \" \";\n } else if (ch === \"/\" && next === \"*\") {\n state = \"blockComment\";\n out[i] = \" \";\n }\n break;\n case \"squote\":\n case \"dquote\":\n if (ch === \"\\\\\" && i + 1 < text.length) {\n lit += text[i + 1]!;\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 1;\n } else if (ch === (state === \"squote\" ? \"'\" : '\"')) {\n literals.push({ start: litStart, end: i + 1, value: lit });\n state = \"code\";\n out[i] = \" \";\n } else {\n lit += ch;\n if (ch !== \"\\n\") out[i] = \" \";\n }\n break;\n case \"lineComment\":\n if (ch === \"\\n\") state = \"code\";\n else out[i] = \" \";\n break;\n case \"blockComment\":\n if (ch === \"*\" && next === \"/\") {\n state = \"code\";\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 1;\n } else if (ch !== \"\\n\") {\n out[i] = \" \";\n }\n break;\n }\n }\n return { code: out.join(\"\"), literals };\n}\n\n/** Index of the `}` matching the `{` at `open`, over MASKED code; -1 when unbalanced. */\nexport function matchBrace(code: string, open: number): number {\n let depth = 0;\n for (let i = open; i < code.length; i += 1) {\n if (code[i] === \"{\") depth += 1;\n else if (code[i] === \"}\") {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/** An element declaration located in source, under the id the computed model gives it. */\nexport interface ScannedElement {\n /** Full dotted id — `parent.child` for a nested declaration. */\n id: string;\n /** Span of the whole declaration: first head character to one past its end. */\n start: number;\n end: number;\n /** Its own body braces; -1 when the declaration has no body. */\n bodyOpen: number;\n bodyClose: number;\n /** Leading whitespace of the declaration's first line. */\n indent: string;\n}\n\n/** A relationship statement located in source, endpoints resolved to full ids (best effort). */\nexport interface ScannedRel {\n source: string;\n target: string;\n title?: string;\n op?: string;\n tags: string[];\n start: number;\n end: number;\n indent: string;\n}\n\nexport interface ScannedModel {\n /** The `model` block's own braces. */\n open: number;\n close: number;\n /** In document order. A nested declaration's span lies inside its parent's. */\n elements: ScannedElement[];\n rels: ScannedRel[];\n}\n\n/**\n * Locate every element and relationship declaration inside the top-level\n * `model { ... }` block of a LikeC4 source, with the byte range each one\n * occupies. This is the splice map `loam archive` merges the landscape with:\n * the parsed model says WHAT exists, this says WHERE its authored text is —\n * verbatim, so nothing the parser does not model (technology, style, links)\n * can be lost by rebuilding it.\n *\n * Both declaration forms are recognised — `name = kind ...` always, and\n * `kind name ...` for any kind the document's own `specification` block\n * declares. Relationship endpoints are resolved the way LikeC4 reads them:\n * innermost enclosing scope outward, then the top level, then a unique leaf\n * name anywhere; `it`/`this` (and an omitted source) mean the enclosing\n * element. A name that resolves nowhere is left as written — the caller's\n * match against the parsed model then fails loudly instead of guessing.\n *\n * Returns null when there is no model block. Callers only hand in documents\n * LikeC4 has already parsed, so the scan can trust balanced braces.\n */\nexport function scanModel(text: string): ScannedModel | null {\n const { code, literals } = maskSource(text);\n const m = /\\bmodel\\s*\\{/.exec(code);\n if (!m) return null;\n const open = m.index + m[0].length - 1;\n const close = matchBrace(code, open);\n if (close === -1) return null;\n\n // Element kinds from the specification block(s): the `<kind> <name>`\n // declaration form is recognisable only by its first token being a kind.\n const kinds = new Set<string>();\n for (const sm of code.matchAll(/\\bspecification\\s*\\{/g)) {\n const sClose = matchBrace(code, sm.index + sm[0].length - 1);\n if (sClose === -1) continue;\n for (const em of code.slice(sm.index, sClose).matchAll(/\\belement\\s+([A-Za-z_][\\w-]*)/g)) {\n kinds.add(em[1]!);\n }\n }\n\n const indentOf = (at: number): string => {\n const nl = text.lastIndexOf(\"\\n\", at - 1);\n const ws = text.slice(nl + 1, at);\n return /^[ \\t]*$/.test(ws) ? ws : \"\";\n };\n const literalIn = (from: number, to: number): SourceLiteral | undefined =>\n literals.find((l) => l.start >= from && l.end <= to);\n const keyedLiteral = (key: string, from: number, to: number): string | undefined => {\n if (from === -1) return undefined;\n const re = new RegExp(`\\\\b${key}\\\\b`, \"g\");\n re.lastIndex = from;\n const km = re.exec(code);\n if (km === null || km.index >= to) return undefined;\n return literalIn(km.index, to)?.value;\n };\n const trimmedEnd = (from: number, to: number): number => {\n let e = to;\n while (e > from && /\\s/.test(text[e - 1]!)) e -= 1;\n return e;\n };\n\n const elements: ScannedElement[] = [];\n interface RawRel {\n srcLit?: string;\n tgtLit: string;\n parent: string;\n start: number;\n end: number;\n indent: string;\n title?: string;\n op?: string;\n tags: string[];\n }\n const raw: RawRel[] = [];\n const stack: Array<{ id: string; el: ScannedElement }> = [];\n\n let i = open + 1;\n while (i < close) {\n const ch = code[i]!;\n if (/\\s/.test(ch)) {\n i += 1;\n continue;\n }\n if (ch === \"}\") {\n const frame = stack.pop();\n if (frame !== undefined) {\n frame.el.bodyClose = i;\n frame.el.end = i + 1;\n elements.push(frame.el);\n }\n i += 1;\n continue;\n }\n\n // A statement's head: up to its own `{`, the end of the line, or the\n // enclosing block's `}` on the same line — whichever comes first.\n const stmtStart = i;\n let headEnd = close;\n let opener = -1;\n for (let j = i; j < close; j += 1) {\n const c = code[j]!;\n if (c === \"\\n\" || c === \"}\") {\n headEnd = j;\n break;\n }\n if (c === \"{\") {\n opener = j;\n headEnd = j;\n break;\n }\n }\n const head = code.slice(stmtStart, headEnd);\n const parentId = stack.length > 0 ? stack[stack.length - 1]!.id : \"\";\n\n // Classify: `name = kind` first, then a relationship (the arrow cannot hide\n // in a string — the head is masked), then the `kind name` form, else a\n // property/tag line that is consumed whole, nested block included.\n let localName: string | null = null;\n const assign = /^([A-Za-z_]\\w*)\\s*=\\s*[A-Za-z_]/.exec(head);\n if (assign !== null) {\n localName = assign[1]!;\n } else if (!head.includes(\"->\")) {\n const toks = head.trim().split(/\\s+/);\n if (toks.length >= 2 && kinds.has(toks[0]!) && /^[A-Za-z_]\\w*$/.test(toks[1]!)) {\n localName = toks[1]!;\n }\n }\n\n if (localName !== null) {\n const id = parentId === \"\" ? localName : `${parentId}.${localName}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n };\n if (opener !== -1) {\n stack.push({ id, el });\n i = opener + 1;\n } else {\n el.end = trimmedEnd(stmtStart, headEnd);\n elements.push(el);\n i = headEnd;\n }\n continue;\n }\n\n if (head.includes(\"->\")) {\n const bClose = opener === -1 ? -1 : matchBrace(code, opener);\n const stmtEnd = opener === -1 ? trimmedEnd(stmtStart, headEnd) : bClose === -1 ? close : bClose + 1;\n const am = /^([A-Za-z_][\\w.]*)?\\s*(?:-\\[[^\\]]*\\])?->\\s*([A-Za-z_][\\w.]*)/.exec(head);\n if (am !== null) {\n const arrowEnd = stmtStart + am[0].length;\n const bodyFrom = opener === -1 ? -1 : opener + 1;\n const bodyTo = opener === -1 ? -1 : stmtEnd - 1;\n const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral(\"title\", bodyFrom, bodyTo);\n const tags: string[] = [];\n for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\\w-]+)/g)) tags.push(tm[1]!);\n raw.push({\n srcLit: am[1],\n tgtLit: am[2]!,\n parent: parentId,\n start: stmtStart,\n end: stmtEnd,\n indent: indentOf(stmtStart),\n title,\n op: keyedLiteral(\"op\", bodyFrom, bodyTo),\n tags,\n });\n }\n i = Math.max(stmtEnd, headEnd);\n continue;\n }\n\n if (opener !== -1) {\n const bClose = matchBrace(code, opener);\n i = bClose === -1 ? close : bClose + 1;\n } else {\n i = headEnd;\n }\n }\n\n // Resolve relationship endpoints against everything declared anywhere in the\n // model — LikeC4 resolution is not order-dependent, so neither is this.\n const ids = new Set(elements.map((e) => e.id));\n const byLeaf = new Map<string, string[]>();\n for (const e of elements) {\n const leaf = e.id.slice(e.id.lastIndexOf(\".\") + 1);\n byLeaf.set(leaf, [...(byLeaf.get(leaf) ?? []), e.id]);\n }\n const resolve = (lit: string | undefined, enclosing: string): string => {\n if (lit === undefined || lit === \"it\" || lit === \"this\") return enclosing;\n const segs = lit.split(\".\");\n let base: string | undefined;\n for (let scope = enclosing; scope !== \"\" && base === undefined; ) {\n if (ids.has(`${scope}.${segs[0]!}`)) base = `${scope}.${segs[0]!}`;\n const dot = scope.lastIndexOf(\".\");\n scope = dot === -1 ? \"\" : scope.slice(0, dot);\n }\n if (base === undefined && ids.has(segs[0]!)) base = segs[0]!;\n if (base === undefined) {\n const leafed = byLeaf.get(segs[0]!);\n if (leafed !== undefined && leafed.length === 1) base = leafed[0]!;\n }\n return [base ?? segs[0]!, ...segs.slice(1)].join(\".\");\n };\n\n const rels: ScannedRel[] = raw.map((r) => ({\n source: resolve(r.srcLit, r.parent),\n target: resolve(r.tgtLit, r.parent),\n title: r.title,\n op: r.op,\n tags: r.tags,\n start: r.start,\n end: r.end,\n indent: r.indent,\n }));\n\n elements.sort((a, b) => a.start - b.start);\n return { open, close, elements, rels };\n}\n"]}
1
+ {"version":3,"file":"likec4.js","sourceRoot":"","sources":["../../src/core/likec4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAwBhC;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,CAAO;IACpC,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,WAAW,CAAC,EAAU;IAC7B,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;IACjB,KAAK,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;QACnF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,KAA2B;IAE3B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,OAAO,CAAC,EAAU,EAAU,EAAE;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;QAClC,IAAI,MAA0B,CAAC;QAC/B,KAAK,MAAM,SAAS,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC9B,IAAI,CAAC,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;gBACnB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAChD,KAAK,MAAM,SAAS,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;gBACxC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBAC9B,IAAI,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC1C,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC;oBACjB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1B,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACrB,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,EAAU,EAAE,KAA2B;IACjF,OAAO,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,CAAC;AA8CD,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,KAAoB;IAC/C,MAAM,QAAQ,GAAW,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzD,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;QACpC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC;QACvC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KAC1B,CAAC,CAAC,CAAC;IACJ,MAAM,aAAa,GAAU,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;QACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;QACnB,+FAA+F;QAC/F,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,SAAS;QAC3B,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC7B,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KAC1B,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY;IACzC,OAAO,UAAU,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,4EAA4E;IAC5E,uEAAuE;IACvE,0EAA0E;IAC1E,0EAA0E;IAC1E,4DAA4D;IAC5D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,4EAA4E;QAC5E,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,uCAAuC;QACvC,MAAM,MAAM,GAAkB,MAAM,CAAC,SAAS,EAAE,CAAC;QACjD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACrD,CAAC;QAED,sEAAsE;QACtE,uEAAuE;QACvE,4EAA4E;QAC5E,4EAA4E;QAC5E,wEAAwE;QACxE,gDAAgD;QAChD,MAAM,KAAK,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAkB,CAAC;QAC5D,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5C,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,CAAU,EAAE,GAAW;IACtC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAI,CAA6B,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,+FAA+F;AAC/F,SAAS,QAAQ,CAAC,CAAU;IAC1B,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAwBD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,IAAI,KAAK,GAAU,MAAM,CAAC;IAC1B,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;IAClB,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACzB,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,MAAM;gBACT,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;oBAC7B,KAAK,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;oBACzC,QAAQ,GAAG,CAAC,CAAC;oBACb,GAAG,GAAG,EAAE,CAAC;oBACT,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACf,CAAC;qBAAM,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACtC,KAAK,GAAG,aAAa,CAAC;oBACtB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACf,CAAC;qBAAM,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACtC,KAAK,GAAG,cAAc,CAAC;oBACvB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACf,CAAC;gBACD,MAAM;YACR,KAAK,QAAQ,CAAC;YACd,KAAK,QAAQ;gBACX,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;oBACvC,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;oBACpB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;oBACb,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;oBACjB,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;qBAAM,IAAI,EAAE,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;oBAC3D,KAAK,GAAG,MAAM,CAAC;oBACf,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACf,CAAC;qBAAM,CAAC;oBACN,GAAG,IAAI,EAAE,CAAC;oBACV,IAAI,EAAE,KAAK,IAAI;wBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBAChC,CAAC;gBACD,MAAM;YACR,KAAK,aAAa;gBAChB,IAAI,EAAE,KAAK,IAAI;oBAAE,KAAK,GAAG,MAAM,CAAC;;oBAC3B,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBAClB,MAAM;YACR,KAAK,cAAc;gBACjB,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBAC/B,KAAK,GAAG,MAAM,CAAC;oBACf,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;oBACb,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;oBACjB,CAAC,IAAI,CAAC,CAAC;gBACT,CAAC;qBAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;oBACvB,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBACf,CAAC;gBACD,MAAM;QACV,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,IAAY;IACnD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,KAAK,IAAI,CAAC,CAAC;aAC3B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzB,KAAK,IAAI,CAAC,CAAC;YACX,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAqCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,qEAAqE;IACrE,yEAAyE;IACzE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7D,IAAI,MAAM,KAAK,CAAC,CAAC;YAAE,SAAS;QAC5B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC;YACzF,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAU,EAAE;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAClC,OAAO,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvC,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAU,EAA6B,EAAE,CACxE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,IAAY,EAAE,EAAU,EAAsB,EAAE;QACjF,IAAI,IAAI,KAAK,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC;QAC3C,EAAE,CAAC,SAAS,GAAG,IAAI,CAAC;QACpB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE;YAAE,OAAO,SAAS,CAAC;QACpD,OAAO,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC;IACxC,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAU,EAAU,EAAE;QACtD,IAAI,CAAC,GAAG,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;YAAE,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAYtC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,KAAK,GAA8C,EAAE,CAAC;IAE5D,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;IACjB,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACpB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,KAAK,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,CAAC;gBACvB,KAAK,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;gBACrB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC;YACD,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,qEAAqE;QACrE,kEAAkE;QAClE,MAAM,SAAS,GAAG,CAAC,CAAC;QACpB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC;QAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;YACnB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC5B,OAAO,GAAG,CAAC,CAAC;gBACZ,MAAM;YACR,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;gBACd,MAAM,GAAG,CAAC,CAAC;gBACX,OAAO,GAAG,CAAC,CAAC;gBACZ,MAAM;YACR,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAErE,4EAA4E;QAC5E,uEAAuE;QACvE,mEAAmE;QACnE,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,MAAM,MAAM,GAAG,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,SAAS,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACzB,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;gBAC/E,SAAS,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAED,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;YACpE,MAAM,EAAE,GAAmB;gBACzB,EAAE;gBACF,KAAK,EAAE,SAAS;gBAChB,GAAG,EAAE,OAAO;gBACZ,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,CAAC,CAAC;gBACb,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC;aAC5B,CAAC;YACF,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvB,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAClB,CAAC,GAAG,OAAO,CAAC;YACd,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC7D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YACpG,MAAM,EAAE,GAAG,8DAA8D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrF,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAChB,MAAM,QAAQ,GAAG,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;gBAC1C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;gBACjD,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC;gBAChD,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC7F,MAAM,IAAI,GAAa,EAAE,CAAC;gBAC1B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC;gBAC1F,GAAG,CAAC,IAAI,CAAC;oBACP,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;oBACb,MAAM,EAAE,EAAE,CAAC,CAAC,CAAE;oBACd,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,SAAS;oBAChB,GAAG,EAAE,OAAO;oBACZ,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC;oBAC3B,KAAK;oBACL,EAAE,EAAE,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;oBACxC,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YACD,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/B,SAAS;QACX,CAAC;QAED,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACxC,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,CAAC,GAAG,OAAO,CAAC;QACd,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,wEAAwE;IACxE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,GAAuB,EAAE,SAAiB,EAAU,EAAE;QACrE,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM;YAAE,OAAO,SAAS,CAAC;QAC1E,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,IAAwB,CAAC;QAC7B,KAAK,IAAI,KAAK,GAAG,SAAS,EAAE,KAAK,KAAK,EAAE,IAAI,IAAI,KAAK,SAAS,GAAI,CAAC;YACjE,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAE,EAAE,CAAC;gBAAE,IAAI,GAAG,GAAG,KAAK,IAAI,IAAI,CAAC,CAAC,CAAE,EAAE,CAAC;YACnE,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YACnC,KAAK,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC;YAAE,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QAC7D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC;YACpC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,IAAI,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QACrE,CAAC;QACD,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAE,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,IAAI,GAAiB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACnC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACnC,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,MAAM,EAAE,CAAC,CAAC,MAAM;KACjB,CAAC,CAAC,CAAC;IAEJ,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAC3C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzC,CAAC","sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { LikeC4 } from \"likec4\";\n\n/** A parse/validation issue reported by LikeC4. */\nexport interface LikeC4Error {\n message: string;\n line?: number;\n sourceFsPath?: string;\n}\n\n/** loam-neutral element view (flattened from the LikeC4 parsed model). */\nexport interface Elem {\n id: string;\n kind: string;\n title: string;\n description?: string;\n /**\n * The `services/<id>` directory this element stands for, from the element's\n * `metadata { service '...' }`. Absent on the elements nobody has bound —\n * see `elementService` for the fallback.\n */\n service?: string;\n tags: string[];\n}\n\n/**\n * The service directory an element stands for: an explicit\n * `metadata { service '<id>' }` binding wins, the title is the fallback.\n *\n * The fallback is what every docs repo written before the binding existed relies\n * on, and it is also the trap the binding exists to close: matching on the title\n * means renaming a box in a diagram silently unlinks it from its service, and\n * every check that joined the two just stops finding anything.\n */\nexport function elementService(e: Elem): string {\n return e.service ?? e.title;\n}\n\n/**\n * Every id an endpoint may be filed under, nearest first: `a.b.c`, `a.b`, `a`.\n *\n * A landscape does not have to draw a service as one opaque box. The moment\n * somebody models its containers — `paymentService.api`, `paymentService.worker`\n * — an edge drawn INTO a container is still an edge into the service, and every\n * join that groups by service has to know that. Resolving only the exact id is\n * what made those edges invisible: the spine check silently skipped them, and\n * the no-openapi grace treated a service with a dozen inbound container calls as\n * one nobody calls at all.\n */\nfunction ancestorIds(id: string): string[] {\n const out = [id];\n for (let dot = id.lastIndexOf(\".\"); dot !== -1; dot = id.lastIndexOf(\".\", dot - 1)) {\n out.push(id.slice(0, dot));\n }\n return out;\n}\n\n/**\n * A memoized `id -> service` resolver over one document.\n *\n * Resolution order, and why it is this order:\n *\n * 1. the nearest ancestor (the id itself first) carrying an explicit\n * `metadata { service '<id>' }` — a binding is a claim somebody wrote down,\n * so it outranks every guess;\n * 2. the nearest ancestor whose title names a REAL `services/<id>/` directory —\n * positive evidence from the filesystem, available only to callers that\n * hand in `known`;\n * 3. the element's own title, and finally the raw id — today's fallback, kept\n * LAST because it is the one that lies: it happily resolves\n * `paymentService.api` to \"api\", a service that has never existed.\n *\n * Built once per document and shared, because it is called inside loops over\n * every relationship and the walk up the ancestor chain is not free.\n */\nexport function serviceResolver(\n elements: Elem[],\n known?: ReadonlySet<string>,\n): (id: string) => string {\n const byId = new Map(elements.map((e) => [e.id, e]));\n const memo = new Map<string, string>();\n return (id: string): string => {\n const hit = memo.get(id);\n if (hit !== undefined) return hit;\n let answer: string | undefined;\n for (const candidate of ancestorIds(id)) {\n const e = byId.get(candidate);\n if (e?.service !== undefined) {\n answer = e.service;\n break;\n }\n }\n if (answer === undefined && known !== undefined) {\n for (const candidate of ancestorIds(id)) {\n const e = byId.get(candidate);\n if (e !== undefined && known.has(e.title)) {\n answer = e.title;\n break;\n }\n }\n }\n if (answer === undefined) {\n const self = byId.get(id);\n answer = self ? elementService(self) : id;\n }\n memo.set(id, answer);\n return answer;\n };\n}\n\n/**\n * The service a relationship endpoint belongs to. An id that names no element\n * resolves to itself, so a partial document degrades to the id rather than\n * throwing.\n *\n * `known` is the set of service directories that actually exist; pass it\n * wherever the caller has enumerated `services/`, so an edge into a modelled\n * container resolves to the service that owns it instead of to the container's\n * own title. Callers with a single document and no repository in hand omit it\n * and keep the pre-existing behaviour.\n */\nexport function serviceOf(elements: Elem[], id: string, known?: ReadonlySet<string>): string {\n return serviceResolver(elements, known)(id);\n}\n\n/** loam-neutral relationship view. */\nexport interface Rel {\n source: string;\n target: string;\n title?: string;\n /** OpenAPI operationId this call uses, from the relationship's `metadata { op '...' }`. */\n op?: string;\n tags: string[];\n}\n\nexport interface LoadedDoc {\n errors: LikeC4Error[];\n elements: Elem[];\n relationships: Rel[];\n}\n\n/**\n * The slice of a LikeC4 model loam reads: elements and relationships, and on\n * each of those only id/kind/title/description/tags/metadata.\n *\n * It is a type of its own, rather than an inline cast at the one call site,\n * because BOTH of LikeC4's model stages expose exactly this slice — which is\n * what makes the cheap stage a safe substitute for the expensive one. The\n * substitution is pinned in test/likec4-model-parity.test.ts, which flattens\n * both stages through `flattenModel` below and compares the results.\n */\nexport interface ReadableModel {\n elements: () => Iterable<{\n id: string;\n kind: string;\n title: string;\n description?: unknown;\n tags?: readonly string[];\n metadata?: unknown;\n }>;\n relationships: () => Iterable<{\n source: { id: string };\n target: { id: string };\n title?: string | null;\n tags?: readonly string[];\n metadata?: unknown;\n }>;\n}\n\n/** Flatten a LikeC4 model into loam's neutral `Elem`/`Rel` view. */\nexport function flattenModel(model: ReadableModel): { elements: Elem[]; relationships: Rel[] } {\n const elements: Elem[] = [...model.elements()].map((e) => ({\n id: e.id,\n kind: e.kind,\n title: e.title,\n description: descText(e.description),\n service: metaKey(e.metadata, \"service\"),\n tags: [...(e.tags ?? [])],\n }));\n const relationships: Rel[] = [...model.relationships()].map((r) => ({\n source: r.source.id,\n target: r.target.id,\n // LikeC4 reports an untitled edge as title: null — normalize to the declared `title?: string`.\n title: r.title ?? undefined,\n op: metaKey(r.metadata, \"op\"),\n tags: [...(r.tags ?? [])],\n }));\n return { elements, relationships };\n}\n\n/**\n * Load and validate a single self-contained `.likec4` document, in-process\n * (no external tool, no JVM). Returns validation errors and, if clean, the\n * flattened elements + relationships.\n */\nexport async function loadFile(path: string): Promise<LoadedDoc> {\n return loadSource(await readFile(path, \"utf8\"));\n}\n\n/**\n * `loadFile` for text that is not (yet) on disk — what the archive merge uses\n * to prove a computed landscape parses BEFORE anything is written.\n */\nexport async function loadSource(src: string): Promise<LoadedDoc> {\n // LikeC4 owns a Langium workspace and registers a process-exit listener for\n // it. Validation creates many short-lived instances, so every acquired\n // instance must be disposed even on an invalid document or a failed model\n // computation. Its logger is disabled because diagnostics are returned in\n // LoadedDoc instead of being written out-of-band to stderr.\n const likec4 = await LikeC4.fromSource(src, { logger: false });\n try {\n // Assigned, not cast: LikeC4 declares `getErrors()` as a non-nullable array\n // whose element type is structurally wider than ours, so the compiler can\n // check the shape here. The cast was the only thing standing between a\n // dependency renaming `message` and a build that still succeeded — and the\n // `?? []` it carried could never fire.\n const errors: LikeC4Error[] = likec4.getErrors();\n if (errors.length > 0) {\n return { errors, elements: [], relationships: [] };\n }\n\n // `parsedModel`, not `computedModel`: the computed stage additionally\n // computes every VIEW the document declares (and a default one when it\n // declares none), which loam never reads — it renders nothing. That work is\n // superlinear in the number of RELATIONSHIPS, so a landscape at fleet shape\n // turned `loam list` from under a second into minutes. The elements and\n // relationships below are identical either way.\n const model = (await likec4.parsedModel()) as ReadableModel;\n return { errors, ...flattenModel(model) };\n } finally {\n await likec4.dispose();\n }\n}\n\n/**\n * Read one string key out of a LikeC4 `metadata { ... }` block. Two keys carry\n * loam's spines: `op` on a relationship (the OpenAPI operationId it calls) and\n * `service` on an element (the services/<id> directory it stands for). Elements\n * with no metadata come back as `{}`, so a missing key is indistinguishable from\n * a missing block — both mean \"not bound\".\n */\nfunction metaKey(m: unknown, key: string): string | undefined {\n if (m && typeof m === \"object\") {\n const v = (m as Record<string, unknown>)[key];\n if (typeof v === \"string\") return v;\n }\n return undefined;\n}\n\n/** LikeC4 descriptions can be a string or a rich-text object ({ txt } / { text } / { md }). */\nfunction descText(d: unknown): string | undefined {\n if (typeof d === \"string\") return d;\n if (d && typeof d === \"object\") {\n const o = d as Record<string, unknown>;\n for (const key of [\"txt\", \"text\", \"md\", \"value\"]) {\n const v = o[key];\n if (typeof v === \"string\") return v;\n }\n }\n return undefined;\n}\n\n/* ------------------------------------------------------------------ */\n/* Source scanning — the text-level view the archive merge splices from */\n/* ------------------------------------------------------------------ */\n\n/** A string literal in LikeC4 source: its span in the text, and its unescaped value. */\nexport interface SourceLiteral {\n start: number;\n end: number;\n value: string;\n}\n\n/**\n * A LikeC4 source with everything that is not code blanked out: string\n * interiors and comments become spaces, newlines survive, and the result is\n * exactly as long as the input — so structure (braces, arrows, `#tags`) can be\n * read with plain string operations at offsets that are valid in the original.\n */\nexport interface MaskedSource {\n code: string;\n literals: SourceLiteral[];\n}\n\nexport function maskSource(text: string): MaskedSource {\n const out = text.split(\"\");\n const literals: SourceLiteral[] = [];\n type State = \"code\" | \"squote\" | \"dquote\" | \"lineComment\" | \"blockComment\";\n let state: State = \"code\";\n let litStart = -1;\n let lit = \"\";\n for (let i = 0; i < text.length; i += 1) {\n const ch = text[i]!;\n const next = text[i + 1];\n switch (state) {\n case \"code\":\n if (ch === \"'\" || ch === '\"') {\n state = ch === \"'\" ? \"squote\" : \"dquote\";\n litStart = i;\n lit = \"\";\n out[i] = \" \";\n } else if (ch === \"/\" && next === \"/\") {\n state = \"lineComment\";\n out[i] = \" \";\n } else if (ch === \"/\" && next === \"*\") {\n state = \"blockComment\";\n out[i] = \" \";\n }\n break;\n case \"squote\":\n case \"dquote\":\n if (ch === \"\\\\\" && i + 1 < text.length) {\n lit += text[i + 1]!;\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 1;\n } else if (ch === (state === \"squote\" ? \"'\" : '\"')) {\n literals.push({ start: litStart, end: i + 1, value: lit });\n state = \"code\";\n out[i] = \" \";\n } else {\n lit += ch;\n if (ch !== \"\\n\") out[i] = \" \";\n }\n break;\n case \"lineComment\":\n if (ch === \"\\n\") state = \"code\";\n else out[i] = \" \";\n break;\n case \"blockComment\":\n if (ch === \"*\" && next === \"/\") {\n state = \"code\";\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 1;\n } else if (ch !== \"\\n\") {\n out[i] = \" \";\n }\n break;\n }\n }\n return { code: out.join(\"\"), literals };\n}\n\n/** Index of the `}` matching the `{` at `open`, over MASKED code; -1 when unbalanced. */\nexport function matchBrace(code: string, open: number): number {\n let depth = 0;\n for (let i = open; i < code.length; i += 1) {\n if (code[i] === \"{\") depth += 1;\n else if (code[i] === \"}\") {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/** An element declaration located in source, under the id the computed model gives it. */\nexport interface ScannedElement {\n /** Full dotted id — `parent.child` for a nested declaration. */\n id: string;\n /** Span of the whole declaration: first head character to one past its end. */\n start: number;\n end: number;\n /** Its own body braces; -1 when the declaration has no body. */\n bodyOpen: number;\n bodyClose: number;\n /** Leading whitespace of the declaration's first line. */\n indent: string;\n}\n\n/** A relationship statement located in source, endpoints resolved to full ids (best effort). */\nexport interface ScannedRel {\n source: string;\n target: string;\n title?: string;\n op?: string;\n tags: string[];\n start: number;\n end: number;\n indent: string;\n}\n\nexport interface ScannedModel {\n /** The `model` block's own braces. */\n open: number;\n close: number;\n /** In document order. A nested declaration's span lies inside its parent's. */\n elements: ScannedElement[];\n rels: ScannedRel[];\n}\n\n/**\n * Locate every element and relationship declaration inside the top-level\n * `model { ... }` block of a LikeC4 source, with the byte range each one\n * occupies. This is the splice map `loam archive` merges the landscape with:\n * the parsed model says WHAT exists, this says WHERE its authored text is —\n * verbatim, so nothing the parser does not model (technology, style, links)\n * can be lost by rebuilding it.\n *\n * Both declaration forms are recognised — `name = kind ...` always, and\n * `kind name ...` for any kind the document's own `specification` block\n * declares. Relationship endpoints are resolved the way LikeC4 reads them:\n * innermost enclosing scope outward, then the top level, then a unique leaf\n * name anywhere; `it`/`this` (and an omitted source) mean the enclosing\n * element. A name that resolves nowhere is left as written — the caller's\n * match against the parsed model then fails loudly instead of guessing.\n *\n * Returns null when there is no model block. Callers only hand in documents\n * LikeC4 has already parsed, so the scan can trust balanced braces.\n */\nexport function scanModel(text: string): ScannedModel | null {\n const { code, literals } = maskSource(text);\n const m = /\\bmodel\\s*\\{/.exec(code);\n if (!m) return null;\n const open = m.index + m[0].length - 1;\n const close = matchBrace(code, open);\n if (close === -1) return null;\n\n // Element kinds from the specification block(s): the `<kind> <name>`\n // declaration form is recognisable only by its first token being a kind.\n const kinds = new Set<string>();\n for (const sm of code.matchAll(/\\bspecification\\s*\\{/g)) {\n const sClose = matchBrace(code, sm.index + sm[0].length - 1);\n if (sClose === -1) continue;\n for (const em of code.slice(sm.index, sClose).matchAll(/\\belement\\s+([A-Za-z_][\\w-]*)/g)) {\n kinds.add(em[1]!);\n }\n }\n\n const indentOf = (at: number): string => {\n const nl = text.lastIndexOf(\"\\n\", at - 1);\n const ws = text.slice(nl + 1, at);\n return /^[ \\t]*$/.test(ws) ? ws : \"\";\n };\n const literalIn = (from: number, to: number): SourceLiteral | undefined =>\n literals.find((l) => l.start >= from && l.end <= to);\n const keyedLiteral = (key: string, from: number, to: number): string | undefined => {\n if (from === -1) return undefined;\n const re = new RegExp(`\\\\b${key}\\\\b`, \"g\");\n re.lastIndex = from;\n const km = re.exec(code);\n if (km === null || km.index >= to) return undefined;\n return literalIn(km.index, to)?.value;\n };\n const trimmedEnd = (from: number, to: number): number => {\n let e = to;\n while (e > from && /\\s/.test(text[e - 1]!)) e -= 1;\n return e;\n };\n\n const elements: ScannedElement[] = [];\n interface RawRel {\n srcLit?: string;\n tgtLit: string;\n parent: string;\n start: number;\n end: number;\n indent: string;\n title?: string;\n op?: string;\n tags: string[];\n }\n const raw: RawRel[] = [];\n const stack: Array<{ id: string; el: ScannedElement }> = [];\n\n let i = open + 1;\n while (i < close) {\n const ch = code[i]!;\n if (/\\s/.test(ch)) {\n i += 1;\n continue;\n }\n if (ch === \"}\") {\n const frame = stack.pop();\n if (frame !== undefined) {\n frame.el.bodyClose = i;\n frame.el.end = i + 1;\n elements.push(frame.el);\n }\n i += 1;\n continue;\n }\n\n // A statement's head: up to its own `{`, the end of the line, or the\n // enclosing block's `}` on the same line — whichever comes first.\n const stmtStart = i;\n let headEnd = close;\n let opener = -1;\n for (let j = i; j < close; j += 1) {\n const c = code[j]!;\n if (c === \"\\n\" || c === \"}\") {\n headEnd = j;\n break;\n }\n if (c === \"{\") {\n opener = j;\n headEnd = j;\n break;\n }\n }\n const head = code.slice(stmtStart, headEnd);\n const parentId = stack.length > 0 ? stack[stack.length - 1]!.id : \"\";\n\n // Classify: `name = kind` first, then a relationship (the arrow cannot hide\n // in a string — the head is masked), then the `kind name` form, else a\n // property/tag line that is consumed whole, nested block included.\n let localName: string | null = null;\n const assign = /^([A-Za-z_]\\w*)\\s*=\\s*[A-Za-z_]/.exec(head);\n if (assign !== null) {\n localName = assign[1]!;\n } else if (!head.includes(\"->\")) {\n const toks = head.trim().split(/\\s+/);\n if (toks.length >= 2 && kinds.has(toks[0]!) && /^[A-Za-z_]\\w*$/.test(toks[1]!)) {\n localName = toks[1]!;\n }\n }\n\n if (localName !== null) {\n const id = parentId === \"\" ? localName : `${parentId}.${localName}`;\n const el: ScannedElement = {\n id,\n start: stmtStart,\n end: headEnd,\n bodyOpen: opener,\n bodyClose: -1,\n indent: indentOf(stmtStart),\n };\n if (opener !== -1) {\n stack.push({ id, el });\n i = opener + 1;\n } else {\n el.end = trimmedEnd(stmtStart, headEnd);\n elements.push(el);\n i = headEnd;\n }\n continue;\n }\n\n if (head.includes(\"->\")) {\n const bClose = opener === -1 ? -1 : matchBrace(code, opener);\n const stmtEnd = opener === -1 ? trimmedEnd(stmtStart, headEnd) : bClose === -1 ? close : bClose + 1;\n const am = /^([A-Za-z_][\\w.]*)?\\s*(?:-\\[[^\\]]*\\])?->\\s*([A-Za-z_][\\w.]*)/.exec(head);\n if (am !== null) {\n const arrowEnd = stmtStart + am[0].length;\n const bodyFrom = opener === -1 ? -1 : opener + 1;\n const bodyTo = opener === -1 ? -1 : stmtEnd - 1;\n const title = literalIn(arrowEnd, headEnd)?.value ?? keyedLiteral(\"title\", bodyFrom, bodyTo);\n const tags: string[] = [];\n for (const tm of code.slice(stmtStart, stmtEnd).matchAll(/#([\\w-]+)/g)) tags.push(tm[1]!);\n raw.push({\n srcLit: am[1],\n tgtLit: am[2]!,\n parent: parentId,\n start: stmtStart,\n end: stmtEnd,\n indent: indentOf(stmtStart),\n title,\n op: keyedLiteral(\"op\", bodyFrom, bodyTo),\n tags,\n });\n }\n i = Math.max(stmtEnd, headEnd);\n continue;\n }\n\n if (opener !== -1) {\n const bClose = matchBrace(code, opener);\n i = bClose === -1 ? close : bClose + 1;\n } else {\n i = headEnd;\n }\n }\n\n // Resolve relationship endpoints against everything declared anywhere in the\n // model — LikeC4 resolution is not order-dependent, so neither is this.\n const ids = new Set(elements.map((e) => e.id));\n const byLeaf = new Map<string, string[]>();\n for (const e of elements) {\n const leaf = e.id.slice(e.id.lastIndexOf(\".\") + 1);\n byLeaf.set(leaf, [...(byLeaf.get(leaf) ?? []), e.id]);\n }\n const resolve = (lit: string | undefined, enclosing: string): string => {\n if (lit === undefined || lit === \"it\" || lit === \"this\") return enclosing;\n const segs = lit.split(\".\");\n let base: string | undefined;\n for (let scope = enclosing; scope !== \"\" && base === undefined; ) {\n if (ids.has(`${scope}.${segs[0]!}`)) base = `${scope}.${segs[0]!}`;\n const dot = scope.lastIndexOf(\".\");\n scope = dot === -1 ? \"\" : scope.slice(0, dot);\n }\n if (base === undefined && ids.has(segs[0]!)) base = segs[0]!;\n if (base === undefined) {\n const leafed = byLeaf.get(segs[0]!);\n if (leafed !== undefined && leafed.length === 1) base = leafed[0]!;\n }\n return [base ?? segs[0]!, ...segs.slice(1)].join(\".\");\n };\n\n const rels: ScannedRel[] = raw.map((r) => ({\n source: resolve(r.srcLit, r.parent),\n target: resolve(r.tgtLit, r.parent),\n title: r.title,\n op: r.op,\n tags: r.tags,\n start: r.start,\n end: r.end,\n indent: r.indent,\n }));\n\n elements.sort((a, b) => a.start - b.start);\n return { open, close, elements, rels };\n}\n"]}
@@ -0,0 +1,66 @@
1
+ /** The ladder, in order. Each rung stands on every rung below it. */
2
+ export const MATURITY_LADDER = ["empty", "partial", "documented", "sourced", "vouched"];
3
+ /**
4
+ * How far a service's documentation has got. Derived from artifact PRESENCE and
5
+ * provenance state only — the data an enumeration already holds — never from
6
+ * what the artifacts say. COMPLETENESS of adopted docs is explicitly on the
7
+ * unchecked list (brief.ts): a service with one endpoint documented out of
8
+ * thirty climbs this ladder exactly as fast as a thorough one, which is why no
9
+ * rung is called "adopted".
10
+ *
11
+ * empty services/<id>/ exists, no artifact is in it
12
+ * partial some artifacts, but not the required set
13
+ * documented the artifacts the adopt brief marks required are present
14
+ * sourced the living spec declares `sources` — something ties it to code
15
+ * vouched status: verified with a sources_digest behind it — a person
16
+ * stamped it. `verified` with no digest is a claim with nothing
17
+ * behind it and stays below this rung.
18
+ *
19
+ * `openapi.yaml` is required ONLY where an API is expected. The rung used to
20
+ * demand it of everything, which permanently pinned every worker, cron and
21
+ * consumer in the fleet at `partial` — services that are fully documented and
22
+ * vouched for, reported as unfinished forever, and a rollup that therefore said
23
+ * a correctly-adopted fleet was half-done. The evidence is the same one
24
+ * `validate` uses to keep `service.no-openapi` quiet, so a service cannot be
25
+ * green in one command and unfinished in the other.
26
+ */
27
+ export function serviceMaturity(v) {
28
+ const s = v.entry;
29
+ if (!Object.values(s.has).some(Boolean) && !v.archSpec && s.adrs === 0)
30
+ return "empty";
31
+ if (!(s.has.model && s.has.spec && (!v.apiExpected || s.has.openapi)))
32
+ return "partial";
33
+ if (!s.sources.declared)
34
+ return "documented";
35
+ if (!(s.status === "verified" && s.sources.stamped))
36
+ return "sourced";
37
+ return "vouched";
38
+ }
39
+ /**
40
+ * What stands between this service and `vouched`, named as the thing to go and
41
+ * do. One rung's worth at a time: telling somebody at `empty` that they also
42
+ * need a vouch is noise, and the vouch is not even possible yet.
43
+ */
44
+ export function maturityGaps(v) {
45
+ const s = v.entry;
46
+ const files = [
47
+ ...(s.has.model ? [] : ["model.likec4"]),
48
+ ...(s.has.spec ? [] : ["spec.md"]),
49
+ ...(v.apiExpected && !s.has.openapi ? ["openapi.yaml"] : []),
50
+ ];
51
+ if (files.length > 0)
52
+ return files;
53
+ if (!s.sources.declared)
54
+ return ["sources: in the spec.md frontmatter"];
55
+ if (!(s.status === "verified" && s.sources.stamped))
56
+ return [`\`loam vouch --service ${s.id}\``];
57
+ return [];
58
+ }
59
+ /** Counts per rung, every rung present — a stable shape a fleet dashboard can diff. */
60
+ export function maturityRollup(graded) {
61
+ const out = Object.fromEntries(MATURITY_LADDER.map((m) => [m, 0]));
62
+ for (const v of graded)
63
+ out[v.maturity] += 1;
64
+ return out;
65
+ }
66
+ //# sourceMappingURL=maturity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maturity.js","sourceRoot":"","sources":["../../src/core/maturity.ts"],"names":[],"mappings":"AAeA,qEAAqE;AACrE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,CAAU,CAAC;AAoBjG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,eAAe,CAAC,CAAgB;IAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAClB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACvF,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACxF,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ;QAAE,OAAO,YAAY,CAAC;IAC7C,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,CAAgB;IAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAClB,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QACxC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAClC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7D,CAAC;IACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ;QAAE,OAAO,CAAC,qCAAqC,CAAC,CAAC;IACxE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACjG,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,cAAc,CAAC,MAAyC;IACtE,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAA6B,CAAC;IAC/F,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * The adoption-maturity ladder: one monotone word for how far a service's\n * documentation has got, and what stands between it and the next rung.\n *\n * This lived inside `commands/list.ts` while `list` was the only caller. It\n * moved here when `explore` needed the same answer, because the alternative is\n * the failure `core/ids.ts` already records for the service-id grammar: a\n * second, subtly different copy, so two commands grade the same directory\n * differently and nobody can tell which one is lying. The rung is a fleet dial\n * — `list` prints it per service and in a rollup, `explore` prints it for a\n * service somebody is about to build against — and a dial with two readings is\n * not a dial.\n */\nimport type { ServiceEntry } from \"./repo.js\";\n\n/** The ladder, in order. Each rung stands on every rung below it. */\nexport const MATURITY_LADDER = [\"empty\", \"partial\", \"documented\", \"sourced\", \"vouched\"] as const;\nexport type Maturity = (typeof MATURITY_LADDER)[number];\n\n/**\n * A service entry plus the two facts the directory enumeration cannot know on\n * its own. Both change what a rung MEANS, and both are fleet-level: they need\n * the landscape, not `services/<id>/`.\n */\nexport interface MaturityInput {\n entry: ServiceEntry;\n /** `arch.spec.md` — the architecture-obligations axis, absent from ServiceEntry.has. */\n archSpec: boolean;\n /**\n * Does anything in the fleet call an operation on this service? True unless\n * the landscape PROVES otherwise, exactly as `validate`'s no-openapi grace\n * reads it: a missing or unparseable landscape proves nothing.\n */\n apiExpected: boolean;\n}\n\n/**\n * How far a service's documentation has got. Derived from artifact PRESENCE and\n * provenance state only — the data an enumeration already holds — never from\n * what the artifacts say. COMPLETENESS of adopted docs is explicitly on the\n * unchecked list (brief.ts): a service with one endpoint documented out of\n * thirty climbs this ladder exactly as fast as a thorough one, which is why no\n * rung is called \"adopted\".\n *\n * empty services/<id>/ exists, no artifact is in it\n * partial some artifacts, but not the required set\n * documented the artifacts the adopt brief marks required are present\n * sourced the living spec declares `sources` — something ties it to code\n * vouched status: verified with a sources_digest behind it — a person\n * stamped it. `verified` with no digest is a claim with nothing\n * behind it and stays below this rung.\n *\n * `openapi.yaml` is required ONLY where an API is expected. The rung used to\n * demand it of everything, which permanently pinned every worker, cron and\n * consumer in the fleet at `partial` — services that are fully documented and\n * vouched for, reported as unfinished forever, and a rollup that therefore said\n * a correctly-adopted fleet was half-done. The evidence is the same one\n * `validate` uses to keep `service.no-openapi` quiet, so a service cannot be\n * green in one command and unfinished in the other.\n */\nexport function serviceMaturity(v: MaturityInput): Maturity {\n const s = v.entry;\n if (!Object.values(s.has).some(Boolean) && !v.archSpec && s.adrs === 0) return \"empty\";\n if (!(s.has.model && s.has.spec && (!v.apiExpected || s.has.openapi))) return \"partial\";\n if (!s.sources.declared) return \"documented\";\n if (!(s.status === \"verified\" && s.sources.stamped)) return \"sourced\";\n return \"vouched\";\n}\n\n/**\n * What stands between this service and `vouched`, named as the thing to go and\n * do. One rung's worth at a time: telling somebody at `empty` that they also\n * need a vouch is noise, and the vouch is not even possible yet.\n */\nexport function maturityGaps(v: MaturityInput): string[] {\n const s = v.entry;\n const files = [\n ...(s.has.model ? [] : [\"model.likec4\"]),\n ...(s.has.spec ? [] : [\"spec.md\"]),\n ...(v.apiExpected && !s.has.openapi ? [\"openapi.yaml\"] : []),\n ];\n if (files.length > 0) return files;\n if (!s.sources.declared) return [\"sources: in the spec.md frontmatter\"];\n if (!(s.status === \"verified\" && s.sources.stamped)) return [`\\`loam vouch --service ${s.id}\\``];\n return [];\n}\n\n/** Counts per rung, every rung present — a stable shape a fleet dashboard can diff. */\nexport function maturityRollup(graded: readonly { maturity: Maturity }[]): Record<Maturity, number> {\n const out = Object.fromEntries(MATURITY_LADDER.map((m) => [m, 0])) as Record<Maturity, number>;\n for (const v of graded) out[v.maturity] += 1;\n return out;\n}\n"]}
@@ -1,6 +1,9 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
2
  import { isMap, parseDocument } from "yaml";
3
3
  import { HTTP_METHODS, OPENAPI_BASELINE_KEY, classifyBaselineDigests, operationBaselineOf, operationDigest, withoutOperationBaseline, } from "./openapi.js";
4
+ // Every `isRecord` below asks one question of a resolved plain tree: is this a
5
+ // node that can hold OpenAPI keys — an object, not an array?
6
+ import { isRecord } from "./records.js";
4
7
  /**
5
8
  * Classify one feature operation against its living counterpart, from the raw
6
9
  * YAML trees the merge works in. The rule itself lives in core/openapi.ts, so
@@ -160,7 +163,30 @@ export function stripOpenapiRemovalMarkers(featureText, service) {
160
163
  // deleting a key through it would change every use), so those documents get
161
164
  // their `paths` rewritten from the resolved tree instead: losing formatting
162
165
  // is a cost, shipping the marker is a corruption.
163
- const editable = isMap(feature.get("paths")) && Object.keys(paths).every((p) => isMap(feature.getIn(["paths", p])));
166
+ //
167
+ // The test has to reach the OPERATION nodes too, not just the path items. The
168
+ // in-place branch strips a surviving operation's pin through
169
+ // `["paths", p, m, x-loam-based-on]`, and an aliased operation is exactly one
170
+ // level below where the check used to look — so `deleteIn` walked into a node
171
+ // that is not a collection and threw out of archive as `internal`, on a
172
+ // document whose only fault was writing one operation twice.
173
+ //
174
+ // What disqualifies a method is "there is something here to strip and I cannot
175
+ // reach it", not "this is not a map node". Only a resolved MAPPING can be a
176
+ // removal marker or carry a pin, so a method spelled as a scalar — `get: ~`,
177
+ // or a string — is nothing the in-place branch would have touched; demanding a
178
+ // map node of it too demoted whole documents to the rewrite branch and cost
179
+ // their author every comment, anchor and hand-chosen key order inside `paths`,
180
+ // in the bytes archive installs as the living contract. What is left is the
181
+ // real hazard: a mapping the AST does not hand back as a map. An alias is the
182
+ // one node kind that resolves to a mapping without being one, and a method
183
+ // whose KEY is an alias is not findable by name at all, so `deleteIn` reports
184
+ // nothing deleted and the marker ships in silence. Both answer `undefined` or
185
+ // a non-map here, and both belong on the safe branch.
186
+ const editable = isMap(feature.get("paths")) &&
187
+ Object.entries(paths).every(([p, item]) => isMap(feature.getIn(["paths", p])) &&
188
+ (!isRecord(item) ||
189
+ Object.entries(item).every(([m, op]) => !HTTP_METHODS.has(m) || !isRecord(op) || isMap(feature.getIn(["paths", p, m])))));
164
190
  if (!editable) {
165
191
  feature.setIn(["paths"], cleaned);
166
192
  }
@@ -326,6 +352,17 @@ export function mergeOpenapiPaths(livingText, featureText, service) {
326
352
  else
327
353
  pathItemModified.push(`'${m}' (${path})`);
328
354
  }
355
+ // Every shape question above was answered from the RESOLVED tree, which
356
+ // is exactly what makes an aliased path item read as an ordinary
357
+ // mapping. The WRITE cannot be that forgiving: `setIn` walks the AST,
358
+ // and one shared value backs every use of an anchor, so an operation
359
+ // merged through the alias would land in every other path that
360
+ // references it. There is no way to write into one use of an anchor and
361
+ // not the rest, so this is a refusal rather than a fallback — and it is
362
+ // asked here, at the write, because reading is safe and writing is not.
363
+ if (!isMap(living.getIn(["paths", path]))) {
364
+ throw new OpenapiMergeError("living", service, `path '${path}' is written as a YAML alias — one shared value backs every use, so merging into it would rewrite every other path that aliases it. Expand it before archiving.`);
365
+ }
329
366
  // Without the strip the living contract would grow a pin to a version
330
367
  // of itself, and the NEXT feature's baseline would hash it.
331
368
  living.setIn(["paths", path, m], publishable[m]);
@@ -414,10 +451,6 @@ function noop() {
414
451
  unresolved: [],
415
452
  };
416
453
  }
417
- /** A resolved plain tree that can hold OpenAPI keys — an object, not an array. */
418
- function isRecord(node) {
419
- return node !== null && typeof node === "object" && !Array.isArray(node);
420
- }
421
454
  /** Every `$ref` string value anywhere in a plain JS tree, in document order. */
422
455
  export function collectRefs(node) {
423
456
  const out = [];
@@ -461,7 +494,7 @@ export function resolvePointer(root, ref) {
461
494
  return { found: true, value: current };
462
495
  }
463
496
  /** Name an overwritten operation by its operationId (feature's, else living's), or path+method. */
464
- export function opLabel(before, after, method, path) {
497
+ function opLabel(before, after, method, path) {
465
498
  const operation = operationIdOf(after) ?? operationIdOf(before);
466
499
  return operation !== undefined ? `'${operation}' (${method} ${path})` : `${method} ${path}`;
467
500
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-merge.js","sourceRoot":"","sources":["../../src/core/openapi-merge.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { isMap, parseDocument } from \"yaml\";\nimport {\n HTTP_METHODS,\n OPENAPI_BASELINE_KEY,\n classifyBaselineDigests,\n operationBaselineOf,\n operationDigest,\n withoutOperationBaseline,\n} from \"./openapi.js\";\n\n/**\n * What a feature's operation IS, relative to the living contract — the one\n * judgement that tells a QUOTE from an EDIT.\n *\n * A feature's openapi.yaml is a complete document, so most of what it spells is\n * quotation: the author restated the living contract around the slot they were\n * changing. Without a pin the merge cannot tell the two apart and upserts both,\n * which is how a feature that only meant to touch `cancelOrder` silently\n * reverted another team's landed change to `refundOrder` — no overlap between\n * the features required, just two deltas over one service.\n */\nexport type OperationBaselineVerdict = ReturnType<typeof classifyBaselineDigests>;\n\n/**\n * Classify one feature operation against its living counterpart, from the raw\n * YAML trees the merge works in. The rule itself lives in core/openapi.ts, so\n * the gate and the merge cannot drift apart about which operations get written.\n *\n * A malformed pin matches no digest and lands in `stale`, which merges rather\n * than skips. Deliberate: `openapi.baseline-invalid` refuses it at the gate, and\n * a value nobody can evaluate must never be the reason a merge quietly drops an\n * operation.\n */\nexport function classifyOperationBaseline(featureOp: unknown, livingOp: unknown): OperationBaselineVerdict {\n return classifyBaselineDigests(\n operationBaselineOf(featureOp),\n operationDigest(featureOp),\n livingOp === undefined ? undefined : operationDigest(livingOp),\n );\n}\n\n/** What happened to one operation's `x-loam-based-on`. */\nexport interface OperationPin {\n path: string;\n method: string;\n /** Empty when the operation declares none — the slot is still the identity. */\n operationId: string;\n status:\n /** It had no pin and now has one. */\n | \"pinned\"\n /** It named an older living version; it now names the current one. */\n | \"repinned\"\n /** It already named the current living version — no write. */\n | \"unchanged\"\n /** The living contract has no operation at this slot: this feature is adding it. */\n | \"unresolved\"\n /** Written as a YAML alias — one shared value backs every use, so loam will not stamp through it. */\n | \"unwritable\";\n from: string | null;\n to: string | null;\n}\n\nexport interface OpenapiPinPlan {\n /** The rewritten contract, or null when no pin changes. */\n text: string | null;\n pins: OperationPin[];\n}\n\n/**\n * Pin every operation in a feature contract against the living one — what\n * `loam rebase` writes on this axis.\n *\n * The pin is always `operationDigest` of the LIVING operation, never of the\n * delta's own, and that single rule produces both merge verdicts by itself: an\n * operation the author only QUOTED is byte-equal to living, so its pin equals\n * its own content and `classifyOperationBaseline` calls it a quote; one the\n * author EDITED differs from its pin, so the merge writes it. Nothing has to\n * guess at intent — the document already records it, and the pin makes it\n * legible to the merge.\n *\n * Slot-keyed (path + method), exactly as the merge upserts. An operationId that\n * moved to another slot is a new slot with nothing living behind it, which is\n * `unresolved` and correct: there is no living version of an operation at a\n * path the contract does not serve yet.\n */\nexport function pinOpenapiOperations(featureText: string, livingText: string, service: string): OpenapiPinPlan {\n const doc = parseDocument(featureText);\n if (doc.errors.length > 0) throw new OpenapiMergeError(\"feature\", service, doc.errors[0]!.message);\n let featPlain: unknown;\n let livingPlain: unknown;\n try {\n featPlain = doc.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n try {\n const parsed = parseDocument(livingText);\n if (parsed.errors.length > 0) throw new OpenapiMergeError(\"living\", service, parsed.errors[0]!.message);\n livingPlain = parsed.toJS() ?? {};\n } catch (error) {\n if (error instanceof OpenapiMergeError) throw error;\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n\n const featPaths = plainChild(featPlain, \"paths\");\n if (!isRecord(featPaths)) return { text: null, pins: [] };\n const livingPaths = plainChild(livingPlain, \"paths\");\n\n const pins: OperationPin[] = [];\n let edited = false;\n for (const [path, item] of Object.entries(featPaths)) {\n if (!isRecord(item)) continue;\n for (const [method, op] of Object.entries(item)) {\n if (!HTTP_METHODS.has(method) || !isRecord(op)) continue;\n // A removal marker asserts a slot rather than restating an operation, so\n // it has nothing to be based on; `openapi.remove-target-mismatch` is what\n // guards it against a living slot that moved under it.\n if (isRemoval(op)) continue;\n\n const id = typeof op[\"operationId\"] === \"string\" ? op[\"operationId\"] : \"\";\n const at = { path, method, operationId: id };\n const from = operationBaselineOf(op) ?? null;\n const livingItem = plainChild(livingPaths, path);\n const livingOp = isRecord(livingItem) ? livingItem[method] : undefined;\n if (!isRecord(livingOp)) {\n pins.push({ ...at, status: \"unresolved\", from, to: null });\n continue;\n }\n const digest = operationDigest(livingOp);\n if (from === digest) {\n pins.push({ ...at, status: \"unchanged\", from: digest, to: digest });\n continue;\n }\n // One shared value backs every use of an anchor, so `setIn` through an\n // alias would pin every other use of it too — the same reason\n // stripOpenapiRemovalMarkers refuses to edit aliases in place.\n if (!isMap(doc.getIn([\"paths\", path, method]))) {\n pins.push({ ...at, status: \"unwritable\", from, to: null });\n continue;\n }\n pins.push({ ...at, status: from === null ? \"pinned\" : \"repinned\", from, to: digest });\n doc.setIn([\"paths\", path, method, OPENAPI_BASELINE_KEY], digest);\n edited = true;\n }\n }\n\n if (!edited) return { text: null, pins };\n try {\n return { text: doc.toString(), pins };\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n\n/** What an OpenAPI path merge computed, including every condition the caller must surface. */\nexport interface OpenapiMergeResult {\n /** The merged living document, or null when the feature document has no paths to merge. */\n text: string | null;\n /** Labels of existing operations overwritten with different content. */\n modified: string[];\n /**\n * Labels of PATH-LEVEL keys (`parameters`, `servers`, `summary`, `x-*`)\n * overwritten with different content. They are not operations, so they were\n * excluded from the difference check entirely and overwritten in silence —\n * a delta restating a path with a shorter `parameters` list dropped shared\n * parameters from every operation under it, and the plan said nothing.\n */\n pathItemModified: string[];\n /** Labels of living operations deleted by `x-loam-remove: true` markers. */\n removed: string[];\n /**\n * Labels of operations the delta QUOTED — pinned, and equal to their own\n * baseline — so the merge left the living contract's own copy alone. Reported\n * rather than silent: \"your delta mentions this and I did not write it\" is\n * exactly the sentence whose absence made the revert invisible.\n */\n quoted: string[];\n /**\n * Labels of operations whose pin matches neither the delta's own content nor\n * the living one: edited here AND changed by somebody else in between.\n * `openapi.baseline-stale` refuses these at the gate; the merge still\n * overwrites, because reaching it at all means `--approve` said to.\n */\n baselineStale: string[];\n /** `<kind>/<name>` of living components overwritten with different content. */\n componentsModified: string[];\n /** Local refs reachable from merged content that resolve in neither document. */\n unresolved: Array<{ ref: string; from: string }>;\n}\n\nexport type OpenapiMergeSource = \"feature\" | \"living\";\n\n/** A document the merge planner cannot read. Commands map this domain error to their own envelope. */\nexport class OpenapiMergeError extends Error {\n override readonly name = \"OpenapiMergeError\";\n\n constructor(\n readonly source: OpenapiMergeSource,\n readonly service: string,\n detail: string,\n ) {\n super(`${source} openapi for ${service} is not valid YAML: ${detail}`);\n }\n}\n\n/**\n * Remove feature-only operation-removal markers before a feature contract is\n * used to create a brand-new living document. Normally coherence refuses this\n * shape because there cannot be a removal target; this guard also keeps\n * `--approve` from ever persisting the marker into living docs.\n */\nexport function stripOpenapiRemovalMarkers(featureText: string, service: string): string {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new OpenapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n let plain: unknown;\n try {\n plain = feature.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n // Shape from the RESOLVED tree, for the same reason the merge reads it there:\n // an aliased `paths` or path item is not a map node, and treating it as\n // \"nothing to strip\" is how a feature-only marker reached a living contract.\n const paths = plainChild(plain, \"paths\");\n if (!isRecord(paths)) return featureText;\n\n const cleaned: Record<string, unknown> = {};\n let stripped = false;\n for (const [path, item] of Object.entries(paths)) {\n const kept = withoutFeatureMarkers(item);\n if (!isDeepStrictEqual(kept, item)) stripped = true;\n // A path the strip emptied goes with its last operation: `\\/x: {}` is a\n // path the contract advertises and nothing answers.\n if (kept !== undefined) cleaned[path] = kept;\n }\n if (!stripped) return featureText;\n\n // Edit the AST in place when every node the strip touches IS a node — the\n // author's comments, key order and formatting are theirs to keep. An alias\n // cannot be edited in place (there is one shared value behind it, and\n // deleting a key through it would change every use), so those documents get\n // their `paths` rewritten from the resolved tree instead: losing formatting\n // is a cost, shipping the marker is a corruption.\n const editable =\n isMap(feature.get(\"paths\")) && Object.keys(paths).every((p) => isMap(feature.getIn([\"paths\", p])));\n if (!editable) {\n feature.setIn([\"paths\"], cleaned);\n } else {\n for (const [path, item] of Object.entries(paths)) {\n if (!isRecord(item)) continue;\n for (const [m, value] of Object.entries(item)) {\n // A loam marker at PATH level, deleted here for the same reason the\n // resolved-tree branch drops it: the two branches must agree exactly\n // about what a living contract may carry.\n if (FEATURE_ONLY_KEYS.has(m)) feature.deleteIn([\"paths\", path, m]);\n if (!HTTP_METHODS.has(m)) continue;\n if (isRemoval(value)) feature.deleteIn([\"paths\", path, m]);\n // The surviving operations keep their formatting but lose their pin:\n // the in-place branch must strip everything the resolved-tree branch\n // does, or the two disagree about what a living contract may carry.\n else if (operationBaselineOf(value) !== undefined) {\n feature.deleteIn([\"paths\", path, m, OPENAPI_BASELINE_KEY]);\n }\n }\n const remaining = feature.getIn([\"paths\", path]);\n if (isMap(remaining) && remaining.items.length === 0) feature.deleteIn([\"paths\", path]);\n }\n }\n try {\n return feature.toString();\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n\n/**\n * Merge the feature's `paths` into the living OpenAPI structurally (YAML AST, not\n * text splicing). A feature document without paths is a successful no-op.\n * The merged operations' local component-ref closure rides along recursively;\n * external refs are left untouched and never gated.\n *\n * Every SHAPE question — is there a `paths` mapping, is this path item a\n * mapping, which methods does it hold — is answered from the RESOLVED plain\n * trees, never from the AST node. Asking the AST (`isMap(node)`) answers a\n * different question: an alias node is not a map even when it resolves to one.\n * `paths: *alias` therefore read as \"no paths to merge\" and the whole contract\n * delta was dropped with a successful exit, and an aliased path ITEM fell into\n * the wholesale-replace branch and deleted every living operation on that path\n * that the alias did not restate. Aliases are legal OpenAPI and the natural way\n * to write a delta that repeats a shape; nothing here may treat them as absent.\n * An alias that cannot be resolved at all is a document loam cannot read, and\n * says so — it is never \"nothing to merge\".\n */\nexport function mergeOpenapiPaths(\n livingText: string,\n featureText: string,\n service: string,\n): OpenapiMergeResult {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new OpenapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n let featPlain: unknown;\n try {\n // Resolve aliases once with the document's own anchor context. Calling an\n // individual AST node's toJSON() loses that context and can silently turn\n // an aliased operation or component into the wrong value.\n featPlain = feature.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n const featPathsPlain = plainChild(featPlain, \"paths\");\n if (featPathsPlain === undefined || featPathsPlain === null) {\n return noop();\n }\n if (!isRecord(featPathsPlain)) {\n throw new OpenapiMergeError(\"feature\", service, \"`paths` is not a mapping\");\n }\n const featPathEntries = Object.entries(featPathsPlain);\n if (featPathEntries.length === 0) return noop();\n\n const living = parseDocument(livingText);\n if (living.errors.length > 0) {\n throw new OpenapiMergeError(\"living\", service, living.errors[0]!.message);\n }\n let livingPlain: unknown;\n try {\n livingPlain = living.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n const livingPathsPlain = plainChild(livingPlain, \"paths\");\n if (livingPathsPlain !== undefined && livingPathsPlain !== null && !isRecord(livingPathsPlain)) {\n throw new OpenapiMergeError(\"living\", service, \"`paths` is not a mapping\");\n }\n const modified: string[] = [];\n const pathItemModified: string[] = [];\n const removed: string[] = [];\n const quoted: string[] = [];\n const baselineStale: string[] = [];\n for (const [path, featItemPlain] of featPathEntries) {\n const existing = living.getIn([\"paths\", path]);\n const existingPlain = plainChild(livingPathsPlain, path);\n if (existing !== undefined && !isRecord(existingPlain)) {\n // The living contract holds this path as something other than a path\n // item. Replacing it wholesale is the one branch that may delete living\n // operations without naming them, so it is reserved for paths the living\n // contract does not have at all.\n throw new OpenapiMergeError(\"living\", service, `path '${path}' is not a mapping`);\n }\n if (existing !== undefined) {\n if (!isRecord(featItemPlain)) {\n throw new OpenapiMergeError(\"feature\", service, `path '${path}' is not a mapping`);\n }\n // EVERY branch publishes through withoutFeatureMarkers. This one used to\n // copy every key of the feature path item and guard only the HTTP\n // methods, so a path-level `x-loam-remove` landed in the living contract\n // with `modified: []` and no warning. A key the strip drops is never\n // written; the removal handling below still reads the RAW item, because\n // that is where the markers it acts on live.\n const publish = withoutFeatureMarkers(featItemPlain);\n const publishable = isRecord(publish) ? publish : {};\n for (const [m, afterPlain] of Object.entries(featItemPlain)) {\n const before = living.getIn([\"paths\", path, m]);\n const beforePlain = plainChild(existingPlain, m);\n if (HTTP_METHODS.has(m) && isRemoval(afterPlain)) {\n // Coherence validates the marker and gates absent/mismatched targets.\n // The merge remains defensive under --approve: never delete a\n // different operation merely because it occupies the requested slot.\n if (\n before !== undefined &&\n operationIdOf(beforePlain) !== undefined &&\n operationIdOf(beforePlain) === operationIdOf(afterPlain)\n ) {\n removed.push(opLabel(beforePlain, afterPlain, m, path));\n living.deleteIn([\"paths\", path, m]);\n }\n continue;\n }\n if (HTTP_METHODS.has(m)) {\n const verdict = classifyOperationBaseline(afterPlain, before === undefined ? undefined : beforePlain);\n // A QUOTE is not a merge input. The author wrote this operation down\n // because the document is complete, not because they changed it, so\n // the living contract keeps whatever it holds — including a change\n // that landed after this delta was written. This is mechanical, not a\n // judgement, so `--approve` does not turn it back on: overriding a\n // gate is a decision, reverting an operation nobody edited is a bug.\n if (verdict === \"quote\") {\n quoted.push(opLabel(beforePlain, afterPlain, m, path));\n continue;\n }\n if (verdict === \"stale\") baselineStale.push(opLabel(beforePlain, afterPlain, m, path));\n }\n if (!(m in publishable)) {\n // A feature-only marker at path level. It is never published, and\n // never reported as a path-item overwrite either — it is not a key of\n // the contract at all. The archive gate names it to the author.\n continue;\n }\n // The difference check covers EVERY key of the path item; only the\n // LABEL depends on whether the key is an HTTP method.\n if (before !== undefined && !isDeepStrictEqual(beforePlain, afterPlain)) {\n if (HTTP_METHODS.has(m)) modified.push(opLabel(beforePlain, afterPlain, m, path));\n else pathItemModified.push(`'${m}' (${path})`);\n }\n // Without the strip the living contract would grow a pin to a version\n // of itself, and the NEXT feature's baseline would hash it.\n living.setIn([\"paths\", path, m], publishable[m]);\n }\n // Removing the last method leaves `\\/x: {}` — a path the contract still\n // advertises and nothing answers. The same cleanup\n // stripOpenapiRemovalMarkers already does on the feature side.\n const remaining = living.getIn([\"paths\", path]);\n if (isMap(remaining) && remaining.items.length === 0) living.deleteIn([\"paths\", path]);\n continue;\n }\n if (!isRecord(featItemPlain)) {\n throw new OpenapiMergeError(\"feature\", service, `path '${path}' is not a mapping`);\n }\n const clean = withoutFeatureMarkers(featItemPlain);\n if (clean !== undefined) living.setIn([\"paths\", path], clean);\n }\n\n const componentsModified: string[] = [];\n const unresolved: OpenapiMergeResult[\"unresolved\"] = [];\n const visited = new Set<string>();\n const copies: Array<{ kind: string; name: string; value: unknown }> = [];\n\n const visitRef = (ref: string, from: string): void => {\n if (!ref.startsWith(\"#/\")) return;\n const match = /^#\\/components\\/([^/]+)\\/([^/]+)(?:\\/|$)/.exec(ref);\n if (!match) {\n if (!resolvePointer(featPlain, ref).found && !resolvePointer(livingPlain, ref).found) {\n unresolved.push({ ref, from });\n }\n return;\n }\n const kind = match[1]!;\n const name = match[2]!;\n const key = `${kind}/${name}`;\n if (visited.has(key)) return;\n visited.add(key);\n const inFeature = resolvePointer(featPlain, `#/components/${kind}/${name}`);\n if (inFeature.found) {\n copies.push({ kind, name, value: inFeature.value });\n walk(inFeature.value, `components/${key}`);\n return;\n }\n if (!resolvePointer(livingPlain, `#/components/${kind}/${name}`).found) {\n unresolved.push({ ref, from });\n }\n };\n\n const walk = (node: unknown, from: string): void => {\n for (const ref of collectRefs(node)) visitRef(ref, from);\n };\n\n for (const [path, featItemPlain] of featPathEntries) {\n walk(withoutFeatureMarkers(featItemPlain), `paths ${path}`);\n }\n\n for (const { kind, name, value } of copies) {\n const existing = living.getIn([\"components\", kind, name]);\n if (existing !== undefined) {\n const existingPlain = resolvePointer(livingPlain, `#/components/${kind}/${name}`);\n if (existingPlain.found && isDeepStrictEqual(existingPlain.value, value)) continue;\n componentsModified.push(`${kind}/${name}`);\n }\n living.setIn([\"components\", kind, name], value);\n }\n\n let text: string;\n try {\n text = living.toString();\n } catch (error) {\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n return { text, modified, pathItemModified, removed, quoted, baselineStale, componentsModified, unresolved };\n}\n\n/** The successful \"the feature document has nothing to merge\" answer. */\nfunction noop(): OpenapiMergeResult {\n return {\n text: null,\n modified: [],\n pathItemModified: [],\n removed: [],\n quoted: [],\n baselineStale: [],\n componentsModified: [],\n unresolved: [],\n };\n}\n\n/** A resolved plain tree that can hold OpenAPI keys — an object, not an array. */\nfunction isRecord(node: unknown): node is Record<string, unknown> {\n return node !== null && typeof node === \"object\" && !Array.isArray(node);\n}\n\n/** Every `$ref` string value anywhere in a plain JS tree, in document order. */\nexport function collectRefs(node: unknown): string[] {\n const out: string[] = [];\n const walk = (current: unknown): void => {\n if (Array.isArray(current)) {\n for (const value of current) walk(value);\n return;\n }\n if (current !== null && typeof current === \"object\") {\n for (const [key, value] of Object.entries(current)) {\n if (key === \"$ref\" && typeof value === \"string\") out.push(value);\n else walk(value);\n }\n }\n };\n walk(node);\n return out;\n}\n\n/** Resolve a local JSON pointer (`#/a/b~1c`) against a plain JS tree. */\nexport function resolvePointer(root: unknown, ref: string): { found: boolean; value: unknown } {\n let current: unknown = root;\n for (const raw of ref.slice(2).split(\"/\")) {\n const segment = raw.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n if (Array.isArray(current)) {\n const index = Number(segment);\n if (!Number.isInteger(index) || index < 0 || index >= current.length) {\n return { found: false, value: undefined };\n }\n current = current[index];\n } else if (current !== null && typeof current === \"object\" && segment in (current as Record<string, unknown>)) {\n current = (current as Record<string, unknown>)[segment];\n } else {\n return { found: false, value: undefined };\n }\n }\n return { found: true, value: current };\n}\n\n/** Name an overwritten operation by its operationId (feature's, else living's), or path+method. */\nexport function opLabel(before: unknown, after: unknown, method: string, path: string): string {\n const operation = operationIdOf(after) ?? operationIdOf(before);\n return operation !== undefined ? `'${operation}' (${method} ${path})` : `${method} ${path}`;\n}\n\n/** Is this operation node a feature-only explicit removal marker? */\nfunction isRemoval(node: unknown): boolean {\n return node !== null &&\n typeof node === \"object\" &&\n (node as Record<string, unknown>)[\"x-loam-remove\"] === true;\n}\n\n/** Read an operationId from a YAML or plain operation node. */\nfunction operationIdOf(node: unknown): string | undefined {\n const value = isMap(node)\n ? node.get(\"operationId\")\n : node !== null && typeof node === \"object\"\n ? (node as Record<string, unknown>)[\"operationId\"]\n : undefined;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/**\n * Every key that is an instruction to loam rather than part of the contract.\n * At PATH level neither has any meaning — `x-loam-remove` addresses one\n * operation and `x-loam-based-on` pins one — so a path item carrying either is\n * an authoring mistake, and one that must not be published whatever else is\n * done about it.\n */\nconst FEATURE_ONLY_KEYS = new Set([\"x-loam-remove\", OPENAPI_BASELINE_KEY]);\n\n/**\n * Copy a path item without anything that belongs to the FEATURE rather than to\n * the contract: removal-marker operations, the `x-loam-based-on` pins on the\n * operations that survive, and a loam marker written at PATH level. All three\n * are instructions to loam, and a living contract that carries any of them is\n * lying to the next reader — and, for the pin, to the next feature's baseline.\n *\n * The path-level case used to fall through: the filter guarded only HTTP\n * methods, so `x-loam-remove: true` beside the methods was copied verbatim into\n * the fleet's living contract, where it also kept the empty-path cleanup from\n * ever seeing an empty path.\n */\nfunction withoutFeatureMarkers(node: unknown): unknown {\n if (node === null || typeof node !== \"object\" || Array.isArray(node)) return node;\n const entries = Object.entries(node as Record<string, unknown>)\n .filter(([key, value]) => !FEATURE_ONLY_KEYS.has(key) && !(HTTP_METHODS.has(key) && isRemoval(value)))\n .map(([key, value]) => [key, HTTP_METHODS.has(key) ? withoutOperationBaseline(value) : value] as const);\n return entries.length === 0 ? undefined : Object.fromEntries(entries);\n}\n\nfunction plainChild(parent: unknown, key: string): unknown {\n return parent !== null && typeof parent === \"object\"\n ? (parent as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
1
+ {"version":3,"file":"openapi-merge.js","sourceRoot":"","sources":["../../src/core/openapi-merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,+EAA+E;AAC/E,6DAA6D;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAexC;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAAkB,EAAE,QAAiB;IAC7E,OAAO,uBAAuB,CAC5B,mBAAmB,CAAC,SAAS,CAAC,EAC9B,eAAe,CAAC,SAAS,CAAC,EAC1B,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAC/D,CAAC;AACJ,CAAC;AA6BD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB,EAAE,UAAkB,EAAE,OAAe;IAC3F,MAAM,GAAG,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;IACnG,IAAI,SAAkB,CAAC;IACvB,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;QACxG,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,iBAAiB;YAAE,MAAM,KAAK,CAAC;QACpD,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC1D,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAErD,MAAM,IAAI,GAAmB,EAAE,CAAC;IAChC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAAE,SAAS;YACzD,yEAAyE;YACzE,0EAA0E;YAC1E,uDAAuD;YACvD,IAAI,SAAS,CAAC,EAAE,CAAC;gBAAE,SAAS;YAE5B,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,mBAAmB,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;YAC7C,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3D,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;gBACpE,SAAS;YACX,CAAC;YACD,uEAAuE;YACvE,8DAA8D;YAC9D,+DAA+D;YAC/D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3D,SAAS;YACX,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACtF,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAC;YACjE,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAwCD,sGAAsG;AACtG,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAI/B,MAAM;IACN,OAAO;IAJA,IAAI,GAAG,mBAAmB,CAAC;IAE7C,YACW,MAA0B,EAC1B,OAAe,EACxB,MAAc;QAEd,KAAK,CAAC,GAAG,MAAM,gBAAgB,OAAO,uBAAuB,MAAM,EAAE,CAAC,CAAC;sBAJ9D,MAAM;uBACN,OAAO;IAIlB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAmB,EAAE,OAAe;IAC7E,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,8EAA8E;IAC9E,wEAAwE;IACxE,6EAA6E;IAC7E,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAEzC,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC;YAAE,QAAQ,GAAG,IAAI,CAAC;QACpD,wEAAwE;QACxE,oDAAoD;QACpD,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,QAAQ;QAAE,OAAO,WAAW,CAAC;IAElC,0EAA0E;IAC1E,2EAA2E;IAC3E,sEAAsE;IACtE,4EAA4E;IAC5E,4EAA4E;IAC5E,kDAAkD;IAClD,EAAE;IACF,8EAA8E;IAC9E,6DAA6D;IAC7D,8EAA8E;IAC9E,8EAA8E;IAC9E,wEAAwE;IACxE,6DAA6D;IAC7D,EAAE;IACF,+EAA+E;IAC/E,4EAA4E;IAC5E,6EAA6E;IAC7E,+EAA+E;IAC/E,4EAA4E;IAC5E,+EAA+E;IAC/E,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,8EAA8E;IAC9E,8EAA8E;IAC9E,sDAAsD;IACtD,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CACzB,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CACZ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YAClC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACd,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CACxB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAC5F,CAAC,CACP,CAAC;IACJ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9C,oEAAoE;gBACpE,qEAAqE;gBACrE,0CAA0C;gBAC1C,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACnE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,SAAS;gBACnC,IAAI,SAAS,CAAC,KAAK,CAAC;oBAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC3D,qEAAqE;gBACrE,qEAAqE;gBACrE,oEAAoE;qBAC/D,IAAI,mBAAmB,CAAC,KAAK,CAAC,KAAK,SAAS,EAAE,CAAC;oBAClD,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;YACD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACjD,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,WAAmB,EACnB,OAAe;IAEf,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,SAAkB,CAAC;IACvB,IAAI,CAAC;QACH,0EAA0E;QAC1E,0EAA0E;QAC1E,0DAA0D;QAC1D,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;QAC5D,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACvD,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IAEhD,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,gBAAgB,GAAG,UAAU,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC1D,IAAI,gBAAgB,KAAK,SAAS,IAAI,gBAAgB,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC/F,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,0BAA0B,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,eAAe,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/C,MAAM,aAAa,GAAG,UAAU,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;QACzD,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACvD,qEAAqE;YACrE,wEAAwE;YACxE,yEAAyE;YACzE,iCAAiC;YACjC,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,IAAI,oBAAoB,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,oBAAoB,CAAC,CAAC;YACrF,CAAC;YACD,yEAAyE;YACzE,kEAAkE;YAClE,yEAAyE;YACzE,qEAAqE;YACrE,wEAAwE;YACxE,6CAA6C;YAC7C,MAAM,OAAO,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;YACrD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAChD,MAAM,WAAW,GAAG,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;gBACjD,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;oBACjD,sEAAsE;oBACtE,8DAA8D;oBAC9D,qEAAqE;oBACrE,IACE,MAAM,KAAK,SAAS;wBACpB,aAAa,CAAC,WAAW,CAAC,KAAK,SAAS;wBACxC,aAAa,CAAC,WAAW,CAAC,KAAK,aAAa,CAAC,UAAU,CAAC,EACxD,CAAC;wBACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;wBACxD,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;oBACtC,CAAC;oBACD,SAAS;gBACX,CAAC;gBACD,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBACxB,MAAM,OAAO,GAAG,yBAAyB,CAAC,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;oBACtG,qEAAqE;oBACrE,oEAAoE;oBACpE,mEAAmE;oBACnE,sEAAsE;oBACtE,mEAAmE;oBACnE,qEAAqE;oBACrE,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;wBACxB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;wBACvD,SAAS;oBACX,CAAC;oBACD,IAAI,OAAO,KAAK,OAAO;wBAAE,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;gBACzF,CAAC;gBACD,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,EAAE,CAAC;oBACxB,kEAAkE;oBAClE,sEAAsE;oBACtE,gEAAgE;oBAChE,SAAS;gBACX,CAAC;gBACD,mEAAmE;gBACnE,sDAAsD;gBACtD,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC;oBACxE,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;wBAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;;wBAC7E,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;gBACjD,CAAC;gBACD,wEAAwE;gBACxE,iEAAiE;gBACjE,sEAAsE;gBACtE,qEAAqE;gBACrE,+DAA+D;gBAC/D,wEAAwE;gBACxE,wEAAwE;gBACxE,wEAAwE;gBACxE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1C,MAAM,IAAI,iBAAiB,CACzB,QAAQ,EACR,OAAO,EACP,SAAS,IAAI,iKAAiK,CAC/K,CAAC;gBACJ,CAAC;gBACD,sEAAsE;gBACtE,4DAA4D;gBAC5D,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,CAAC;YACD,wEAAwE;YACxE,mDAAmD;YACnD,+DAA+D;YAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YAChD,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACvF,SAAS;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,oBAAoB,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;QACnD,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,MAAM,UAAU,GAAqC,EAAE,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,MAAM,GAA0D,EAAE,CAAC;IAEzE,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,IAAY,EAAQ,EAAE;QACnD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO;QAClC,MAAM,KAAK,GAAG,0CAA0C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;gBACrF,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,EAAE,gBAAgB,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAC5E,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,EAAE,CAAC,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,gBAAgB,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YACvE,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,IAAY,EAAQ,EAAE;QACjD,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,eAAe,EAAE,CAAC;QACpD,IAAI,CAAC,qBAAqB,CAAC,aAAa,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,aAAa,GAAG,cAAc,CAAC,WAAW,EAAE,gBAAgB,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;YAClF,IAAI,aAAa,CAAC,KAAK,IAAI,iBAAiB,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC;gBAAE,SAAS;YACnF,kBAAkB,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,kBAAkB,EAAE,UAAU,EAAE,CAAC;AAC9G,CAAC;AAED,yEAAyE;AACzE,SAAS,IAAI;IACX,OAAO;QACL,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,EAAE;QACZ,gBAAgB,EAAE,EAAE;QACpB,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,EAAE;QACV,aAAa,EAAE,EAAE;QACjB,kBAAkB,EAAE,EAAE;QACtB,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,OAAgB,EAAQ,EAAE;QACtC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,KAAK,MAAM,KAAK,IAAI,OAAO;gBAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QACD,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnD,IAAI,GAAG,KAAK,MAAM,IAAI,OAAO,KAAK,KAAK,QAAQ;oBAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;oBAC5D,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,CAAC;IACX,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAC,IAAa,EAAE,GAAW;IACvD,IAAI,OAAO,GAAY,IAAI,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACrE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YAC5C,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAK,OAAmC,EAAE,CAAC;YAC9G,OAAO,GAAI,OAAmC,CAAC,OAAO,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC;AAED,mGAAmG;AACnG,SAAS,OAAO,CAAC,MAAe,EAAE,KAAc,EAAE,MAAc,EAAE,IAAY;IAC5E,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAChE,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,MAAM,MAAM,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC9F,CAAC;AAED,qEAAqE;AACrE,SAAS,SAAS,CAAC,IAAa;IAC9B,OAAO,IAAI,KAAK,IAAI;QAClB,OAAO,IAAI,KAAK,QAAQ;QACvB,IAAgC,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;AAChE,CAAC;AAED,+DAA+D;AAC/D,SAAS,aAAa,CAAC,IAAa;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;QACzB,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;YACzC,CAAC,CAAE,IAAgC,CAAC,aAAa,CAAC;YAClD,CAAC,CAAC,SAAS,CAAC;IAChB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,SAAS,qBAAqB,CAAC,IAAa;IAC1C,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAClF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAA+B,CAAC;SAC5D,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;SACrG,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAU,CAAC,CAAC;IAC1G,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,MAAe,EAAE,GAAW;IAC9C,OAAO,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAClD,CAAC,CAAE,MAAkC,CAAC,GAAG,CAAC;QAC1C,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC","sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { isMap, parseDocument } from \"yaml\";\nimport {\n HTTP_METHODS,\n OPENAPI_BASELINE_KEY,\n classifyBaselineDigests,\n operationBaselineOf,\n operationDigest,\n withoutOperationBaseline,\n} from \"./openapi.js\";\n// Every `isRecord` below asks one question of a resolved plain tree: is this a\n// node that can hold OpenAPI keys — an object, not an array?\nimport { isRecord } from \"./records.js\";\n\n/**\n * What a feature's operation IS, relative to the living contract — the one\n * judgement that tells a QUOTE from an EDIT.\n *\n * A feature's openapi.yaml is a complete document, so most of what it spells is\n * quotation: the author restated the living contract around the slot they were\n * changing. Without a pin the merge cannot tell the two apart and upserts both,\n * which is how a feature that only meant to touch `cancelOrder` silently\n * reverted another team's landed change to `refundOrder` — no overlap between\n * the features required, just two deltas over one service.\n */\nexport type OperationBaselineVerdict = ReturnType<typeof classifyBaselineDigests>;\n\n/**\n * Classify one feature operation against its living counterpart, from the raw\n * YAML trees the merge works in. The rule itself lives in core/openapi.ts, so\n * the gate and the merge cannot drift apart about which operations get written.\n *\n * A malformed pin matches no digest and lands in `stale`, which merges rather\n * than skips. Deliberate: `openapi.baseline-invalid` refuses it at the gate, and\n * a value nobody can evaluate must never be the reason a merge quietly drops an\n * operation.\n */\nexport function classifyOperationBaseline(featureOp: unknown, livingOp: unknown): OperationBaselineVerdict {\n return classifyBaselineDigests(\n operationBaselineOf(featureOp),\n operationDigest(featureOp),\n livingOp === undefined ? undefined : operationDigest(livingOp),\n );\n}\n\n/** What happened to one operation's `x-loam-based-on`. */\nexport interface OperationPin {\n path: string;\n method: string;\n /** Empty when the operation declares none — the slot is still the identity. */\n operationId: string;\n status:\n /** It had no pin and now has one. */\n | \"pinned\"\n /** It named an older living version; it now names the current one. */\n | \"repinned\"\n /** It already named the current living version — no write. */\n | \"unchanged\"\n /** The living contract has no operation at this slot: this feature is adding it. */\n | \"unresolved\"\n /** Written as a YAML alias — one shared value backs every use, so loam will not stamp through it. */\n | \"unwritable\";\n from: string | null;\n to: string | null;\n}\n\nexport interface OpenapiPinPlan {\n /** The rewritten contract, or null when no pin changes. */\n text: string | null;\n pins: OperationPin[];\n}\n\n/**\n * Pin every operation in a feature contract against the living one — what\n * `loam rebase` writes on this axis.\n *\n * The pin is always `operationDigest` of the LIVING operation, never of the\n * delta's own, and that single rule produces both merge verdicts by itself: an\n * operation the author only QUOTED is byte-equal to living, so its pin equals\n * its own content and `classifyOperationBaseline` calls it a quote; one the\n * author EDITED differs from its pin, so the merge writes it. Nothing has to\n * guess at intent — the document already records it, and the pin makes it\n * legible to the merge.\n *\n * Slot-keyed (path + method), exactly as the merge upserts. An operationId that\n * moved to another slot is a new slot with nothing living behind it, which is\n * `unresolved` and correct: there is no living version of an operation at a\n * path the contract does not serve yet.\n */\nexport function pinOpenapiOperations(featureText: string, livingText: string, service: string): OpenapiPinPlan {\n const doc = parseDocument(featureText);\n if (doc.errors.length > 0) throw new OpenapiMergeError(\"feature\", service, doc.errors[0]!.message);\n let featPlain: unknown;\n let livingPlain: unknown;\n try {\n featPlain = doc.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n try {\n const parsed = parseDocument(livingText);\n if (parsed.errors.length > 0) throw new OpenapiMergeError(\"living\", service, parsed.errors[0]!.message);\n livingPlain = parsed.toJS() ?? {};\n } catch (error) {\n if (error instanceof OpenapiMergeError) throw error;\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n\n const featPaths = plainChild(featPlain, \"paths\");\n if (!isRecord(featPaths)) return { text: null, pins: [] };\n const livingPaths = plainChild(livingPlain, \"paths\");\n\n const pins: OperationPin[] = [];\n let edited = false;\n for (const [path, item] of Object.entries(featPaths)) {\n if (!isRecord(item)) continue;\n for (const [method, op] of Object.entries(item)) {\n if (!HTTP_METHODS.has(method) || !isRecord(op)) continue;\n // A removal marker asserts a slot rather than restating an operation, so\n // it has nothing to be based on; `openapi.remove-target-mismatch` is what\n // guards it against a living slot that moved under it.\n if (isRemoval(op)) continue;\n\n const id = typeof op[\"operationId\"] === \"string\" ? op[\"operationId\"] : \"\";\n const at = { path, method, operationId: id };\n const from = operationBaselineOf(op) ?? null;\n const livingItem = plainChild(livingPaths, path);\n const livingOp = isRecord(livingItem) ? livingItem[method] : undefined;\n if (!isRecord(livingOp)) {\n pins.push({ ...at, status: \"unresolved\", from, to: null });\n continue;\n }\n const digest = operationDigest(livingOp);\n if (from === digest) {\n pins.push({ ...at, status: \"unchanged\", from: digest, to: digest });\n continue;\n }\n // One shared value backs every use of an anchor, so `setIn` through an\n // alias would pin every other use of it too — the same reason\n // stripOpenapiRemovalMarkers refuses to edit aliases in place.\n if (!isMap(doc.getIn([\"paths\", path, method]))) {\n pins.push({ ...at, status: \"unwritable\", from, to: null });\n continue;\n }\n pins.push({ ...at, status: from === null ? \"pinned\" : \"repinned\", from, to: digest });\n doc.setIn([\"paths\", path, method, OPENAPI_BASELINE_KEY], digest);\n edited = true;\n }\n }\n\n if (!edited) return { text: null, pins };\n try {\n return { text: doc.toString(), pins };\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n\n/** What an OpenAPI path merge computed, including every condition the caller must surface. */\nexport interface OpenapiMergeResult {\n /** The merged living document, or null when the feature document has no paths to merge. */\n text: string | null;\n /** Labels of existing operations overwritten with different content. */\n modified: string[];\n /**\n * Labels of PATH-LEVEL keys (`parameters`, `servers`, `summary`, `x-*`)\n * overwritten with different content. They are not operations, so they were\n * excluded from the difference check entirely and overwritten in silence —\n * a delta restating a path with a shorter `parameters` list dropped shared\n * parameters from every operation under it, and the plan said nothing.\n */\n pathItemModified: string[];\n /** Labels of living operations deleted by `x-loam-remove: true` markers. */\n removed: string[];\n /**\n * Labels of operations the delta QUOTED — pinned, and equal to their own\n * baseline — so the merge left the living contract's own copy alone. Reported\n * rather than silent: \"your delta mentions this and I did not write it\" is\n * exactly the sentence whose absence made the revert invisible.\n */\n quoted: string[];\n /**\n * Labels of operations whose pin matches neither the delta's own content nor\n * the living one: edited here AND changed by somebody else in between.\n * `openapi.baseline-stale` refuses these at the gate; the merge still\n * overwrites, because reaching it at all means `--approve` said to.\n */\n baselineStale: string[];\n /** `<kind>/<name>` of living components overwritten with different content. */\n componentsModified: string[];\n /** Local refs reachable from merged content that resolve in neither document. */\n unresolved: Array<{ ref: string; from: string }>;\n}\n\nexport type OpenapiMergeSource = \"feature\" | \"living\";\n\n/** A document the merge planner cannot read. Commands map this domain error to their own envelope. */\nexport class OpenapiMergeError extends Error {\n override readonly name = \"OpenapiMergeError\";\n\n constructor(\n readonly source: OpenapiMergeSource,\n readonly service: string,\n detail: string,\n ) {\n super(`${source} openapi for ${service} is not valid YAML: ${detail}`);\n }\n}\n\n/**\n * Remove feature-only operation-removal markers before a feature contract is\n * used to create a brand-new living document. Normally coherence refuses this\n * shape because there cannot be a removal target; this guard also keeps\n * `--approve` from ever persisting the marker into living docs.\n */\nexport function stripOpenapiRemovalMarkers(featureText: string, service: string): string {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new OpenapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n let plain: unknown;\n try {\n plain = feature.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n // Shape from the RESOLVED tree, for the same reason the merge reads it there:\n // an aliased `paths` or path item is not a map node, and treating it as\n // \"nothing to strip\" is how a feature-only marker reached a living contract.\n const paths = plainChild(plain, \"paths\");\n if (!isRecord(paths)) return featureText;\n\n const cleaned: Record<string, unknown> = {};\n let stripped = false;\n for (const [path, item] of Object.entries(paths)) {\n const kept = withoutFeatureMarkers(item);\n if (!isDeepStrictEqual(kept, item)) stripped = true;\n // A path the strip emptied goes with its last operation: `\\/x: {}` is a\n // path the contract advertises and nothing answers.\n if (kept !== undefined) cleaned[path] = kept;\n }\n if (!stripped) return featureText;\n\n // Edit the AST in place when every node the strip touches IS a node — the\n // author's comments, key order and formatting are theirs to keep. An alias\n // cannot be edited in place (there is one shared value behind it, and\n // deleting a key through it would change every use), so those documents get\n // their `paths` rewritten from the resolved tree instead: losing formatting\n // is a cost, shipping the marker is a corruption.\n //\n // The test has to reach the OPERATION nodes too, not just the path items. The\n // in-place branch strips a surviving operation's pin through\n // `[\"paths\", p, m, x-loam-based-on]`, and an aliased operation is exactly one\n // level below where the check used to look — so `deleteIn` walked into a node\n // that is not a collection and threw out of archive as `internal`, on a\n // document whose only fault was writing one operation twice.\n //\n // What disqualifies a method is \"there is something here to strip and I cannot\n // reach it\", not \"this is not a map node\". Only a resolved MAPPING can be a\n // removal marker or carry a pin, so a method spelled as a scalar — `get: ~`,\n // or a string — is nothing the in-place branch would have touched; demanding a\n // map node of it too demoted whole documents to the rewrite branch and cost\n // their author every comment, anchor and hand-chosen key order inside `paths`,\n // in the bytes archive installs as the living contract. What is left is the\n // real hazard: a mapping the AST does not hand back as a map. An alias is the\n // one node kind that resolves to a mapping without being one, and a method\n // whose KEY is an alias is not findable by name at all, so `deleteIn` reports\n // nothing deleted and the marker ships in silence. Both answer `undefined` or\n // a non-map here, and both belong on the safe branch.\n const editable =\n isMap(feature.get(\"paths\")) &&\n Object.entries(paths).every(\n ([p, item]) =>\n isMap(feature.getIn([\"paths\", p])) &&\n (!isRecord(item) ||\n Object.entries(item).every(\n ([m, op]) => !HTTP_METHODS.has(m) || !isRecord(op) || isMap(feature.getIn([\"paths\", p, m])),\n )),\n );\n if (!editable) {\n feature.setIn([\"paths\"], cleaned);\n } else {\n for (const [path, item] of Object.entries(paths)) {\n if (!isRecord(item)) continue;\n for (const [m, value] of Object.entries(item)) {\n // A loam marker at PATH level, deleted here for the same reason the\n // resolved-tree branch drops it: the two branches must agree exactly\n // about what a living contract may carry.\n if (FEATURE_ONLY_KEYS.has(m)) feature.deleteIn([\"paths\", path, m]);\n if (!HTTP_METHODS.has(m)) continue;\n if (isRemoval(value)) feature.deleteIn([\"paths\", path, m]);\n // The surviving operations keep their formatting but lose their pin:\n // the in-place branch must strip everything the resolved-tree branch\n // does, or the two disagree about what a living contract may carry.\n else if (operationBaselineOf(value) !== undefined) {\n feature.deleteIn([\"paths\", path, m, OPENAPI_BASELINE_KEY]);\n }\n }\n const remaining = feature.getIn([\"paths\", path]);\n if (isMap(remaining) && remaining.items.length === 0) feature.deleteIn([\"paths\", path]);\n }\n }\n try {\n return feature.toString();\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n\n/**\n * Merge the feature's `paths` into the living OpenAPI structurally (YAML AST, not\n * text splicing). A feature document without paths is a successful no-op.\n * The merged operations' local component-ref closure rides along recursively;\n * external refs are left untouched and never gated.\n *\n * Every SHAPE question — is there a `paths` mapping, is this path item a\n * mapping, which methods does it hold — is answered from the RESOLVED plain\n * trees, never from the AST node. Asking the AST (`isMap(node)`) answers a\n * different question: an alias node is not a map even when it resolves to one.\n * `paths: *alias` therefore read as \"no paths to merge\" and the whole contract\n * delta was dropped with a successful exit, and an aliased path ITEM fell into\n * the wholesale-replace branch and deleted every living operation on that path\n * that the alias did not restate. Aliases are legal OpenAPI and the natural way\n * to write a delta that repeats a shape; nothing here may treat them as absent.\n * An alias that cannot be resolved at all is a document loam cannot read, and\n * says so — it is never \"nothing to merge\".\n */\nexport function mergeOpenapiPaths(\n livingText: string,\n featureText: string,\n service: string,\n): OpenapiMergeResult {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new OpenapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n let featPlain: unknown;\n try {\n // Resolve aliases once with the document's own anchor context. Calling an\n // individual AST node's toJSON() loses that context and can silently turn\n // an aliased operation or component into the wrong value.\n featPlain = feature.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"feature\", service, errorMessage(error));\n }\n const featPathsPlain = plainChild(featPlain, \"paths\");\n if (featPathsPlain === undefined || featPathsPlain === null) {\n return noop();\n }\n if (!isRecord(featPathsPlain)) {\n throw new OpenapiMergeError(\"feature\", service, \"`paths` is not a mapping\");\n }\n const featPathEntries = Object.entries(featPathsPlain);\n if (featPathEntries.length === 0) return noop();\n\n const living = parseDocument(livingText);\n if (living.errors.length > 0) {\n throw new OpenapiMergeError(\"living\", service, living.errors[0]!.message);\n }\n let livingPlain: unknown;\n try {\n livingPlain = living.toJS() ?? {};\n } catch (error) {\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n const livingPathsPlain = plainChild(livingPlain, \"paths\");\n if (livingPathsPlain !== undefined && livingPathsPlain !== null && !isRecord(livingPathsPlain)) {\n throw new OpenapiMergeError(\"living\", service, \"`paths` is not a mapping\");\n }\n const modified: string[] = [];\n const pathItemModified: string[] = [];\n const removed: string[] = [];\n const quoted: string[] = [];\n const baselineStale: string[] = [];\n for (const [path, featItemPlain] of featPathEntries) {\n const existing = living.getIn([\"paths\", path]);\n const existingPlain = plainChild(livingPathsPlain, path);\n if (existing !== undefined && !isRecord(existingPlain)) {\n // The living contract holds this path as something other than a path\n // item. Replacing it wholesale is the one branch that may delete living\n // operations without naming them, so it is reserved for paths the living\n // contract does not have at all.\n throw new OpenapiMergeError(\"living\", service, `path '${path}' is not a mapping`);\n }\n if (existing !== undefined) {\n if (!isRecord(featItemPlain)) {\n throw new OpenapiMergeError(\"feature\", service, `path '${path}' is not a mapping`);\n }\n // EVERY branch publishes through withoutFeatureMarkers. This one used to\n // copy every key of the feature path item and guard only the HTTP\n // methods, so a path-level `x-loam-remove` landed in the living contract\n // with `modified: []` and no warning. A key the strip drops is never\n // written; the removal handling below still reads the RAW item, because\n // that is where the markers it acts on live.\n const publish = withoutFeatureMarkers(featItemPlain);\n const publishable = isRecord(publish) ? publish : {};\n for (const [m, afterPlain] of Object.entries(featItemPlain)) {\n const before = living.getIn([\"paths\", path, m]);\n const beforePlain = plainChild(existingPlain, m);\n if (HTTP_METHODS.has(m) && isRemoval(afterPlain)) {\n // Coherence validates the marker and gates absent/mismatched targets.\n // The merge remains defensive under --approve: never delete a\n // different operation merely because it occupies the requested slot.\n if (\n before !== undefined &&\n operationIdOf(beforePlain) !== undefined &&\n operationIdOf(beforePlain) === operationIdOf(afterPlain)\n ) {\n removed.push(opLabel(beforePlain, afterPlain, m, path));\n living.deleteIn([\"paths\", path, m]);\n }\n continue;\n }\n if (HTTP_METHODS.has(m)) {\n const verdict = classifyOperationBaseline(afterPlain, before === undefined ? undefined : beforePlain);\n // A QUOTE is not a merge input. The author wrote this operation down\n // because the document is complete, not because they changed it, so\n // the living contract keeps whatever it holds — including a change\n // that landed after this delta was written. This is mechanical, not a\n // judgement, so `--approve` does not turn it back on: overriding a\n // gate is a decision, reverting an operation nobody edited is a bug.\n if (verdict === \"quote\") {\n quoted.push(opLabel(beforePlain, afterPlain, m, path));\n continue;\n }\n if (verdict === \"stale\") baselineStale.push(opLabel(beforePlain, afterPlain, m, path));\n }\n if (!(m in publishable)) {\n // A feature-only marker at path level. It is never published, and\n // never reported as a path-item overwrite either — it is not a key of\n // the contract at all. The archive gate names it to the author.\n continue;\n }\n // The difference check covers EVERY key of the path item; only the\n // LABEL depends on whether the key is an HTTP method.\n if (before !== undefined && !isDeepStrictEqual(beforePlain, afterPlain)) {\n if (HTTP_METHODS.has(m)) modified.push(opLabel(beforePlain, afterPlain, m, path));\n else pathItemModified.push(`'${m}' (${path})`);\n }\n // Every shape question above was answered from the RESOLVED tree, which\n // is exactly what makes an aliased path item read as an ordinary\n // mapping. The WRITE cannot be that forgiving: `setIn` walks the AST,\n // and one shared value backs every use of an anchor, so an operation\n // merged through the alias would land in every other path that\n // references it. There is no way to write into one use of an anchor and\n // not the rest, so this is a refusal rather than a fallback — and it is\n // asked here, at the write, because reading is safe and writing is not.\n if (!isMap(living.getIn([\"paths\", path]))) {\n throw new OpenapiMergeError(\n \"living\",\n service,\n `path '${path}' is written as a YAML alias — one shared value backs every use, so merging into it would rewrite every other path that aliases it. Expand it before archiving.`,\n );\n }\n // Without the strip the living contract would grow a pin to a version\n // of itself, and the NEXT feature's baseline would hash it.\n living.setIn([\"paths\", path, m], publishable[m]);\n }\n // Removing the last method leaves `\\/x: {}` — a path the contract still\n // advertises and nothing answers. The same cleanup\n // stripOpenapiRemovalMarkers already does on the feature side.\n const remaining = living.getIn([\"paths\", path]);\n if (isMap(remaining) && remaining.items.length === 0) living.deleteIn([\"paths\", path]);\n continue;\n }\n if (!isRecord(featItemPlain)) {\n throw new OpenapiMergeError(\"feature\", service, `path '${path}' is not a mapping`);\n }\n const clean = withoutFeatureMarkers(featItemPlain);\n if (clean !== undefined) living.setIn([\"paths\", path], clean);\n }\n\n const componentsModified: string[] = [];\n const unresolved: OpenapiMergeResult[\"unresolved\"] = [];\n const visited = new Set<string>();\n const copies: Array<{ kind: string; name: string; value: unknown }> = [];\n\n const visitRef = (ref: string, from: string): void => {\n if (!ref.startsWith(\"#/\")) return;\n const match = /^#\\/components\\/([^/]+)\\/([^/]+)(?:\\/|$)/.exec(ref);\n if (!match) {\n if (!resolvePointer(featPlain, ref).found && !resolvePointer(livingPlain, ref).found) {\n unresolved.push({ ref, from });\n }\n return;\n }\n const kind = match[1]!;\n const name = match[2]!;\n const key = `${kind}/${name}`;\n if (visited.has(key)) return;\n visited.add(key);\n const inFeature = resolvePointer(featPlain, `#/components/${kind}/${name}`);\n if (inFeature.found) {\n copies.push({ kind, name, value: inFeature.value });\n walk(inFeature.value, `components/${key}`);\n return;\n }\n if (!resolvePointer(livingPlain, `#/components/${kind}/${name}`).found) {\n unresolved.push({ ref, from });\n }\n };\n\n const walk = (node: unknown, from: string): void => {\n for (const ref of collectRefs(node)) visitRef(ref, from);\n };\n\n for (const [path, featItemPlain] of featPathEntries) {\n walk(withoutFeatureMarkers(featItemPlain), `paths ${path}`);\n }\n\n for (const { kind, name, value } of copies) {\n const existing = living.getIn([\"components\", kind, name]);\n if (existing !== undefined) {\n const existingPlain = resolvePointer(livingPlain, `#/components/${kind}/${name}`);\n if (existingPlain.found && isDeepStrictEqual(existingPlain.value, value)) continue;\n componentsModified.push(`${kind}/${name}`);\n }\n living.setIn([\"components\", kind, name], value);\n }\n\n let text: string;\n try {\n text = living.toString();\n } catch (error) {\n throw new OpenapiMergeError(\"living\", service, errorMessage(error));\n }\n return { text, modified, pathItemModified, removed, quoted, baselineStale, componentsModified, unresolved };\n}\n\n/** The successful \"the feature document has nothing to merge\" answer. */\nfunction noop(): OpenapiMergeResult {\n return {\n text: null,\n modified: [],\n pathItemModified: [],\n removed: [],\n quoted: [],\n baselineStale: [],\n componentsModified: [],\n unresolved: [],\n };\n}\n\n/** Every `$ref` string value anywhere in a plain JS tree, in document order. */\nexport function collectRefs(node: unknown): string[] {\n const out: string[] = [];\n const walk = (current: unknown): void => {\n if (Array.isArray(current)) {\n for (const value of current) walk(value);\n return;\n }\n if (current !== null && typeof current === \"object\") {\n for (const [key, value] of Object.entries(current)) {\n if (key === \"$ref\" && typeof value === \"string\") out.push(value);\n else walk(value);\n }\n }\n };\n walk(node);\n return out;\n}\n\n/** Resolve a local JSON pointer (`#/a/b~1c`) against a plain JS tree. */\nexport function resolvePointer(root: unknown, ref: string): { found: boolean; value: unknown } {\n let current: unknown = root;\n for (const raw of ref.slice(2).split(\"/\")) {\n const segment = raw.replace(/~1/g, \"/\").replace(/~0/g, \"~\");\n if (Array.isArray(current)) {\n const index = Number(segment);\n if (!Number.isInteger(index) || index < 0 || index >= current.length) {\n return { found: false, value: undefined };\n }\n current = current[index];\n } else if (current !== null && typeof current === \"object\" && segment in (current as Record<string, unknown>)) {\n current = (current as Record<string, unknown>)[segment];\n } else {\n return { found: false, value: undefined };\n }\n }\n return { found: true, value: current };\n}\n\n/** Name an overwritten operation by its operationId (feature's, else living's), or path+method. */\nfunction opLabel(before: unknown, after: unknown, method: string, path: string): string {\n const operation = operationIdOf(after) ?? operationIdOf(before);\n return operation !== undefined ? `'${operation}' (${method} ${path})` : `${method} ${path}`;\n}\n\n/** Is this operation node a feature-only explicit removal marker? */\nfunction isRemoval(node: unknown): boolean {\n return node !== null &&\n typeof node === \"object\" &&\n (node as Record<string, unknown>)[\"x-loam-remove\"] === true;\n}\n\n/** Read an operationId from a YAML or plain operation node. */\nfunction operationIdOf(node: unknown): string | undefined {\n const value = isMap(node)\n ? node.get(\"operationId\")\n : node !== null && typeof node === \"object\"\n ? (node as Record<string, unknown>)[\"operationId\"]\n : undefined;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/**\n * Every key that is an instruction to loam rather than part of the contract.\n * At PATH level neither has any meaning — `x-loam-remove` addresses one\n * operation and `x-loam-based-on` pins one — so a path item carrying either is\n * an authoring mistake, and one that must not be published whatever else is\n * done about it.\n */\nconst FEATURE_ONLY_KEYS = new Set([\"x-loam-remove\", OPENAPI_BASELINE_KEY]);\n\n/**\n * Copy a path item without anything that belongs to the FEATURE rather than to\n * the contract: removal-marker operations, the `x-loam-based-on` pins on the\n * operations that survive, and a loam marker written at PATH level. All three\n * are instructions to loam, and a living contract that carries any of them is\n * lying to the next reader — and, for the pin, to the next feature's baseline.\n *\n * The path-level case used to fall through: the filter guarded only HTTP\n * methods, so `x-loam-remove: true` beside the methods was copied verbatim into\n * the fleet's living contract, where it also kept the empty-path cleanup from\n * ever seeing an empty path.\n */\nfunction withoutFeatureMarkers(node: unknown): unknown {\n if (node === null || typeof node !== \"object\" || Array.isArray(node)) return node;\n const entries = Object.entries(node as Record<string, unknown>)\n .filter(([key, value]) => !FEATURE_ONLY_KEYS.has(key) && !(HTTP_METHODS.has(key) && isRemoval(value)))\n .map(([key, value]) => [key, HTTP_METHODS.has(key) ? withoutOperationBaseline(value) : value] as const);\n return entries.length === 0 ? undefined : Object.fromEntries(entries);\n}\n\nfunction plainChild(parent: unknown, key: string): unknown {\n return parent !== null && typeof parent === \"object\"\n ? (parent as Record<string, unknown>)[key]\n : undefined;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}