@miragon/modeler-api 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +141 -2
- package/dist/chunk-HWB2EYDZ.js +7 -0
- package/dist/chunk-HWB2EYDZ.js.map +1 -0
- package/dist/conformance.cjs +718 -0
- package/dist/conformance.cjs.map +1 -0
- package/dist/conformance.d.cts +134 -0
- package/dist/conformance.d.ts +134 -0
- package/dist/conformance.js +689 -0
- package/dist/conformance.js.map +1 -0
- package/dist/index.cjs +31 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +146 -0
- package/dist/index.d.ts +146 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/conformance.ts"],"sourcesContent":["/**\n * The conformance test kit — every law of the CollaborativeModeler contract\n * as an executable case. A modeler repo supplies a small HARNESS (how to\n * create an instance, canonical sample texts, scripted user mutations) and\n * binds the cases to its own test runner:\n *\n * import { conformanceCases, registerConformance } from \"@miragon/modeler-api/conformance\";\n * registerConformance(harness, test); // node:test, vitest, jest — any (name, fn) runner\n *\n * Cases throw plain Errors on violation, so the kit has no runner or\n * assertion-library dependency. A case that CANNOT (fully) run because the\n * harness left an optional field undefined resolves with `{ skipped }` and\n * registerConformance reports it (console.warn by default) — a law the kit\n * did not verify is never a silent green.\n */\nimport { type CollaborativeModeler, MODELER_API_VERSION } from \"./index.js\";\n\nexport interface UserMutation {\n /** names the failing mutation in the kit's error message */\n name: string;\n run(modeler: CollaborativeModeler): Promise<void> | void;\n}\n\nexport interface ConformanceHarness {\n /**\n * a fresh EDITABLE modeler, attached to a host element that is IN the\n * document with a non-zero size (`attachedHost()` below) — diagram-js\n * engines compute viewboxes from the host's client size, so a detached\n * or 0×0 host yields NaN view state; they also need a real browser\n * (vitest browser mode / Playwright), jsdom has no getBBox\n */\n create(): Promise<CollaborativeModeler>;\n /** a fresh READ-ONLY instance (`meta.editable === false`) — the viewer\n * mount hosts use on read-only surfaces; absent = the package ships no\n * viewer and the viewer case is reported as skipped */\n createReadonly?(): Promise<CollaborativeModeler>;\n /**\n * CANONICAL sample documents of the notation (>= 2, distinct, at least one\n * rendering an element, ideally several covering config/axis content too)\n * — exactly what exportText emits. Obtain them by exporting a hand-authored\n * document and REVIEWING the bytes, not by pasting whatever the current\n * build prints: L2 only proves the serializer is a fixpoint of the texts\n * you vouch for\n */\n canonicalTexts: string[];\n /** importable but non-canonical inputs (hand-authored variants); the kit\n * verifies canonicalization is IDEMPOTENT on them, not byte-stable.\n * `undefined` = skipped; `[]` = the notation has no loose form */\n looseTexts?: string[];\n /**\n * NON-importable inputs (half-typed peer text, wrong notation) — the kit\n * verifies importText REJECTS, leaves no trace and stays usable (L7).\n * `undefined` = not provided (the L7 cases report a SKIP); `[]` = the\n * deliberate statement that this notation has no non-importable text\n * (the lenient line DSLs keep every line, so nothing rejects)\n */\n invalidTexts?: string[];\n /**\n * importable documents carrying content the modeler does NOT understand\n * (vendor extensions, unknown lines, unknown JSON keys), each with the\n * fragments that must come back from an import → export round-trip (L6).\n * `undefined` = skipped; `[]` = the notation has no foreign form\n */\n foreignTexts?: Array<{ text: string; mustSurvive: string[] }>;\n /**\n * a NON-default view state the modeler accepts — a panned/zoomed viewport\n * (e.g. a viewbox) that differs from what an import leaves; L5 cannot tell\n * a restore from a no-op without one. The kit never compares a readback\n * with this literal: it sets it, reads the modeler's own (possibly\n * normalised) state back, and requires THAT to survive a re-import and to\n * be settable itself. `undefined` = L5 is reported as skipped\n */\n viewState?: unknown;\n /** wait until deferred/debounced change events have been delivered —\n * MUST outlast the modeler's event debounce; defaults to one macrotask */\n settle?(): Promise<void>;\n /**\n * perform ONE user-visible atomic ELEMENT command through the modeler's\n * own commands: ADD an element — never rename or delete one (the elements\n * case treats it as an edit unrelated to the existing elements, and L4\n * builds undo history from it, so it must be undoable)\n */\n mutate(modeler: CollaborativeModeler): Promise<void> | void;\n /**\n * user-visible changes that do NOT run through an element command:\n * config/axis/title/style/size edits that live in the document. A notation\n * with such surfaces MUST list them — the kit cannot see what the canvas\n * offers, and a modeler that only forwards its command stack passes\n * `mutate` while a host loses exactly these edits. `undefined` = skipped;\n * `[]` = the notation has no such surface\n */\n configMutations?: UserMutation[];\n /** trigger the modeler's undo; `undefined` = the notation has no undo\n * (the undo cases are reported as skipped) */\n undo?(modeler: CollaborativeModeler): Promise<void> | void;\n /** trigger the modeler's redo; `undefined` with `undo` defined = the redo\n * half of the undo/redo case is reported as skipped */\n redo?(modeler: CollaborativeModeler): Promise<void> | void;\n}\n\nexport interface CaseOutcome {\n /** the case could not (fully) verify its law — the harness left the field\n * it needs undefined, or the modeler has no such optional surface; the\n * reason names which */\n skipped?: string;\n}\n\nexport interface ConformanceCase {\n name: string;\n run(harness: ConformanceHarness): Promise<CaseOutcome | void>;\n}\n\n/**\n * a host element of the given size, attached to the document — what\n * `create()` should mount into (browser only). The returned element sits\n * INSIDE a sized wrapper: the Miragon renderers restyle the container they\n * are given to 100% × 100%, which then resolves against the wrapper\n */\nexport function attachedHost(width = 800, height = 600): HTMLElement {\n const wrapper = document.createElement(\"div\");\n wrapper.style.cssText = `width:${width}px;height:${height}px;position:absolute;left:0;top:0;overflow:hidden`;\n const host = document.createElement(\"div\");\n host.style.cssText = \"width:100%;height:100%\";\n wrapper.append(host);\n document.body.append(wrapper);\n return host;\n}\n\n/**\n * apiVersion compatibility: same major — and, while the contract is 0.x,\n * the same minor too (pre-1.0 minors may break; bump-minor-pre-major)\n */\nexport function apiVersionsCompatible(a: string, b: string): boolean {\n const [aMajor = \"\", aMinor = \"\"] = a.split(\".\");\n const [bMajor = \"\", bMinor = \"\"] = b.split(\".\");\n if (aMajor !== bMajor) return false;\n return aMajor !== \"0\" || aMinor === bMinor;\n}\n\nfunction fail(message: string): never {\n throw new Error(`modeler-api conformance: ${message}`);\n}\n\nconst skip = (reason: string): CaseOutcome => ({ skipped: reason });\n\nfunction exportOrFail(modeler: CollaborativeModeler, when: string): string {\n try {\n return modeler.exportText();\n } catch (e) {\n fail(`exportText threw ${when}: ${String(e)}`);\n }\n}\n\nconst same = (a: unknown, b: unknown): boolean => JSON.stringify(a) === JSON.stringify(b);\n\n/** a view state with NaN/Infinity is what a detached or 0×0 host produces */\nfunction assertFinite(state: unknown, when: string): void {\n const json = JSON.stringify(state, (_k, v: unknown) =>\n typeof v === \"number\" && !Number.isFinite(v) ? \"__non_finite__\" : v,\n );\n if (json?.includes(\"__non_finite__\")) {\n fail(\n `getViewState() ${when} contains a non-finite number — the host has no size (mount into attachedHost())`,\n );\n }\n}\n\nconst defaultSettle = (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 0));\n\n/** count invocations of onContentChanged around an action — settle-aware, so\n * debounced engines neither hide an echo nor fail a legitimate event; the\n * export seen INSIDE the last delivery is returned too (L3's ordering rule) */\nasync function changeEvents(\n harness: ConformanceHarness,\n modeler: CollaborativeModeler,\n action: () => Promise<void> | void,\n): Promise<{ calls: number; exportAtEmit: string | undefined }> {\n const settle = harness.settle ?? defaultSettle;\n let calls = 0;\n let exportAtEmit: string | undefined;\n const off = modeler.onContentChanged(() => {\n calls += 1;\n exportAtEmit = modeler.exportText();\n });\n try {\n await action();\n await settle();\n } finally {\n off();\n }\n return { calls, exportAtEmit };\n}\n\nconst secondText = (h: ConformanceHarness): string => h.canonicalTexts[1] ?? h.canonicalTexts[0] ?? \"\";\n\n/** the harness's user mutations: the element command first, then every config edit */\nconst mutationsOf = (h: ConformanceHarness): UserMutation[] => [\n { name: \"mutate (element command)\", run: (m) => h.mutate(m) },\n ...(h.configMutations ?? []),\n];\n\nconst sortedIds = (m: CollaborativeModeler): string[] | undefined =>\n m.elements ? [...m.elements.list().map((e) => e.id)].sort() : undefined;\n\n/**\n * import the first canonical text that renders at least one element (an\n * empty document has no fitted view — renderers leave the viewport alone),\n * and return it; without an elements surface the first text is used\n */\nasync function importContentText(h: ConformanceHarness, m: CollaborativeModeler): Promise<string> {\n for (const text of h.canonicalTexts) {\n await m.importText(text);\n if (!m.elements || m.elements.list().length > 0) return text;\n }\n fail(\"L5 needs a canonical text that renders at least one element — an empty document has no fitted view\");\n}\n\nexport function conformanceCases(): ConformanceCase[] {\n return [\n {\n name: \"meta declares the notation, editability and a compatible apiVersion\",\n async run(h) {\n const m = await h.create();\n try {\n if (!m.meta.notation) fail(\"meta.notation is empty\");\n if (m.meta.editable !== true)\n fail(\"create() must return an EDITABLE modeler (meta.editable === true)\");\n if (!apiVersionsCompatible(m.meta.apiVersion, MODELER_API_VERSION)) {\n fail(`apiVersion ${m.meta.apiVersion} is not compatible with ${MODELER_API_VERSION}`);\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L1: importText is silent (no change events, for canonical, loose and foreign inputs)\",\n async run(h) {\n const m = await h.create();\n try {\n const texts = [\n ...h.canonicalTexts,\n ...(h.looseTexts ?? []),\n ...(h.foreignTexts ?? []).map((f) => f.text),\n ];\n for (const text of texts) {\n const { calls } = await changeEvents(h, m, () => m.importText(text).then(() => undefined));\n if (calls > 0) fail(`importText fired onContentChanged ${calls}x`);\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L1: importText over EXISTING undo history is silent too\",\n async run(h) {\n // diagram-js' commandStack.clear() emits 'changed' whether or not the\n // stack is empty — but an engine that only emits when it has something\n // to clear would pass the fresh-instance case above\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n const { calls } = await changeEvents(h, m, () => m.importText(secondText(h)).then(() => undefined));\n if (calls > 0) fail(`importText over a non-empty undo history fired onContentChanged ${calls}x`);\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L2: canonical texts are byte fixpoints of import → export\",\n async run(h) {\n if (h.canonicalTexts.length === 0) fail(\"harness provides no canonicalTexts\");\n const m = await h.create();\n try {\n for (const text of h.canonicalTexts) {\n await m.importText(text);\n const out = m.exportText();\n if (out !== text)\n fail(`export after import differs from the canonical input:\\n--- in\\n${text}\\n--- out\\n${out}`);\n if (m.exportText() !== out)\n fail(\"exportText is not deterministic — two exports of one document differ\");\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L2: canonicalization of loose input is idempotent\",\n async run(h) {\n if (h.looseTexts === undefined)\n return skip(\"looseTexts is undefined — pass [] if the notation has no loose form\");\n if (h.looseTexts.length === 0) return;\n const m = await h.create();\n try {\n for (const text of h.looseTexts) {\n await m.importText(text);\n const canonical = m.exportText();\n await m.importText(canonical);\n const again = m.exportText();\n if (again !== canonical) fail(\"canonicalization is not idempotent on loose input\");\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L3: a scripted user mutation fires onContentChanged, and the export already reflects it inside the listener\",\n async run(h) {\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n const before = m.exportText();\n const { calls, exportAtEmit } = await changeEvents(h, m, () => h.mutate(m));\n if (calls === 0) fail(\"a user mutation fired no onContentChanged\");\n const after = m.exportText();\n if (after === before)\n fail(\"the harness mutation did not change the export — the case proves nothing\");\n if (exportAtEmit !== after) {\n fail(\n \"exportText() inside the onContentChanged listener did not return the post-change document (emit before apply)\",\n );\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L3: config/axis edits fire onContentChanged too, with the export already updated\",\n async run(h) {\n if (h.configMutations === undefined) {\n return skip(\n \"configMutations is undefined — pass [] if the notation has no config/axis/title surface\",\n );\n }\n for (const mutation of h.configMutations) {\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n const before = m.exportText();\n const { calls, exportAtEmit } = await changeEvents(h, m, () => mutation.run(m));\n if (calls === 0) fail(`config mutation \"${mutation.name}\" fired no onContentChanged`);\n const after = m.exportText();\n if (after === before) {\n fail(`config mutation \"${mutation.name}\" did not change the export — the case proves nothing`);\n }\n if (exportAtEmit !== after) {\n fail(\n `exportText() inside the listener of config mutation \"${mutation.name}\" did not return the post-change document`,\n );\n }\n } finally {\n m.destroy();\n }\n }\n },\n },\n {\n name: \"L3: unsubscribe stops delivery\",\n async run(h) {\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n let calls = 0;\n const off = m.onContentChanged(() => {\n calls += 1;\n });\n off();\n await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n if (calls > 0) fail(\"onContentChanged delivered after unsubscribe\");\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L3: undo and redo fire onContentChanged and restore the export\",\n async run(h) {\n if (!h.undo) return skip(\"undo is undefined — the notation declares no undo\");\n const undo = h.undo;\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n const before = m.exportText();\n await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n const mutated = m.exportText();\n const undone = await changeEvents(h, m, () => undo(m));\n if (undone.calls === 0)\n fail(\"undo fired no onContentChanged — the host would never export the undone state\");\n if (m.exportText() !== before)\n fail(\"undo of a single mutation did not restore the pre-mutation export\");\n if (undone.exportAtEmit !== before)\n fail(\"exportText() inside the undo listener did not return the undone document\");\n if (!h.redo)\n return skip(\n \"redo is undefined — the redo half of this case was not verified (pass redo to verify it)\",\n );\n const redo = h.redo;\n const redone = await changeEvents(h, m, () => redo(m));\n if (redone.calls === 0) fail(\"redo fired no onContentChanged\");\n if (m.exportText() !== mutated) fail(\"redo did not restore the mutated export\");\n if (redone.exportAtEmit !== mutated)\n fail(\"exportText() inside the redo listener did not return the redone document\");\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L4: undo directly after an import is a no-op\",\n async run(h) {\n if (!h.undo) return skip(\"undo is undefined — the notation declares no undo\");\n const first = h.canonicalTexts[0];\n const second = h.canonicalTexts[1];\n if (first === undefined || second === undefined || first === second) {\n fail(\"the L4 case needs TWO DISTINCT canonicalTexts — with one, stale undo is undetectable\");\n }\n const m = await h.create();\n try {\n await m.importText(first);\n await h.mutate(m); // real history exists…\n await h.mutate(m); // …more than one entry deep…\n // leg 1 — GUARANTEED id coincidence: re-import the mutated document\n // itself. A stale diagram-js stack whose revert removes the created\n // shape by id is a silent no-op on any other document and deletes a\n // re-imported element on this one — the tt drift as it really bites\n const mutated = m.exportText();\n await m.importText(mutated);\n const baselineSame = m.exportText();\n const idsSame = sortedIds(m);\n const { calls } = await changeEvents(h, m, () => h.undo!(m));\n if (calls > 0)\n fail(\n \"undo directly after importText fired onContentChanged — history housekeeping is not a change\",\n );\n if (m.exportText() !== baselineSame || (idsSame && !same(idsSame, sortedIds(m)))) {\n fail(\n \"undo after importText removed a re-imported element by id coincidence (stale history applied)\",\n );\n }\n // leg 2 — a DIFFERENT document replaces the doc; a snapshot-restoring\n // stale stack would resurrect the previous one\n await h.mutate(m);\n await m.importText(second);\n // baseline via the modeler's OWN serializer: this case isolates the\n // undo law — a non-canonical serializer must fail L2, not here\n const baseline = m.exportText();\n await h.undo(m);\n await h.undo(m); // drain a stale multi-entry history too\n if (m.exportText() !== baseline) {\n fail(\"undo after importText mutated the freshly imported document (stale history applied)\");\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L5: getViewState never throws before the first import\",\n async run(h) {\n const m = await h.create();\n try {\n let state: unknown;\n try {\n state = m.getViewState();\n } catch (e) {\n fail(`getViewState threw before the first import: ${String(e)}`);\n }\n if (state !== undefined) assertFinite(state, \"before the first import\");\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L5: view state round-trips across a re-import, an import fits the view — and none of it is document content\",\n async run(h) {\n if (h.viewState === undefined) {\n return skip(\n \"viewState is undefined — supply a panned/zoomed state, a no-op setViewState is otherwise undetectable\",\n );\n }\n const alt = h.viewState;\n const m = await h.create();\n try {\n const text = await importContentText(h, m);\n const doc = m.exportText();\n const fitted = m.getViewState();\n assertFinite(fitted, \"after the first import\");\n // the modeler's OWN readback is the oracle from here on — a\n // diagram-js viewbox comes back rounded and enriched (scale, inner,\n // outer), never byte-equal to the harness literal\n m.setViewState(alt);\n const applied = m.getViewState();\n assertFinite(applied, \"after setViewState\");\n if (same(applied, fitted)) {\n fail(\"setViewState(viewState) had no effect — supply a state that differs from the fitted view\");\n }\n await m.importText(text);\n if (!same(m.getViewState(), fitted)) {\n fail(\n \"an import must leave the view FITTED to the content (the same state the first import produced)\",\n );\n }\n // the host restores with what IT read back before the re-import —\n // the readback must be settable and yield itself again\n const { calls } = await changeEvents(h, m, () => m.setViewState(applied));\n if (calls > 0) fail(\"setViewState fired onContentChanged — view state is not document content\");\n if (m.exportText() !== doc)\n fail(\"setViewState changed the export — view state leaked into the document\");\n if (!same(m.getViewState(), applied)) {\n fail(\n \"view state did not survive re-import + restore (setting the modeler's own readback must yield that readback)\",\n );\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"elements (when present): stable ids across re-imports and unrelated edits, reveal and selection semantics\",\n async run(h) {\n const m = await h.create();\n try {\n const text = h.canonicalTexts[0] ?? \"\";\n await m.importText(text);\n const elements = m.elements;\n if (!elements)\n return skip(\"the modeler exposes no elements surface (optional) — nothing to verify\");\n const ids = elements.list().map((e) => e.id);\n if (new Set(ids).size !== ids.length) fail(\"element ids are not unique\");\n await m.importText(text);\n const again = elements.list().map((e) => e.id);\n if (!same([...ids].sort(), [...again].sort()))\n fail(\"element ids are not stable across re-imports of the same text\");\n if (elements.reveal(\"__modeler_api_no_such_id__\") !== false)\n fail(\"reveal(unknown id) must return false\");\n const firstId = ids[0];\n if (firstId !== undefined) {\n const deliveries: string[][] = [];\n const off = elements.onSelection((selected) => deliveries.push([...selected]));\n const { calls } = await changeEvents(h, m, () => {\n if (elements.reveal(firstId) !== true) fail(\"reveal(known id) must return true\");\n });\n if (calls > 0) fail(\"reveal fired onContentChanged — revealing is view behavior, not an edit\");\n if (!deliveries.some((d) => d.includes(firstId))) {\n fail(\n `reveal('${firstId}') delivered no selection containing the id — is it a selectable element (not a root or a label)?`,\n );\n }\n for (const d of deliveries) {\n for (const id of d) {\n if (!again.includes(id)) {\n fail(\n `onSelection reported an id that is not an element: '${id}' (label ids must resolve to their target)`,\n );\n }\n }\n }\n if (!elements.selection().includes(firstId)) fail(\"selection() does not contain the revealed id\");\n const seen = deliveries.length;\n off();\n // a DIFFERENT selection after the unsubscribe — re-revealing the\n // same id would be deduplicated by many engines and prove nothing\n const otherId = ids[1];\n if (otherId !== undefined) elements.reveal(otherId);\n else await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n if (deliveries.length !== seen) fail(\"onSelection delivered after unsubscribe\");\n }\n // an edit to ANOTHER element must not renumber existing ids: every id\n // still exists AND (where the notation has names) still names the\n // same element — a positional scheme keeps the id strings while\n // shifting what they point at\n const namesBefore = new Map(elements.list().map((e) => [e.id, e.name]));\n await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n const afterEdit = new Map(elements.list().map((e) => [e.id, e.name]));\n if (afterEdit.size <= namesBefore.size) {\n fail(\n \"the harness mutate must ADD an element (the elements case verifies ids under an unrelated edit)\",\n );\n }\n for (const [id, name] of namesBefore) {\n if (!afterEdit.has(id)) {\n fail(\n `element id '${id}' vanished after an unrelated edit — ids must survive edits to other elements`,\n );\n }\n if (name !== undefined && afterEdit.get(id) !== name) {\n fail(\n `element id '${id}' names a different element after an unrelated edit ('${name}' → '${String(afterEdit.get(id))}')`,\n );\n }\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L6: export is total after imports, user mutations and undo\",\n async run(h) {\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n for (const mutation of mutationsOf(h)) {\n await mutation.run(m);\n exportOrFail(m, `after ${mutation.name}`);\n }\n if (h.undo) {\n await h.undo(m);\n exportOrFail(m, \"after an undo\");\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L6: foreign content survives an import → export round-trip\",\n async run(h) {\n if (h.foreignTexts === undefined) {\n return skip(\"foreignTexts is undefined — pass [] if the notation has no foreign form\");\n }\n if (h.foreignTexts.length === 0) return;\n const m = await h.create();\n try {\n await foreignRoundTrips(h, m, \"\");\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L7: a rejected import leaves no trace\",\n async run(h) {\n if (h.invalidTexts === undefined) {\n return skip(\"invalidTexts is undefined — pass [] if the notation has no non-importable text\");\n }\n if (h.invalidTexts.length === 0) return;\n const m = await h.create();\n try {\n const text = h.canonicalTexts[0] ?? \"\";\n await m.importText(text);\n const beforeEdit = m.exportText();\n // with undo history on the stack: a rejected import must leave it\n // intact too (an engine that erases history BEFORE parsing does not)\n if (h.undo) {\n await h.mutate(m);\n await (h.settle ?? defaultSettle)();\n }\n const doc = m.exportText();\n const ids = sortedIds(m);\n for (const bad of h.invalidTexts) {\n let rejected = false;\n const { calls } = await changeEvents(h, m, () =>\n m.importText(bad).then(\n () => undefined,\n () => {\n rejected = true;\n },\n ),\n );\n if (!rejected) fail(\"importText resolved for a non-importable input — it must REJECT\");\n if (calls > 0) fail(\"a rejected import fired onContentChanged\");\n if (m.exportText() !== doc)\n fail(\"a rejected import changed the document — the previous state must stay intact\");\n if (ids && !same(ids, sortedIds(m))) {\n fail(\n \"a rejected import changed the rendered elements — the canvas must keep the previous document\",\n );\n }\n }\n if (h.undo) {\n await h.undo(m);\n if (m.exportText() !== beforeEdit) {\n fail(\n \"a rejected import erased the undo history — the previous document's history must stay intact\",\n );\n }\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"L7: the modeler stays usable after a rejected import\",\n async run(h) {\n if (h.invalidTexts === undefined) {\n return skip(\"invalidTexts is undefined — pass [] if the notation has no non-importable text\");\n }\n const bad = h.invalidTexts[0];\n if (bad === undefined) return;\n const m = await h.create();\n try {\n await m.importText(h.canonicalTexts[0] ?? \"\");\n await m.importText(bad).then(\n () => fail(\"importText resolved for a non-importable input — it must REJECT\"),\n () => undefined,\n );\n const next = secondText(h);\n await m\n .importText(next)\n .catch((e) => fail(`the next VALID import after a rejection did not render: ${String(e)}`));\n if (m.exportText() !== next)\n fail(\"the next valid import after a rejection did not replace the document\");\n const before = m.exportText();\n const { calls } = await changeEvents(h, m, () => h.mutate(m));\n if (calls === 0) fail(\"a user mutation after a rejected import fired no onContentChanged (wedged)\");\n if (exportOrFail(m, \"after a mutation that followed a rejected import\") === before) {\n fail(\"a user mutation after a rejected import did not apply (wedged)\");\n }\n if (h.undo) {\n await h.undo(m);\n exportOrFail(m, \"after an undo that followed a rejected import\");\n }\n } finally {\n m.destroy();\n }\n },\n },\n {\n name: \"viewer (when shipped): read-only, silent, canonical, fits, reveals, keeps foreign content, unshaken by a rejected import\",\n async run(h) {\n if (!h.createReadonly) return skip(\"createReadonly is undefined — the package ships no viewer mount\");\n const v = await h.createReadonly();\n try {\n if (v.meta.editable !== false)\n fail(\"createReadonly() must return a viewer (meta.editable === false)\");\n try {\n const fresh = v.getViewState();\n if (fresh !== undefined) assertFinite(fresh, \"on the viewer before the first import\");\n } catch (e) {\n fail(`the viewer's getViewState threw before the first import: ${String(e)}`);\n }\n let calls = 0;\n const off = v.onContentChanged(() => {\n calls += 1;\n });\n try {\n for (const text of h.canonicalTexts) {\n await v\n .importText(text)\n .catch((e) => fail(`the viewer rejected a canonical text: ${String(e)}`));\n if (exportOrFail(v, \"on the viewer\") !== text)\n fail(\"the viewer's export is not the canonical text\");\n }\n const doc = v.exportText();\n const ids = sortedIds(v);\n if (v.elements) {\n const firstId = v.elements.list()[0]?.id;\n if (firstId !== undefined) {\n const deliveries: string[][] = [];\n const offSel = v.elements.onSelection((s) => deliveries.push([...s]));\n if (v.elements.reveal(firstId) !== true)\n fail(\"the viewer's reveal(known id) must return true\");\n await (h.settle ?? defaultSettle)();\n if (!deliveries.some((d) => d.includes(firstId)))\n fail(\"the viewer's reveal delivered no selection containing the id\");\n if (!v.elements.selection().includes(firstId))\n fail(\"the viewer's selection() does not contain the revealed id\");\n offSel();\n }\n if (v.elements.reveal(\"__modeler_api_no_such_id__\") !== false)\n fail(\"the viewer's reveal(unknown id) must return false\");\n }\n for (const bad of h.invalidTexts ?? []) {\n await v.importText(bad).then(\n () => fail(\"the viewer resolved a non-importable input — it must REJECT\"),\n () => undefined,\n );\n if (v.exportText() !== doc) fail(\"a rejected import changed the viewer's document\");\n if (ids && !same(ids, sortedIds(v)))\n fail(\"a rejected import changed the viewer's rendered elements\");\n }\n await foreignRoundTrips(h, v, \"the viewer's \");\n if (h.viewState !== undefined) {\n const text = await importContentText(h, v);\n const fitted = v.getViewState();\n assertFinite(fitted, \"on the viewer after import\");\n v.setViewState(h.viewState);\n const applied = v.getViewState();\n if (same(applied, fitted)) fail(\"the viewer's setViewState had no effect\");\n await v.importText(text);\n if (!same(v.getViewState(), fitted))\n fail(\"the viewer's import must leave the view fitted (L5)\");\n v.setViewState(applied);\n if (!same(v.getViewState(), applied))\n fail(\"setting the viewer's own readback did not yield that readback\");\n }\n await (h.settle ?? defaultSettle)();\n if (calls > 0)\n fail(`the viewer fired onContentChanged ${calls}x — a viewer never changes content`);\n } finally {\n off();\n }\n } finally {\n v.destroy();\n v.destroy(); // must not throw — same as the editor\n }\n },\n },\n {\n name: \"destroy is safe to call twice\",\n async run(h) {\n const m = await h.create();\n m.destroy();\n m.destroy(); // must not throw\n },\n },\n ];\n}\n\n/** the L6 foreign-content round-trips, on an editor or a viewer */\nasync function foreignRoundTrips(h: ConformanceHarness, m: CollaborativeModeler, who: string): Promise<void> {\n for (const { text, mustSurvive } of h.foreignTexts ?? []) {\n if (mustSurvive.length === 0) fail(\"a foreignTexts entry must name at least one fragment in mustSurvive\");\n await m.importText(text); // warnings allowed — a throw is the violation\n const first = exportOrFail(m, `${who}after importing a document with foreign content`);\n for (const fragment of mustSurvive) {\n if (!first.includes(fragment))\n fail(`${who}foreign content was dropped on import → export: '${fragment}' is missing`);\n }\n await m.importText(first);\n const second = exportOrFail(m, `${who}after re-importing its own export of foreign content`);\n if (second !== first) fail(`${who}foreign content did not survive a second import → export round-trip`);\n }\n}\n\nexport interface RegisterOptions {\n /** how a SKIPPED case is reported — a law the kit could not (fully) verify\n * because the harness left its field undefined. Default: console.warn */\n onSkip?: (caseName: string, reason: string) => void;\n}\n\n/** bind every case to a (name, fn) test runner — node:test, vitest, jest */\nexport function registerConformance(\n harness: ConformanceHarness,\n test: (name: string, fn: () => Promise<void>) => unknown,\n options: RegisterOptions = {},\n): void {\n const onSkip =\n options.onSkip ??\n ((name: string, reason: string) => {\n console.warn(`modeler-api conformance: SKIPPED \"${name}\" — ${reason}`);\n });\n for (const conformanceCase of conformanceCases()) {\n test(`conformance: ${conformanceCase.name}`, async () => {\n const outcome = await conformanceCase.run(harness);\n if (outcome?.skipped) onSkip(conformanceCase.name, outcome.skipped);\n });\n }\n}\n"],"mappings":";;;;;AAsHO,SAAS,aAAa,QAAQ,KAAK,SAAS,KAAkB;AACnE,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,MAAM,UAAU,SAAS,KAAK,aAAa,MAAM;AACzD,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,MAAM,UAAU;AACrB,UAAQ,OAAO,IAAI;AACnB,WAAS,KAAK,OAAO,OAAO;AAC5B,SAAO;AACT;AAMO,SAAS,sBAAsB,GAAW,GAAoB;AACnE,QAAM,CAAC,SAAS,IAAI,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG;AAC9C,QAAM,CAAC,SAAS,IAAI,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG;AAC9C,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO,WAAW,OAAO,WAAW;AACtC;AAEA,SAAS,KAAK,SAAwB;AACpC,QAAM,IAAI,MAAM,4BAA4B,OAAO,EAAE;AACvD;AAEA,IAAM,OAAO,CAAC,YAAiC,EAAE,SAAS,OAAO;AAEjE,SAAS,aAAa,SAA+B,MAAsB;AACzE,MAAI;AACF,WAAO,QAAQ,WAAW;AAAA,EAC5B,SAAS,GAAG;AACV,SAAK,oBAAoB,IAAI,KAAK,OAAO,CAAC,CAAC,EAAE;AAAA,EAC/C;AACF;AAEA,IAAM,OAAO,CAAC,GAAY,MAAwB,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC;AAGxF,SAAS,aAAa,OAAgB,MAAoB;AACxD,QAAM,OAAO,KAAK;AAAA,IAAU;AAAA,IAAO,CAAC,IAAI,MACtC,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,CAAC,IAAI,mBAAmB;AAAA,EACpE;AACA,MAAI,MAAM,SAAS,gBAAgB,GAAG;AACpC;AAAA,MACE,kBAAkB,IAAI;AAAA,IACxB;AAAA,EACF;AACF;AAEA,IAAM,gBAAgB,MAAqB,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,CAAC,CAAC;AAK1F,eAAe,aACb,SACA,SACA,QAC8D;AAC9D,QAAM,SAAS,QAAQ,UAAU;AACjC,MAAI,QAAQ;AACZ,MAAI;AACJ,QAAM,MAAM,QAAQ,iBAAiB,MAAM;AACzC,aAAS;AACT,mBAAe,QAAQ,WAAW;AAAA,EACpC,CAAC;AACD,MAAI;AACF,UAAM,OAAO;AACb,UAAM,OAAO;AAAA,EACf,UAAE;AACA,QAAI;AAAA,EACN;AACA,SAAO,EAAE,OAAO,aAAa;AAC/B;AAEA,IAAM,aAAa,CAAC,MAAkC,EAAE,eAAe,CAAC,KAAK,EAAE,eAAe,CAAC,KAAK;AAGpG,IAAM,cAAc,CAAC,MAA0C;AAAA,EAC7D,EAAE,MAAM,4BAA4B,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;AAAA,EAC5D,GAAI,EAAE,mBAAmB,CAAC;AAC5B;AAEA,IAAM,YAAY,CAAC,MACjB,EAAE,WAAW,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,KAAK,IAAI;AAOhE,eAAe,kBAAkB,GAAuB,GAA0C;AAChG,aAAW,QAAQ,EAAE,gBAAgB;AACnC,UAAM,EAAE,WAAW,IAAI;AACvB,QAAI,CAAC,EAAE,YAAY,EAAE,SAAS,KAAK,EAAE,SAAS,EAAG,QAAO;AAAA,EAC1D;AACA,OAAK,yGAAoG;AAC3G;AAEO,SAAS,mBAAsC;AACpD,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,cAAI,CAAC,EAAE,KAAK,SAAU,MAAK,wBAAwB;AACnD,cAAI,EAAE,KAAK,aAAa;AACtB,iBAAK,mEAAmE;AAC1E,cAAI,CAAC,sBAAsB,EAAE,KAAK,YAAY,mBAAmB,GAAG;AAClE,iBAAK,cAAc,EAAE,KAAK,UAAU,2BAA2B,mBAAmB,EAAE;AAAA,UACtF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,QAAQ;AAAA,YACZ,GAAG,EAAE;AAAA,YACL,GAAI,EAAE,cAAc,CAAC;AAAA,YACrB,IAAI,EAAE,gBAAgB,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,UAC7C;AACA,qBAAW,QAAQ,OAAO;AACxB,kBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,WAAW,IAAI,EAAE,KAAK,MAAM,MAAS,CAAC;AACzF,gBAAI,QAAQ,EAAG,MAAK,qCAAqC,KAAK,GAAG;AAAA,UACnE;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AAIX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,gBAAM,EAAE,OAAO,CAAC;AAChB,iBAAO,EAAE,UAAU,eAAe;AAClC,gBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,WAAW,WAAW,CAAC,CAAC,EAAE,KAAK,MAAM,MAAS,CAAC;AAClG,cAAI,QAAQ,EAAG,MAAK,mEAAmE,KAAK,GAAG;AAAA,QACjG,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,eAAe,WAAW,EAAG,MAAK,oCAAoC;AAC5E,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,qBAAW,QAAQ,EAAE,gBAAgB;AACnC,kBAAM,EAAE,WAAW,IAAI;AACvB,kBAAM,MAAM,EAAE,WAAW;AACzB,gBAAI,QAAQ;AACV,mBAAK;AAAA;AAAA,EAAkE,IAAI;AAAA;AAAA,EAAc,GAAG,EAAE;AAChG,gBAAI,EAAE,WAAW,MAAM;AACrB,mBAAK,2EAAsE;AAAA,UAC/E;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,eAAe;AACnB,iBAAO,KAAK,0EAAqE;AACnF,YAAI,EAAE,WAAW,WAAW,EAAG;AAC/B,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,qBAAW,QAAQ,EAAE,YAAY;AAC/B,kBAAM,EAAE,WAAW,IAAI;AACvB,kBAAM,YAAY,EAAE,WAAW;AAC/B,kBAAM,EAAE,WAAW,SAAS;AAC5B,kBAAM,QAAQ,EAAE,WAAW;AAC3B,gBAAI,UAAU,UAAW,MAAK,mDAAmD;AAAA,UACnF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,gBAAM,SAAS,EAAE,WAAW;AAC5B,gBAAM,EAAE,OAAO,aAAa,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;AAC1E,cAAI,UAAU,EAAG,MAAK,2CAA2C;AACjE,gBAAM,QAAQ,EAAE,WAAW;AAC3B,cAAI,UAAU;AACZ,iBAAK,+EAA0E;AACjF,cAAI,iBAAiB,OAAO;AAC1B;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,oBAAoB,QAAW;AACnC,iBAAO;AAAA,YACL;AAAA,UACF;AAAA,QACF;AACA,mBAAW,YAAY,EAAE,iBAAiB;AACxC,gBAAM,IAAI,MAAM,EAAE,OAAO;AACzB,cAAI;AACF,kBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,kBAAM,SAAS,EAAE,WAAW;AAC5B,kBAAM,EAAE,OAAO,aAAa,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,SAAS,IAAI,CAAC,CAAC;AAC9E,gBAAI,UAAU,EAAG,MAAK,oBAAoB,SAAS,IAAI,6BAA6B;AACpF,kBAAM,QAAQ,EAAE,WAAW;AAC3B,gBAAI,UAAU,QAAQ;AACpB,mBAAK,oBAAoB,SAAS,IAAI,4DAAuD;AAAA,YAC/F;AACA,gBAAI,iBAAiB,OAAO;AAC1B;AAAA,gBACE,wDAAwD,SAAS,IAAI;AAAA,cACvE;AAAA,YACF;AAAA,UACF,UAAE;AACA,cAAE,QAAQ;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,cAAI,QAAQ;AACZ,gBAAM,MAAM,EAAE,iBAAiB,MAAM;AACnC,qBAAS;AAAA,UACX,CAAC;AACD,cAAI;AACJ,gBAAM,EAAE,OAAO,CAAC;AAChB,iBAAO,EAAE,UAAU,eAAe;AAClC,cAAI,QAAQ,EAAG,MAAK,8CAA8C;AAAA,QACpE,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,CAAC,EAAE,KAAM,QAAO,KAAK,wDAAmD;AAC5E,cAAM,OAAO,EAAE;AACf,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,gBAAM,SAAS,EAAE,WAAW;AAC5B,gBAAM,EAAE,OAAO,CAAC;AAChB,iBAAO,EAAE,UAAU,eAAe;AAClC,gBAAM,UAAU,EAAE,WAAW;AAC7B,gBAAM,SAAS,MAAM,aAAa,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC;AACrD,cAAI,OAAO,UAAU;AACnB,iBAAK,oFAA+E;AACtF,cAAI,EAAE,WAAW,MAAM;AACrB,iBAAK,mEAAmE;AAC1E,cAAI,OAAO,iBAAiB;AAC1B,iBAAK,0EAA0E;AACjF,cAAI,CAAC,EAAE;AACL,mBAAO;AAAA,cACL;AAAA,YACF;AACF,gBAAM,OAAO,EAAE;AACf,gBAAM,SAAS,MAAM,aAAa,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC;AACrD,cAAI,OAAO,UAAU,EAAG,MAAK,gCAAgC;AAC7D,cAAI,EAAE,WAAW,MAAM,QAAS,MAAK,yCAAyC;AAC9E,cAAI,OAAO,iBAAiB;AAC1B,iBAAK,0EAA0E;AAAA,QACnF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,CAAC,EAAE,KAAM,QAAO,KAAK,wDAAmD;AAC5E,cAAM,QAAQ,EAAE,eAAe,CAAC;AAChC,cAAM,SAAS,EAAE,eAAe,CAAC;AACjC,YAAI,UAAU,UAAa,WAAW,UAAa,UAAU,QAAQ;AACnE,eAAK,2FAAsF;AAAA,QAC7F;AACA,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,KAAK;AACxB,gBAAM,EAAE,OAAO,CAAC;AAChB,gBAAM,EAAE,OAAO,CAAC;AAKhB,gBAAM,UAAU,EAAE,WAAW;AAC7B,gBAAM,EAAE,WAAW,OAAO;AAC1B,gBAAM,eAAe,EAAE,WAAW;AAClC,gBAAM,UAAU,UAAU,CAAC;AAC3B,gBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,KAAM,CAAC,CAAC;AAC3D,cAAI,QAAQ;AACV;AAAA,cACE;AAAA,YACF;AACF,cAAI,EAAE,WAAW,MAAM,gBAAiB,WAAW,CAAC,KAAK,SAAS,UAAU,CAAC,CAAC,GAAI;AAChF;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAGA,gBAAM,EAAE,OAAO,CAAC;AAChB,gBAAM,EAAE,WAAW,MAAM;AAGzB,gBAAM,WAAW,EAAE,WAAW;AAC9B,gBAAM,EAAE,KAAK,CAAC;AACd,gBAAM,EAAE,KAAK,CAAC;AACd,cAAI,EAAE,WAAW,MAAM,UAAU;AAC/B,iBAAK,qFAAqF;AAAA,UAC5F;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,cAAI;AACJ,cAAI;AACF,oBAAQ,EAAE,aAAa;AAAA,UACzB,SAAS,GAAG;AACV,iBAAK,+CAA+C,OAAO,CAAC,CAAC,EAAE;AAAA,UACjE;AACA,cAAI,UAAU,OAAW,cAAa,OAAO,yBAAyB;AAAA,QACxE,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,cAAc,QAAW;AAC7B,iBAAO;AAAA,YACL;AAAA,UACF;AAAA,QACF;AACA,cAAM,MAAM,EAAE;AACd,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,OAAO,MAAM,kBAAkB,GAAG,CAAC;AACzC,gBAAM,MAAM,EAAE,WAAW;AACzB,gBAAM,SAAS,EAAE,aAAa;AAC9B,uBAAa,QAAQ,wBAAwB;AAI7C,YAAE,aAAa,GAAG;AAClB,gBAAM,UAAU,EAAE,aAAa;AAC/B,uBAAa,SAAS,oBAAoB;AAC1C,cAAI,KAAK,SAAS,MAAM,GAAG;AACzB,iBAAK,+FAA0F;AAAA,UACjG;AACA,gBAAM,EAAE,WAAW,IAAI;AACvB,cAAI,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG;AACnC;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAGA,gBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,aAAa,OAAO,CAAC;AACxE,cAAI,QAAQ,EAAG,MAAK,+EAA0E;AAC9F,cAAI,EAAE,WAAW,MAAM;AACrB,iBAAK,4EAAuE;AAC9E,cAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,GAAG;AACpC;AAAA,cACE;AAAA,YACF;AAAA,UACF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,OAAO,EAAE,eAAe,CAAC,KAAK;AACpC,gBAAM,EAAE,WAAW,IAAI;AACvB,gBAAM,WAAW,EAAE;AACnB,cAAI,CAAC;AACH,mBAAO,KAAK,6EAAwE;AACtF,gBAAM,MAAM,SAAS,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAC3C,cAAI,IAAI,IAAI,GAAG,EAAE,SAAS,IAAI,OAAQ,MAAK,4BAA4B;AACvE,gBAAM,EAAE,WAAW,IAAI;AACvB,gBAAM,QAAQ,SAAS,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAC7C,cAAI,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC;AAC1C,iBAAK,+DAA+D;AACtE,cAAI,SAAS,OAAO,4BAA4B,MAAM;AACpD,iBAAK,sCAAsC;AAC7C,gBAAM,UAAU,IAAI,CAAC;AACrB,cAAI,YAAY,QAAW;AACzB,kBAAM,aAAyB,CAAC;AAChC,kBAAM,MAAM,SAAS,YAAY,CAAC,aAAa,WAAW,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC;AAC7E,kBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM;AAC/C,kBAAI,SAAS,OAAO,OAAO,MAAM,KAAM,MAAK,mCAAmC;AAAA,YACjF,CAAC;AACD,gBAAI,QAAQ,EAAG,MAAK,8EAAyE;AAC7F,gBAAI,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC,GAAG;AAChD;AAAA,gBACE,WAAW,OAAO;AAAA,cACpB;AAAA,YACF;AACA,uBAAW,KAAK,YAAY;AAC1B,yBAAW,MAAM,GAAG;AAClB,oBAAI,CAAC,MAAM,SAAS,EAAE,GAAG;AACvB;AAAA,oBACE,uDAAuD,EAAE;AAAA,kBAC3D;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AACA,gBAAI,CAAC,SAAS,UAAU,EAAE,SAAS,OAAO,EAAG,MAAK,8CAA8C;AAChG,kBAAM,OAAO,WAAW;AACxB,gBAAI;AAGJ,kBAAM,UAAU,IAAI,CAAC;AACrB,gBAAI,YAAY,OAAW,UAAS,OAAO,OAAO;AAAA,gBAC7C,OAAM,EAAE,OAAO,CAAC;AACrB,mBAAO,EAAE,UAAU,eAAe;AAClC,gBAAI,WAAW,WAAW,KAAM,MAAK,yCAAyC;AAAA,UAChF;AAKA,gBAAM,cAAc,IAAI,IAAI,SAAS,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACtE,gBAAM,EAAE,OAAO,CAAC;AAChB,iBAAO,EAAE,UAAU,eAAe;AAClC,gBAAM,YAAY,IAAI,IAAI,SAAS,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACpE,cAAI,UAAU,QAAQ,YAAY,MAAM;AACtC;AAAA,cACE;AAAA,YACF;AAAA,UACF;AACA,qBAAW,CAAC,IAAI,IAAI,KAAK,aAAa;AACpC,gBAAI,CAAC,UAAU,IAAI,EAAE,GAAG;AACtB;AAAA,gBACE,eAAe,EAAE;AAAA,cACnB;AAAA,YACF;AACA,gBAAI,SAAS,UAAa,UAAU,IAAI,EAAE,MAAM,MAAM;AACpD;AAAA,gBACE,eAAe,EAAE,yDAAyD,IAAI,aAAQ,OAAO,UAAU,IAAI,EAAE,CAAC,CAAC;AAAA,cACjH;AAAA,YACF;AAAA,UACF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,qBAAW,YAAY,YAAY,CAAC,GAAG;AACrC,kBAAM,SAAS,IAAI,CAAC;AACpB,yBAAa,GAAG,SAAS,SAAS,IAAI,EAAE;AAAA,UAC1C;AACA,cAAI,EAAE,MAAM;AACV,kBAAM,EAAE,KAAK,CAAC;AACd,yBAAa,GAAG,eAAe;AAAA,UACjC;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,iBAAiB,QAAW;AAChC,iBAAO,KAAK,8EAAyE;AAAA,QACvF;AACA,YAAI,EAAE,aAAa,WAAW,EAAG;AACjC,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,kBAAkB,GAAG,GAAG,EAAE;AAAA,QAClC,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,iBAAiB,QAAW;AAChC,iBAAO,KAAK,qFAAgF;AAAA,QAC9F;AACA,YAAI,EAAE,aAAa,WAAW,EAAG;AACjC,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,OAAO,EAAE,eAAe,CAAC,KAAK;AACpC,gBAAM,EAAE,WAAW,IAAI;AACvB,gBAAM,aAAa,EAAE,WAAW;AAGhC,cAAI,EAAE,MAAM;AACV,kBAAM,EAAE,OAAO,CAAC;AAChB,mBAAO,EAAE,UAAU,eAAe;AAAA,UACpC;AACA,gBAAM,MAAM,EAAE,WAAW;AACzB,gBAAM,MAAM,UAAU,CAAC;AACvB,qBAAW,OAAO,EAAE,cAAc;AAChC,gBAAI,WAAW;AACf,kBAAM,EAAE,MAAM,IAAI,MAAM;AAAA,cAAa;AAAA,cAAG;AAAA,cAAG,MACzC,EAAE,WAAW,GAAG,EAAE;AAAA,gBAChB,MAAM;AAAA,gBACN,MAAM;AACJ,6BAAW;AAAA,gBACb;AAAA,cACF;AAAA,YACF;AACA,gBAAI,CAAC,SAAU,MAAK,sEAAiE;AACrF,gBAAI,QAAQ,EAAG,MAAK,0CAA0C;AAC9D,gBAAI,EAAE,WAAW,MAAM;AACrB,mBAAK,mFAA8E;AACrF,gBAAI,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,GAAG;AACnC;AAAA,gBACE;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,cAAI,EAAE,MAAM;AACV,kBAAM,EAAE,KAAK,CAAC;AACd,gBAAI,EAAE,WAAW,MAAM,YAAY;AACjC;AAAA,gBACE;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,EAAE,iBAAiB,QAAW;AAChC,iBAAO,KAAK,qFAAgF;AAAA,QAC9F;AACA,cAAM,MAAM,EAAE,aAAa,CAAC;AAC5B,YAAI,QAAQ,OAAW;AACvB,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,YAAI;AACF,gBAAM,EAAE,WAAW,EAAE,eAAe,CAAC,KAAK,EAAE;AAC5C,gBAAM,EAAE,WAAW,GAAG,EAAE;AAAA,YACtB,MAAM,KAAK,sEAAiE;AAAA,YAC5E,MAAM;AAAA,UACR;AACA,gBAAM,OAAO,WAAW,CAAC;AACzB,gBAAM,EACH,WAAW,IAAI,EACf,MAAM,CAAC,MAAM,KAAK,2DAA2D,OAAO,CAAC,CAAC,EAAE,CAAC;AAC5F,cAAI,EAAE,WAAW,MAAM;AACrB,iBAAK,sEAAsE;AAC7E,gBAAM,SAAS,EAAE,WAAW;AAC5B,gBAAM,EAAE,MAAM,IAAI,MAAM,aAAa,GAAG,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;AAC5D,cAAI,UAAU,EAAG,MAAK,4EAA4E;AAClG,cAAI,aAAa,GAAG,kDAAkD,MAAM,QAAQ;AAClF,iBAAK,gEAAgE;AAAA,UACvE;AACA,cAAI,EAAE,MAAM;AACV,kBAAM,EAAE,KAAK,CAAC;AACd,yBAAa,GAAG,+CAA+C;AAAA,UACjE;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,YAAI,CAAC,EAAE,eAAgB,QAAO,KAAK,sEAAiE;AACpG,cAAM,IAAI,MAAM,EAAE,eAAe;AACjC,YAAI;AACF,cAAI,EAAE,KAAK,aAAa;AACtB,iBAAK,iEAAiE;AACxE,cAAI;AACF,kBAAM,QAAQ,EAAE,aAAa;AAC7B,gBAAI,UAAU,OAAW,cAAa,OAAO,uCAAuC;AAAA,UACtF,SAAS,GAAG;AACV,iBAAK,4DAA4D,OAAO,CAAC,CAAC,EAAE;AAAA,UAC9E;AACA,cAAI,QAAQ;AACZ,gBAAM,MAAM,EAAE,iBAAiB,MAAM;AACnC,qBAAS;AAAA,UACX,CAAC;AACD,cAAI;AACF,uBAAW,QAAQ,EAAE,gBAAgB;AACnC,oBAAM,EACH,WAAW,IAAI,EACf,MAAM,CAAC,MAAM,KAAK,yCAAyC,OAAO,CAAC,CAAC,EAAE,CAAC;AAC1E,kBAAI,aAAa,GAAG,eAAe,MAAM;AACvC,qBAAK,+CAA+C;AAAA,YACxD;AACA,kBAAM,MAAM,EAAE,WAAW;AACzB,kBAAM,MAAM,UAAU,CAAC;AACvB,gBAAI,EAAE,UAAU;AACd,oBAAM,UAAU,EAAE,SAAS,KAAK,EAAE,CAAC,GAAG;AACtC,kBAAI,YAAY,QAAW;AACzB,sBAAM,aAAyB,CAAC;AAChC,sBAAM,SAAS,EAAE,SAAS,YAAY,CAAC,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACpE,oBAAI,EAAE,SAAS,OAAO,OAAO,MAAM;AACjC,uBAAK,gDAAgD;AACvD,uBAAO,EAAE,UAAU,eAAe;AAClC,oBAAI,CAAC,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC;AAC7C,uBAAK,8DAA8D;AACrE,oBAAI,CAAC,EAAE,SAAS,UAAU,EAAE,SAAS,OAAO;AAC1C,uBAAK,2DAA2D;AAClE,uBAAO;AAAA,cACT;AACA,kBAAI,EAAE,SAAS,OAAO,4BAA4B,MAAM;AACtD,qBAAK,mDAAmD;AAAA,YAC5D;AACA,uBAAW,OAAO,EAAE,gBAAgB,CAAC,GAAG;AACtC,oBAAM,EAAE,WAAW,GAAG,EAAE;AAAA,gBACtB,MAAM,KAAK,kEAA6D;AAAA,gBACxE,MAAM;AAAA,cACR;AACA,kBAAI,EAAE,WAAW,MAAM,IAAK,MAAK,iDAAiD;AAClF,kBAAI,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;AAChC,qBAAK,0DAA0D;AAAA,YACnE;AACA,kBAAM,kBAAkB,GAAG,GAAG,eAAe;AAC7C,gBAAI,EAAE,cAAc,QAAW;AAC7B,oBAAM,OAAO,MAAM,kBAAkB,GAAG,CAAC;AACzC,oBAAM,SAAS,EAAE,aAAa;AAC9B,2BAAa,QAAQ,4BAA4B;AACjD,gBAAE,aAAa,EAAE,SAAS;AAC1B,oBAAM,UAAU,EAAE,aAAa;AAC/B,kBAAI,KAAK,SAAS,MAAM,EAAG,MAAK,yCAAyC;AACzE,oBAAM,EAAE,WAAW,IAAI;AACvB,kBAAI,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM;AAChC,qBAAK,qDAAqD;AAC5D,gBAAE,aAAa,OAAO;AACtB,kBAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;AACjC,qBAAK,+DAA+D;AAAA,YACxE;AACA,mBAAO,EAAE,UAAU,eAAe;AAClC,gBAAI,QAAQ;AACV,mBAAK,qCAAqC,KAAK,yCAAoC;AAAA,UACvF,UAAE;AACA,gBAAI;AAAA,UACN;AAAA,QACF,UAAE;AACA,YAAE,QAAQ;AACV,YAAE,QAAQ;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,MAAM,IAAI,GAAG;AACX,cAAM,IAAI,MAAM,EAAE,OAAO;AACzB,UAAE,QAAQ;AACV,UAAE,QAAQ;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AACF;AAGA,eAAe,kBAAkB,GAAuB,GAAyB,KAA4B;AAC3G,aAAW,EAAE,MAAM,YAAY,KAAK,EAAE,gBAAgB,CAAC,GAAG;AACxD,QAAI,YAAY,WAAW,EAAG,MAAK,qEAAqE;AACxG,UAAM,EAAE,WAAW,IAAI;AACvB,UAAM,QAAQ,aAAa,GAAG,GAAG,GAAG,iDAAiD;AACrF,eAAW,YAAY,aAAa;AAClC,UAAI,CAAC,MAAM,SAAS,QAAQ;AAC1B,aAAK,GAAG,GAAG,yDAAoD,QAAQ,cAAc;AAAA,IACzF;AACA,UAAM,EAAE,WAAW,KAAK;AACxB,UAAM,SAAS,aAAa,GAAG,GAAG,GAAG,sDAAsD;AAC3F,QAAI,WAAW,MAAO,MAAK,GAAG,GAAG,0EAAqE;AAAA,EACxG;AACF;AASO,SAAS,oBACd,SACA,MACA,UAA2B,CAAC,GACtB;AACN,QAAM,SACJ,QAAQ,WACP,CAAC,MAAc,WAAmB;AACjC,YAAQ,KAAK,qCAAqC,IAAI,YAAO,MAAM,EAAE;AAAA,EACvE;AACF,aAAW,mBAAmB,iBAAiB,GAAG;AAChD,SAAK,gBAAgB,gBAAgB,IAAI,IAAI,YAAY;AACvD,YAAM,UAAU,MAAM,gBAAgB,IAAI,OAAO;AACjD,UAAI,SAAS,QAAS,QAAO,gBAAgB,MAAM,QAAQ,OAAO;AAAA,IACpE,CAAC;AAAA,EACH;AACF;","names":[]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
MODELER_API_VERSION: () => MODELER_API_VERSION
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var MODELER_API_VERSION = "1.0.0";
|
|
27
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
28
|
+
0 && (module.exports = {
|
|
29
|
+
MODELER_API_VERSION
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @miragon/modeler-api — ONE interface every Miragon modeler implements.\n *\n * The contract encodes, as REQUIREMENTS, the behavioral drift that had to be\n * discovered per modeler against engine internals before it existed:\n * an `importDSL` that emitted change events (rewriting hand-authored files on\n * open), an import that left the undo stack on stale removed shapes, a\n * serializer that was not a byte fixpoint. A host embedding a conforming\n * modeler needs no per-engine suppression tricks — the laws below hold.\n *\n * The conformance test kit (`@miragon/modeler-api/conformance`) turns each\n * law into an executable case the modeler repo runs in its own CI.\n */\n\n/** the semver of THIS contract — a modeler declares the version it implements\n * in `meta.apiVersion`; hosts check compatibility with `apiVersionsCompatible`\n * (same major; while 0.x, the same minor too). The constant IS the\n * package version: release-please rewrites the literal below on every\n * release (release-please-config.json `extra-files`), and the kit's own\n * test pins it to package.json exactly. Modelers pin the npm package; the\n * constant is what travels in `meta`. */\nexport const MODELER_API_VERSION = \"1.0.0\"; // x-release-please-version\n\nexport interface ModelerMeta {\n /** stable notation id, e.g. \"wardley\", \"team-topology\", \"event-storming\" */\n readonly notation: string;\n /** the MODELER_API_VERSION this modeler implements — compatible when the\n * major matches and, while the contract is 0.x, the minor too (pre-1.0\n * minors may break: bump-minor-pre-major) */\n readonly apiVersion: string;\n /**\n * true on an editing mount (the package's Modeler), false on a VIEWER\n * (its NavigatedViewer/Viewer): a viewer never fires `onContentChanged`,\n * accepts no user commands, and still imports, exports, reveals and\n * reports view state exactly like the editor — hosts mount it on\n * read-only surfaces (an MCP-App widget in read-only mode) without\n * per-package knowledge or a command-stack shim.\n */\n readonly editable: boolean;\n}\n\nexport interface ImportResult {\n /** non-fatal notes from the import (unknown lines kept, migrations run) */\n warnings: string[];\n}\n\nexport interface ElementInfo {\n /**\n * stable element id — identical across re-imports of the same text AND\n * untouched by edits to OTHER elements: hosts anchor todos, presence and\n * `?element=` deep links to it, so an id that renumbers when a line is\n * inserted above (positional edge ids) breaks every anchor below it. An\n * element without an id in the text gets one the serializer WRITES BACK.\n */\n id: string;\n /** human label, when the notation has one */\n name?: string;\n}\n\n/**\n * Optional element surface — what a host needs for anchored todos, `?element=`\n * deep links and the selection half of live presence. Absent = the notation\n * has no addressable element identity. Ids are ELEMENT ids throughout: a\n * shape that only labels another element (diagram-js external labels) is\n * reported and revealed as its target, never under its own label id.\n */\nexport interface ElementsSurface {\n /** every addressable element currently on the canvas */\n list(): ElementInfo[];\n /** select + scroll the element into view; false when the id is unknown.\n * Revealing is view behavior: it delivers a selection, never a change event */\n reveal(id: string): boolean;\n /** the current selection as stable element ids — synchronous, so a host\n * can read it at the moment of a click (a deep link carrying the\n * selection) without caching every delivery */\n selection(): string[];\n /** selection changes as STABLE element ids; returns the unsubscribe */\n onSelection(cb: (ids: string[]) => void): () => void;\n}\n\n/**\n * The collaborative-modeler contract. The LAWS (verified by the conformance\n * kit) are part of the interface:\n *\n * L1 SILENT IMPORT — `importText` never fires `onContentChanged` and erases\n * the undo history without emitting — also when history exists. Hosts\n * re-import remote states on every sync; an import echo would re-export\n * the canonical serialization over half-typed peer text.\n * L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:\n * with c = exportText() after importText(t), importText(c) followed by\n * exportText() returns c byte-for-byte. Canonicalization is idempotent;\n * opening a file never rewrites it.\n * L3 ONE CHANGE EVENT — every user-visible atomic change (element commands\n * AND config/axis/title/style edits that live in the document, AND\n * undo/redo) fires `onContentChanged` at least once, and nothing else\n * does: not `importText`, not undo-history housekeeping, not view or\n * selection changes. When a listener runs, `exportText()` ALREADY\n * returns the post-change serialization — hosts export inside the\n * listener; an emit-before-apply would lose the last edit.\n * L4 DEFINED UNDO ACROSS IMPORTS — undo directly after an `importText` is a\n * no-op: it must never mutate or resurrect shapes from the pre-import\n * document (id coincidence included).\n * L5 VIEW-STATE ROUND-TRIP — `getViewState`/`setViewState` survive a\n * re-import: snapshot before, restore after, viewport unchanged. An\n * import leaves the view FITTED to the content (the defined post-import\n * view, the same for the same document and host — a host that wants to\n * keep the user's viewport across a remote re-import snapshots before\n * and restores after); before the first import `getViewState()` returns\n * `undefined` or a state `setViewState` accepts, and never throws. The\n * readback may be a NORMALISED form of what was set (a diagram-js\n * viewbox comes back rounded, with scale/inner/outer) — what must hold\n * is that setting a readback yields that readback again.\n * L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any\n * sequence of user commands and undos), `exportText` succeeds. Foreign or\n * auxiliary content the modeler does not understand is PRESERVED through\n * import → export (it comes back in the export, canonicalised like the\n * rest), never dropped and never a reason to throw.\n * L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text\n * REJECTS (resolve-with-warnings means \"imported, with notes\"; rejection\n * means \"nothing imported\"): afterwards the previously imported document\n * is still rendered with its elements, `exportText` still returns it, no\n * change event has fired and the undo history is untouched.\n * The modeler stays USABLE: the next valid import renders, the next user\n * command applies. Hosts re-import half-typed peer text on every sync —\n * \"blank (or wedged) until healed\" is not an acceptable failure mode.\n *\n * View state is NEVER part of the document: `setViewState` fires no change\n * events and `exportText` is independent of it.\n */\nexport interface CollaborativeModeler {\n readonly meta: ModelerMeta;\n\n /** mount the canvas into a host element (once, before the first import).\n * The host must be attached to the document with a non-zero size — a\n * detached or 0×0 element gives diagram-js engines NaN viewboxes */\n attachTo(host: Element): void;\n\n /** parse + render `text` — SILENT per L1, the view fitted to the content\n * per L5; resolves when rendered, REJECTS when nothing was imported (L7) */\n importText(text: string): Promise<ImportResult>;\n\n /** the canonical serialization of the current document (L2, L6) */\n exportText(): string;\n\n /** subscribe to user-visible model changes (L3); returns the unsubscribe */\n onContentChanged(cb: () => void): () => void;\n\n /** opaque viewport snapshot (zoom/scroll) — JSON-serializable (L5) */\n getViewState(): unknown;\n setViewState(state: unknown): void;\n\n readonly elements?: ElementsSurface;\n\n /** tear down DOM + listeners; further calls on the instance are undefined\n * behavior, but a second destroy() must not throw */\n destroy(): void;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,IAAM,sBAAsB;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @miragon/modeler-api — ONE interface every Miragon modeler implements.
|
|
3
|
+
*
|
|
4
|
+
* The contract encodes, as REQUIREMENTS, the behavioral drift that had to be
|
|
5
|
+
* discovered per modeler against engine internals before it existed:
|
|
6
|
+
* an `importDSL` that emitted change events (rewriting hand-authored files on
|
|
7
|
+
* open), an import that left the undo stack on stale removed shapes, a
|
|
8
|
+
* serializer that was not a byte fixpoint. A host embedding a conforming
|
|
9
|
+
* modeler needs no per-engine suppression tricks — the laws below hold.
|
|
10
|
+
*
|
|
11
|
+
* The conformance test kit (`@miragon/modeler-api/conformance`) turns each
|
|
12
|
+
* law into an executable case the modeler repo runs in its own CI.
|
|
13
|
+
*/
|
|
14
|
+
/** the semver of THIS contract — a modeler declares the version it implements
|
|
15
|
+
* in `meta.apiVersion`; hosts check compatibility with `apiVersionsCompatible`
|
|
16
|
+
* (same major; while 0.x, the same minor too). The constant IS the
|
|
17
|
+
* package version: release-please rewrites the literal below on every
|
|
18
|
+
* release (release-please-config.json `extra-files`), and the kit's own
|
|
19
|
+
* test pins it to package.json exactly. Modelers pin the npm package; the
|
|
20
|
+
* constant is what travels in `meta`. */
|
|
21
|
+
declare const MODELER_API_VERSION = "1.0.0";
|
|
22
|
+
interface ModelerMeta {
|
|
23
|
+
/** stable notation id, e.g. "wardley", "team-topology", "event-storming" */
|
|
24
|
+
readonly notation: string;
|
|
25
|
+
/** the MODELER_API_VERSION this modeler implements — compatible when the
|
|
26
|
+
* major matches and, while the contract is 0.x, the minor too (pre-1.0
|
|
27
|
+
* minors may break: bump-minor-pre-major) */
|
|
28
|
+
readonly apiVersion: string;
|
|
29
|
+
/**
|
|
30
|
+
* true on an editing mount (the package's Modeler), false on a VIEWER
|
|
31
|
+
* (its NavigatedViewer/Viewer): a viewer never fires `onContentChanged`,
|
|
32
|
+
* accepts no user commands, and still imports, exports, reveals and
|
|
33
|
+
* reports view state exactly like the editor — hosts mount it on
|
|
34
|
+
* read-only surfaces (an MCP-App widget in read-only mode) without
|
|
35
|
+
* per-package knowledge or a command-stack shim.
|
|
36
|
+
*/
|
|
37
|
+
readonly editable: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface ImportResult {
|
|
40
|
+
/** non-fatal notes from the import (unknown lines kept, migrations run) */
|
|
41
|
+
warnings: string[];
|
|
42
|
+
}
|
|
43
|
+
interface ElementInfo {
|
|
44
|
+
/**
|
|
45
|
+
* stable element id — identical across re-imports of the same text AND
|
|
46
|
+
* untouched by edits to OTHER elements: hosts anchor todos, presence and
|
|
47
|
+
* `?element=` deep links to it, so an id that renumbers when a line is
|
|
48
|
+
* inserted above (positional edge ids) breaks every anchor below it. An
|
|
49
|
+
* element without an id in the text gets one the serializer WRITES BACK.
|
|
50
|
+
*/
|
|
51
|
+
id: string;
|
|
52
|
+
/** human label, when the notation has one */
|
|
53
|
+
name?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Optional element surface — what a host needs for anchored todos, `?element=`
|
|
57
|
+
* deep links and the selection half of live presence. Absent = the notation
|
|
58
|
+
* has no addressable element identity. Ids are ELEMENT ids throughout: a
|
|
59
|
+
* shape that only labels another element (diagram-js external labels) is
|
|
60
|
+
* reported and revealed as its target, never under its own label id.
|
|
61
|
+
*/
|
|
62
|
+
interface ElementsSurface {
|
|
63
|
+
/** every addressable element currently on the canvas */
|
|
64
|
+
list(): ElementInfo[];
|
|
65
|
+
/** select + scroll the element into view; false when the id is unknown.
|
|
66
|
+
* Revealing is view behavior: it delivers a selection, never a change event */
|
|
67
|
+
reveal(id: string): boolean;
|
|
68
|
+
/** the current selection as stable element ids — synchronous, so a host
|
|
69
|
+
* can read it at the moment of a click (a deep link carrying the
|
|
70
|
+
* selection) without caching every delivery */
|
|
71
|
+
selection(): string[];
|
|
72
|
+
/** selection changes as STABLE element ids; returns the unsubscribe */
|
|
73
|
+
onSelection(cb: (ids: string[]) => void): () => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The collaborative-modeler contract. The LAWS (verified by the conformance
|
|
77
|
+
* kit) are part of the interface:
|
|
78
|
+
*
|
|
79
|
+
* L1 SILENT IMPORT — `importText` never fires `onContentChanged` and erases
|
|
80
|
+
* the undo history without emitting — also when history exists. Hosts
|
|
81
|
+
* re-import remote states on every sync; an import echo would re-export
|
|
82
|
+
* the canonical serialization over half-typed peer text.
|
|
83
|
+
* L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:
|
|
84
|
+
* with c = exportText() after importText(t), importText(c) followed by
|
|
85
|
+
* exportText() returns c byte-for-byte. Canonicalization is idempotent;
|
|
86
|
+
* opening a file never rewrites it.
|
|
87
|
+
* L3 ONE CHANGE EVENT — every user-visible atomic change (element commands
|
|
88
|
+
* AND config/axis/title/style edits that live in the document, AND
|
|
89
|
+
* undo/redo) fires `onContentChanged` at least once, and nothing else
|
|
90
|
+
* does: not `importText`, not undo-history housekeeping, not view or
|
|
91
|
+
* selection changes. When a listener runs, `exportText()` ALREADY
|
|
92
|
+
* returns the post-change serialization — hosts export inside the
|
|
93
|
+
* listener; an emit-before-apply would lose the last edit.
|
|
94
|
+
* L4 DEFINED UNDO ACROSS IMPORTS — undo directly after an `importText` is a
|
|
95
|
+
* no-op: it must never mutate or resurrect shapes from the pre-import
|
|
96
|
+
* document (id coincidence included).
|
|
97
|
+
* L5 VIEW-STATE ROUND-TRIP — `getViewState`/`setViewState` survive a
|
|
98
|
+
* re-import: snapshot before, restore after, viewport unchanged. An
|
|
99
|
+
* import leaves the view FITTED to the content (the defined post-import
|
|
100
|
+
* view, the same for the same document and host — a host that wants to
|
|
101
|
+
* keep the user's viewport across a remote re-import snapshots before
|
|
102
|
+
* and restores after); before the first import `getViewState()` returns
|
|
103
|
+
* `undefined` or a state `setViewState` accepts, and never throws. The
|
|
104
|
+
* readback may be a NORMALISED form of what was set (a diagram-js
|
|
105
|
+
* viewbox comes back rounded, with scale/inner/outer) — what must hold
|
|
106
|
+
* is that setting a readback yields that readback again.
|
|
107
|
+
* L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any
|
|
108
|
+
* sequence of user commands and undos), `exportText` succeeds. Foreign or
|
|
109
|
+
* auxiliary content the modeler does not understand is PRESERVED through
|
|
110
|
+
* import → export (it comes back in the export, canonicalised like the
|
|
111
|
+
* rest), never dropped and never a reason to throw.
|
|
112
|
+
* L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text
|
|
113
|
+
* REJECTS (resolve-with-warnings means "imported, with notes"; rejection
|
|
114
|
+
* means "nothing imported"): afterwards the previously imported document
|
|
115
|
+
* is still rendered with its elements, `exportText` still returns it, no
|
|
116
|
+
* change event has fired and the undo history is untouched.
|
|
117
|
+
* The modeler stays USABLE: the next valid import renders, the next user
|
|
118
|
+
* command applies. Hosts re-import half-typed peer text on every sync —
|
|
119
|
+
* "blank (or wedged) until healed" is not an acceptable failure mode.
|
|
120
|
+
*
|
|
121
|
+
* View state is NEVER part of the document: `setViewState` fires no change
|
|
122
|
+
* events and `exportText` is independent of it.
|
|
123
|
+
*/
|
|
124
|
+
interface CollaborativeModeler {
|
|
125
|
+
readonly meta: ModelerMeta;
|
|
126
|
+
/** mount the canvas into a host element (once, before the first import).
|
|
127
|
+
* The host must be attached to the document with a non-zero size — a
|
|
128
|
+
* detached or 0×0 element gives diagram-js engines NaN viewboxes */
|
|
129
|
+
attachTo(host: Element): void;
|
|
130
|
+
/** parse + render `text` — SILENT per L1, the view fitted to the content
|
|
131
|
+
* per L5; resolves when rendered, REJECTS when nothing was imported (L7) */
|
|
132
|
+
importText(text: string): Promise<ImportResult>;
|
|
133
|
+
/** the canonical serialization of the current document (L2, L6) */
|
|
134
|
+
exportText(): string;
|
|
135
|
+
/** subscribe to user-visible model changes (L3); returns the unsubscribe */
|
|
136
|
+
onContentChanged(cb: () => void): () => void;
|
|
137
|
+
/** opaque viewport snapshot (zoom/scroll) — JSON-serializable (L5) */
|
|
138
|
+
getViewState(): unknown;
|
|
139
|
+
setViewState(state: unknown): void;
|
|
140
|
+
readonly elements?: ElementsSurface;
|
|
141
|
+
/** tear down DOM + listeners; further calls on the instance are undefined
|
|
142
|
+
* behavior, but a second destroy() must not throw */
|
|
143
|
+
destroy(): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { type CollaborativeModeler, type ElementInfo, type ElementsSurface, type ImportResult, MODELER_API_VERSION, type ModelerMeta };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @miragon/modeler-api — ONE interface every Miragon modeler implements.
|
|
3
|
+
*
|
|
4
|
+
* The contract encodes, as REQUIREMENTS, the behavioral drift that had to be
|
|
5
|
+
* discovered per modeler against engine internals before it existed:
|
|
6
|
+
* an `importDSL` that emitted change events (rewriting hand-authored files on
|
|
7
|
+
* open), an import that left the undo stack on stale removed shapes, a
|
|
8
|
+
* serializer that was not a byte fixpoint. A host embedding a conforming
|
|
9
|
+
* modeler needs no per-engine suppression tricks — the laws below hold.
|
|
10
|
+
*
|
|
11
|
+
* The conformance test kit (`@miragon/modeler-api/conformance`) turns each
|
|
12
|
+
* law into an executable case the modeler repo runs in its own CI.
|
|
13
|
+
*/
|
|
14
|
+
/** the semver of THIS contract — a modeler declares the version it implements
|
|
15
|
+
* in `meta.apiVersion`; hosts check compatibility with `apiVersionsCompatible`
|
|
16
|
+
* (same major; while 0.x, the same minor too). The constant IS the
|
|
17
|
+
* package version: release-please rewrites the literal below on every
|
|
18
|
+
* release (release-please-config.json `extra-files`), and the kit's own
|
|
19
|
+
* test pins it to package.json exactly. Modelers pin the npm package; the
|
|
20
|
+
* constant is what travels in `meta`. */
|
|
21
|
+
declare const MODELER_API_VERSION = "1.0.0";
|
|
22
|
+
interface ModelerMeta {
|
|
23
|
+
/** stable notation id, e.g. "wardley", "team-topology", "event-storming" */
|
|
24
|
+
readonly notation: string;
|
|
25
|
+
/** the MODELER_API_VERSION this modeler implements — compatible when the
|
|
26
|
+
* major matches and, while the contract is 0.x, the minor too (pre-1.0
|
|
27
|
+
* minors may break: bump-minor-pre-major) */
|
|
28
|
+
readonly apiVersion: string;
|
|
29
|
+
/**
|
|
30
|
+
* true on an editing mount (the package's Modeler), false on a VIEWER
|
|
31
|
+
* (its NavigatedViewer/Viewer): a viewer never fires `onContentChanged`,
|
|
32
|
+
* accepts no user commands, and still imports, exports, reveals and
|
|
33
|
+
* reports view state exactly like the editor — hosts mount it on
|
|
34
|
+
* read-only surfaces (an MCP-App widget in read-only mode) without
|
|
35
|
+
* per-package knowledge or a command-stack shim.
|
|
36
|
+
*/
|
|
37
|
+
readonly editable: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface ImportResult {
|
|
40
|
+
/** non-fatal notes from the import (unknown lines kept, migrations run) */
|
|
41
|
+
warnings: string[];
|
|
42
|
+
}
|
|
43
|
+
interface ElementInfo {
|
|
44
|
+
/**
|
|
45
|
+
* stable element id — identical across re-imports of the same text AND
|
|
46
|
+
* untouched by edits to OTHER elements: hosts anchor todos, presence and
|
|
47
|
+
* `?element=` deep links to it, so an id that renumbers when a line is
|
|
48
|
+
* inserted above (positional edge ids) breaks every anchor below it. An
|
|
49
|
+
* element without an id in the text gets one the serializer WRITES BACK.
|
|
50
|
+
*/
|
|
51
|
+
id: string;
|
|
52
|
+
/** human label, when the notation has one */
|
|
53
|
+
name?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Optional element surface — what a host needs for anchored todos, `?element=`
|
|
57
|
+
* deep links and the selection half of live presence. Absent = the notation
|
|
58
|
+
* has no addressable element identity. Ids are ELEMENT ids throughout: a
|
|
59
|
+
* shape that only labels another element (diagram-js external labels) is
|
|
60
|
+
* reported and revealed as its target, never under its own label id.
|
|
61
|
+
*/
|
|
62
|
+
interface ElementsSurface {
|
|
63
|
+
/** every addressable element currently on the canvas */
|
|
64
|
+
list(): ElementInfo[];
|
|
65
|
+
/** select + scroll the element into view; false when the id is unknown.
|
|
66
|
+
* Revealing is view behavior: it delivers a selection, never a change event */
|
|
67
|
+
reveal(id: string): boolean;
|
|
68
|
+
/** the current selection as stable element ids — synchronous, so a host
|
|
69
|
+
* can read it at the moment of a click (a deep link carrying the
|
|
70
|
+
* selection) without caching every delivery */
|
|
71
|
+
selection(): string[];
|
|
72
|
+
/** selection changes as STABLE element ids; returns the unsubscribe */
|
|
73
|
+
onSelection(cb: (ids: string[]) => void): () => void;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The collaborative-modeler contract. The LAWS (verified by the conformance
|
|
77
|
+
* kit) are part of the interface:
|
|
78
|
+
*
|
|
79
|
+
* L1 SILENT IMPORT — `importText` never fires `onContentChanged` and erases
|
|
80
|
+
* the undo history without emitting — also when history exists. Hosts
|
|
81
|
+
* re-import remote states on every sync; an import echo would re-export
|
|
82
|
+
* the canonical serialization over half-typed peer text.
|
|
83
|
+
* L2 CANONICAL FIXPOINT — `exportText` is deterministic, and for any text t:
|
|
84
|
+
* with c = exportText() after importText(t), importText(c) followed by
|
|
85
|
+
* exportText() returns c byte-for-byte. Canonicalization is idempotent;
|
|
86
|
+
* opening a file never rewrites it.
|
|
87
|
+
* L3 ONE CHANGE EVENT — every user-visible atomic change (element commands
|
|
88
|
+
* AND config/axis/title/style edits that live in the document, AND
|
|
89
|
+
* undo/redo) fires `onContentChanged` at least once, and nothing else
|
|
90
|
+
* does: not `importText`, not undo-history housekeeping, not view or
|
|
91
|
+
* selection changes. When a listener runs, `exportText()` ALREADY
|
|
92
|
+
* returns the post-change serialization — hosts export inside the
|
|
93
|
+
* listener; an emit-before-apply would lose the last edit.
|
|
94
|
+
* L4 DEFINED UNDO ACROSS IMPORTS — undo directly after an `importText` is a
|
|
95
|
+
* no-op: it must never mutate or resurrect shapes from the pre-import
|
|
96
|
+
* document (id coincidence included).
|
|
97
|
+
* L5 VIEW-STATE ROUND-TRIP — `getViewState`/`setViewState` survive a
|
|
98
|
+
* re-import: snapshot before, restore after, viewport unchanged. An
|
|
99
|
+
* import leaves the view FITTED to the content (the defined post-import
|
|
100
|
+
* view, the same for the same document and host — a host that wants to
|
|
101
|
+
* keep the user's viewport across a remote re-import snapshots before
|
|
102
|
+
* and restores after); before the first import `getViewState()` returns
|
|
103
|
+
* `undefined` or a state `setViewState` accepts, and never throws. The
|
|
104
|
+
* readback may be a NORMALISED form of what was set (a diagram-js
|
|
105
|
+
* viewbox comes back rounded, with scale/inner/outer) — what must hold
|
|
106
|
+
* is that setting a readback yields that readback again.
|
|
107
|
+
* L6 EXPORT IS TOTAL AFTER IMPORT — after a successful import (and any
|
|
108
|
+
* sequence of user commands and undos), `exportText` succeeds. Foreign or
|
|
109
|
+
* auxiliary content the modeler does not understand is PRESERVED through
|
|
110
|
+
* import → export (it comes back in the export, canonicalised like the
|
|
111
|
+
* rest), never dropped and never a reason to throw.
|
|
112
|
+
* L7 REJECTED IMPORTS LEAVE NO TRACE — `importText` on non-importable text
|
|
113
|
+
* REJECTS (resolve-with-warnings means "imported, with notes"; rejection
|
|
114
|
+
* means "nothing imported"): afterwards the previously imported document
|
|
115
|
+
* is still rendered with its elements, `exportText` still returns it, no
|
|
116
|
+
* change event has fired and the undo history is untouched.
|
|
117
|
+
* The modeler stays USABLE: the next valid import renders, the next user
|
|
118
|
+
* command applies. Hosts re-import half-typed peer text on every sync —
|
|
119
|
+
* "blank (or wedged) until healed" is not an acceptable failure mode.
|
|
120
|
+
*
|
|
121
|
+
* View state is NEVER part of the document: `setViewState` fires no change
|
|
122
|
+
* events and `exportText` is independent of it.
|
|
123
|
+
*/
|
|
124
|
+
interface CollaborativeModeler {
|
|
125
|
+
readonly meta: ModelerMeta;
|
|
126
|
+
/** mount the canvas into a host element (once, before the first import).
|
|
127
|
+
* The host must be attached to the document with a non-zero size — a
|
|
128
|
+
* detached or 0×0 element gives diagram-js engines NaN viewboxes */
|
|
129
|
+
attachTo(host: Element): void;
|
|
130
|
+
/** parse + render `text` — SILENT per L1, the view fitted to the content
|
|
131
|
+
* per L5; resolves when rendered, REJECTS when nothing was imported (L7) */
|
|
132
|
+
importText(text: string): Promise<ImportResult>;
|
|
133
|
+
/** the canonical serialization of the current document (L2, L6) */
|
|
134
|
+
exportText(): string;
|
|
135
|
+
/** subscribe to user-visible model changes (L3); returns the unsubscribe */
|
|
136
|
+
onContentChanged(cb: () => void): () => void;
|
|
137
|
+
/** opaque viewport snapshot (zoom/scroll) — JSON-serializable (L5) */
|
|
138
|
+
getViewState(): unknown;
|
|
139
|
+
setViewState(state: unknown): void;
|
|
140
|
+
readonly elements?: ElementsSurface;
|
|
141
|
+
/** tear down DOM + listeners; further calls on the instance are undefined
|
|
142
|
+
* behavior, but a second destroy() must not throw */
|
|
143
|
+
destroy(): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { type CollaborativeModeler, type ElementInfo, type ElementsSurface, type ImportResult, MODELER_API_VERSION, type ModelerMeta };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miragon/modeler-api",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ONE interface every Miragon modeler implements — the collaborative-modeler contract and its conformance test kit.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Miragon/modeler-api.git",
|
|
9
|
+
"directory": "packages/api"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Miragon/modeler-api/tree/main/packages/api#readme",
|
|
12
|
+
"bugs": "https://github.com/Miragon/modeler-api/issues",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./dist/index.d.cts",
|
|
23
|
+
"default": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"./conformance": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/conformance.d.ts",
|
|
29
|
+
"default": "./dist/conformance.js"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/conformance.d.cts",
|
|
33
|
+
"default": "./dist/conformance.cjs"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"main": "./dist/index.cjs",
|
|
38
|
+
"module": "./dist/index.js",
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"files": [
|
|
41
|
+
"dist"
|
|
42
|
+
],
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22.13.0"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"publint": "publint",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
53
|
+
"test": "vitest run"
|
|
54
|
+
}
|
|
55
|
+
}
|