callman-core 1.28.0 → 1.29.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/ai-packs/scenario-nodes.md +451 -0
- package/dist/ai/index.d.ts +2 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +1 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/outputSchemas.d.ts +3 -0
- package/dist/ai/outputSchemas.d.ts.map +1 -1
- package/dist/ai/outputSchemas.js +1 -0
- package/dist/ai/outputSchemas.js.map +1 -1
- package/dist/ai/parse/diagram.d.ts.map +1 -1
- package/dist/ai/parse/diagram.js +6 -3
- package/dist/ai/parse/diagram.js.map +1 -1
- package/dist/ai/prompts/diagram.d.ts +7 -3
- package/dist/ai/prompts/diagram.d.ts.map +1 -1
- package/dist/ai/prompts/diagram.js +44 -5
- package/dist/ai/prompts/diagram.js.map +1 -1
- package/dist/ai/prompts/scenario.d.ts.map +1 -1
- package/dist/ai/prompts/scenario.js +9 -8
- package/dist/ai/prompts/scenario.js.map +1 -1
- package/dist/ai/prompts/scenarioNodeReference.d.ts +16 -0
- package/dist/ai/prompts/scenarioNodeReference.d.ts.map +1 -0
- package/dist/ai/prompts/scenarioNodeReference.js +882 -0
- package/dist/ai/prompts/scenarioNodeReference.js.map +1 -0
- package/dist/ai/types.d.ts +6 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/diagram/bpmn/derive.d.ts +74 -0
- package/dist/diagram/bpmn/derive.d.ts.map +1 -0
- package/dist/diagram/bpmn/derive.js +392 -0
- package/dist/diagram/bpmn/derive.js.map +1 -0
- package/dist/diagram/bpmn/index.d.ts +7 -0
- package/dist/diagram/bpmn/index.d.ts.map +1 -0
- package/dist/diagram/bpmn/index.js +12 -0
- package/dist/diagram/bpmn/index.js.map +1 -0
- package/dist/diagram/bpmn/patch.d.ts +14 -0
- package/dist/diagram/bpmn/patch.d.ts.map +1 -0
- package/dist/diagram/bpmn/patch.js +770 -0
- package/dist/diagram/bpmn/patch.js.map +1 -0
- package/dist/diagram/bpmn/place.d.ts +4 -0
- package/dist/diagram/bpmn/place.d.ts.map +1 -0
- package/dist/diagram/bpmn/place.js +65 -0
- package/dist/diagram/bpmn/place.js.map +1 -0
- package/dist/diagram/bpmn/serialize.d.ts +12 -0
- package/dist/diagram/bpmn/serialize.d.ts.map +1 -0
- package/dist/diagram/bpmn/serialize.js +292 -0
- package/dist/diagram/bpmn/serialize.js.map +1 -0
- package/dist/diagram/bpmn/types.d.ts +42 -0
- package/dist/diagram/bpmn/types.d.ts.map +1 -0
- package/dist/diagram/bpmn/types.js +84 -0
- package/dist/diagram/bpmn/types.js.map +1 -0
- package/dist/diagram/bpmn/xml.d.ts +60 -0
- package/dist/diagram/bpmn/xml.d.ts.map +1 -0
- package/dist/diagram/bpmn/xml.js +342 -0
- package/dist/diagram/bpmn/xml.js.map +1 -0
- package/dist/diagram/elkGraph.d.ts +1 -3
- package/dist/diagram/elkGraph.d.ts.map +1 -1
- package/dist/diagram/elkGraph.js +1 -0
- package/dist/diagram/elkGraph.js.map +1 -1
- package/dist/diagram/fixtures.d.ts +10 -0
- package/dist/diagram/fixtures.d.ts.map +1 -0
- package/dist/diagram/fixtures.js +113 -0
- package/dist/diagram/fixtures.js.map +1 -0
- package/dist/diagram/geometry.d.ts +27 -0
- package/dist/diagram/geometry.d.ts.map +1 -0
- package/dist/diagram/geometry.js +122 -0
- package/dist/diagram/geometry.js.map +1 -0
- package/dist/diagram/history.d.ts +36 -0
- package/dist/diagram/history.d.ts.map +1 -0
- package/dist/diagram/history.js +54 -0
- package/dist/diagram/history.js.map +1 -0
- package/dist/diagram/ids.d.ts +5 -0
- package/dist/diagram/ids.d.ts.map +1 -0
- package/dist/diagram/ids.js +52 -0
- package/dist/diagram/ids.js.map +1 -0
- package/dist/diagram/index.d.ts +14 -2
- package/dist/diagram/index.d.ts.map +1 -1
- package/dist/diagram/index.js +20 -8
- package/dist/diagram/index.js.map +1 -1
- package/dist/diagram/layout.d.ts +107 -0
- package/dist/diagram/layout.d.ts.map +1 -0
- package/dist/diagram/layout.js +356 -0
- package/dist/diagram/layout.js.map +1 -0
- package/dist/diagram/mermaid/derive.d.ts +55 -0
- package/dist/diagram/mermaid/derive.d.ts.map +1 -0
- package/dist/diagram/mermaid/derive.js +343 -0
- package/dist/diagram/mermaid/derive.js.map +1 -0
- package/dist/diagram/mermaid/index.d.ts +8 -0
- package/dist/diagram/mermaid/index.d.ts.map +1 -0
- package/dist/diagram/mermaid/index.js +24 -0
- package/dist/diagram/mermaid/index.js.map +1 -0
- package/dist/diagram/mermaid/parse.d.ts +96 -0
- package/dist/diagram/mermaid/parse.d.ts.map +1 -0
- package/dist/diagram/mermaid/parse.js +672 -0
- package/dist/diagram/mermaid/parse.js.map +1 -0
- package/dist/diagram/mermaid/patch.d.ts +16 -0
- package/dist/diagram/mermaid/patch.d.ts.map +1 -0
- package/dist/diagram/mermaid/patch.js +463 -0
- package/dist/diagram/mermaid/patch.js.map +1 -0
- package/dist/diagram/mermaid/serialize.d.ts +14 -0
- package/dist/diagram/mermaid/serialize.d.ts.map +1 -0
- package/dist/diagram/mermaid/serialize.js +125 -0
- package/dist/diagram/mermaid/serialize.js.map +1 -0
- package/dist/diagram/mermaid/shapes.d.ts +11 -0
- package/dist/diagram/mermaid/shapes.d.ts.map +1 -0
- package/dist/diagram/mermaid/shapes.js +320 -0
- package/dist/diagram/mermaid/shapes.js.map +1 -0
- package/dist/diagram/migrations.d.ts +1 -0
- package/dist/diagram/migrations.d.ts.map +1 -1
- package/dist/diagram/migrations.js +7 -2
- package/dist/diagram/migrations.js.map +1 -1
- package/dist/diagram/normalize.d.ts +9 -1
- package/dist/diagram/normalize.d.ts.map +1 -1
- package/dist/diagram/normalize.js +194 -0
- package/dist/diagram/normalize.js.map +1 -1
- package/dist/diagram/ops.d.ts +146 -0
- package/dist/diagram/ops.d.ts.map +1 -0
- package/dist/diagram/ops.js +823 -0
- package/dist/diagram/ops.js.map +1 -0
- package/dist/diagram/opsReference.d.ts +3 -0
- package/dist/diagram/opsReference.d.ts.map +1 -0
- package/dist/diagram/opsReference.js +51 -0
- package/dist/diagram/opsReference.js.map +1 -0
- package/dist/diagram/patchInput.d.ts +193 -0
- package/dist/diagram/patchInput.d.ts.map +1 -0
- package/dist/diagram/patchInput.js +621 -0
- package/dist/diagram/patchInput.js.map +1 -0
- package/dist/diagram/routing/batch.d.ts +45 -0
- package/dist/diagram/routing/batch.d.ts.map +1 -0
- package/dist/diagram/routing/batch.js +136 -0
- package/dist/diagram/routing/batch.js.map +1 -0
- package/dist/diagram/routing/curves.d.ts +7 -0
- package/dist/diagram/routing/curves.d.ts.map +1 -0
- package/dist/diagram/routing/curves.js +120 -0
- package/dist/diagram/routing/curves.js.map +1 -0
- package/dist/diagram/routing/grid.d.ts +15 -0
- package/dist/diagram/routing/grid.d.ts.map +1 -0
- package/dist/diagram/routing/grid.js +245 -0
- package/dist/diagram/routing/grid.js.map +1 -0
- package/dist/diagram/routing/index.d.ts +10 -0
- package/dist/diagram/routing/index.d.ts.map +1 -0
- package/dist/diagram/routing/index.js +10 -0
- package/dist/diagram/routing/index.js.map +1 -0
- package/dist/diagram/routing/legacy.d.ts +6 -0
- package/dist/diagram/routing/legacy.d.ts.map +1 -0
- package/dist/diagram/routing/legacy.js +27 -0
- package/dist/diagram/routing/legacy.js.map +1 -0
- package/dist/diagram/routing/nudge.d.ts +4 -0
- package/dist/diagram/routing/nudge.d.ts.map +1 -0
- package/dist/diagram/routing/nudge.js +96 -0
- package/dist/diagram/routing/nudge.js.map +1 -0
- package/dist/diagram/routing/orthogonal.d.ts +6 -0
- package/dist/diagram/routing/orthogonal.d.ts.map +1 -0
- package/dist/diagram/routing/orthogonal.js +56 -0
- package/dist/diagram/routing/orthogonal.js.map +1 -0
- package/dist/diagram/routing/path.d.ts +16 -0
- package/dist/diagram/routing/path.d.ts.map +1 -0
- package/dist/diagram/routing/path.js +128 -0
- package/dist/diagram/routing/path.js.map +1 -0
- package/dist/diagram/routing/sides.d.ts +22 -0
- package/dist/diagram/routing/sides.d.ts.map +1 -0
- package/dist/diagram/routing/sides.js +74 -0
- package/dist/diagram/routing/sides.js.map +1 -0
- package/dist/diagram/routing/types.d.ts +46 -0
- package/dist/diagram/routing/types.d.ts.map +1 -0
- package/dist/diagram/routing/types.js +11 -0
- package/dist/diagram/routing/types.js.map +1 -0
- package/dist/diagram/schema.d.ts +70 -37
- package/dist/diagram/schema.d.ts.map +1 -1
- package/dist/diagram/schema.js +62 -8
- package/dist/diagram/schema.js.map +1 -1
- package/dist/diagram/styleInput.d.ts +41 -0
- package/dist/diagram/styleInput.d.ts.map +1 -0
- package/dist/diagram/styleInput.js +105 -0
- package/dist/diagram/styleInput.js.map +1 -0
- package/dist/diagram/views.d.ts +9 -0
- package/dist/diagram/views.d.ts.map +1 -0
- package/dist/diagram/views.js +42 -0
- package/dist/diagram/views.js.map +1 -0
- package/dist/http-file/flatImport.d.ts +1 -0
- package/dist/http-file/flatImport.d.ts.map +1 -1
- package/dist/http-file/flatImport.js.map +1 -1
- package/dist/http-file/index.d.ts +1 -1
- package/dist/http-file/index.d.ts.map +1 -1
- package/dist/http-file/index.js +1 -1
- package/dist/http-file/index.js.map +1 -1
- package/dist/http-file/parseHttpFile.d.ts +1 -0
- package/dist/http-file/parseHttpFile.d.ts.map +1 -1
- package/dist/http-file/parseHttpFile.js +40 -8
- package/dist/http-file/parseHttpFile.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/request/requestBody.d.ts +55 -0
- package/dist/request/requestBody.d.ts.map +1 -0
- package/dist/request/requestBody.js +198 -0
- package/dist/request/requestBody.js.map +1 -0
- package/dist/runner/requestRunner.d.ts.map +1 -1
- package/dist/runner/requestRunner.js +127 -43
- package/dist/runner/requestRunner.js.map +1 -1
- package/dist/runner/runCollection.d.ts +1 -1
- package/dist/runner/runCollection.d.ts.map +1 -1
- package/dist/runner/runCollection.js +9 -2
- package/dist/runner/runCollection.js.map +1 -1
- package/dist/scenario-runner/adapters/helpers/request-helpers.d.ts +2 -1
- package/dist/scenario-runner/adapters/helpers/request-helpers.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/helpers/request-helpers.js +8 -40
- package/dist/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.d.ts.map +1 -1
- package/dist/scenario-runner/adapters/request-executor.js +2 -29
- package/dist/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist/scenario-runner/index.d.ts +1 -0
- package/dist/scenario-runner/index.d.ts.map +1 -1
- package/dist/scenario-runner/index.js +1 -0
- package/dist/scenario-runner/index.js.map +1 -1
- package/dist/scenario-runner/labels.d.ts +3 -0
- package/dist/scenario-runner/labels.d.ts.map +1 -0
- package/dist/scenario-runner/labels.js +20 -0
- package/dist/scenario-runner/labels.js.map +1 -0
- package/dist/scenario-runner/runScenario.d.ts.map +1 -1
- package/dist/scenario-runner/runScenario.js +4 -11
- package/dist/scenario-runner/runScenario.js.map +1 -1
- package/dist/script/legacy.d.ts.map +1 -1
- package/dist/script/legacy.js +24 -9
- package/dist/script/legacy.js.map +1 -1
- package/dist/types/index.d.ts +18 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/variables/resolver.d.ts.map +1 -1
- package/dist/variables/resolver.js +27 -5
- package/dist/variables/resolver.js.map +1 -1
- package/dist-cjs/ai/index.js +4 -1
- package/dist-cjs/ai/index.js.map +1 -1
- package/dist-cjs/ai/outputSchemas.js +1 -0
- package/dist-cjs/ai/outputSchemas.js.map +1 -1
- package/dist-cjs/ai/parse/diagram.js +6 -3
- package/dist-cjs/ai/parse/diagram.js.map +1 -1
- package/dist-cjs/ai/prompts/diagram.js +44 -5
- package/dist-cjs/ai/prompts/diagram.js.map +1 -1
- package/dist-cjs/ai/prompts/scenario.js +9 -8
- package/dist-cjs/ai/prompts/scenario.js.map +1 -1
- package/dist-cjs/ai/prompts/scenarioNodeReference.js +886 -0
- package/dist-cjs/ai/prompts/scenarioNodeReference.js.map +1 -0
- package/dist-cjs/diagram/bpmn/derive.js +398 -0
- package/dist-cjs/diagram/bpmn/derive.js.map +1 -0
- package/dist-cjs/diagram/bpmn/index.js +31 -0
- package/dist-cjs/diagram/bpmn/index.js.map +1 -0
- package/dist-cjs/diagram/bpmn/patch.js +774 -0
- package/dist-cjs/diagram/bpmn/patch.js.map +1 -0
- package/dist-cjs/diagram/bpmn/place.js +69 -0
- package/dist-cjs/diagram/bpmn/place.js.map +1 -0
- package/dist-cjs/diagram/bpmn/serialize.js +299 -0
- package/dist-cjs/diagram/bpmn/serialize.js.map +1 -0
- package/dist-cjs/diagram/bpmn/types.js +99 -0
- package/dist-cjs/diagram/bpmn/types.js.map +1 -0
- package/dist-cjs/diagram/bpmn/xml.js +367 -0
- package/dist-cjs/diagram/bpmn/xml.js.map +1 -0
- package/dist-cjs/diagram/elkGraph.js +1 -0
- package/dist-cjs/diagram/elkGraph.js.map +1 -1
- package/dist-cjs/diagram/fixtures.js +117 -0
- package/dist-cjs/diagram/fixtures.js.map +1 -0
- package/dist-cjs/diagram/geometry.js +143 -0
- package/dist-cjs/diagram/geometry.js.map +1 -0
- package/dist-cjs/diagram/history.js +65 -0
- package/dist-cjs/diagram/history.js.map +1 -0
- package/dist-cjs/diagram/ids.js +58 -0
- package/dist-cjs/diagram/ids.js.map +1 -0
- package/dist-cjs/diagram/index.js +23 -8
- package/dist-cjs/diagram/index.js.map +1 -1
- package/dist-cjs/diagram/layout.js +364 -0
- package/dist-cjs/diagram/layout.js.map +1 -0
- package/dist-cjs/diagram/mermaid/derive.js +353 -0
- package/dist-cjs/diagram/mermaid/derive.js.map +1 -0
- package/dist-cjs/diagram/mermaid/index.js +44 -0
- package/dist-cjs/diagram/mermaid/index.js.map +1 -0
- package/dist-cjs/diagram/mermaid/parse.js +681 -0
- package/dist-cjs/diagram/mermaid/parse.js.map +1 -0
- package/dist-cjs/diagram/mermaid/patch.js +468 -0
- package/dist-cjs/diagram/mermaid/patch.js.map +1 -0
- package/dist-cjs/diagram/mermaid/serialize.js +133 -0
- package/dist-cjs/diagram/mermaid/serialize.js.map +1 -0
- package/dist-cjs/diagram/mermaid/shapes.js +327 -0
- package/dist-cjs/diagram/mermaid/shapes.js.map +1 -0
- package/dist-cjs/diagram/migrations.js +9 -3
- package/dist-cjs/diagram/migrations.js.map +1 -1
- package/dist-cjs/diagram/normalize.js +198 -1
- package/dist-cjs/diagram/normalize.js.map +1 -1
- package/dist-cjs/diagram/ops.js +829 -0
- package/dist-cjs/diagram/ops.js.map +1 -0
- package/dist-cjs/diagram/opsReference.js +55 -0
- package/dist-cjs/diagram/opsReference.js.map +1 -0
- package/dist-cjs/diagram/patchInput.js +636 -0
- package/dist-cjs/diagram/patchInput.js.map +1 -0
- package/dist-cjs/diagram/routing/batch.js +142 -0
- package/dist-cjs/diagram/routing/batch.js.map +1 -0
- package/dist-cjs/diagram/routing/curves.js +127 -0
- package/dist-cjs/diagram/routing/curves.js.map +1 -0
- package/dist-cjs/diagram/routing/grid.js +250 -0
- package/dist-cjs/diagram/routing/grid.js.map +1 -0
- package/dist-cjs/diagram/routing/index.js +29 -0
- package/dist-cjs/diagram/routing/index.js.map +1 -0
- package/dist-cjs/diagram/routing/legacy.js +32 -0
- package/dist-cjs/diagram/routing/legacy.js.map +1 -0
- package/dist-cjs/diagram/routing/nudge.js +100 -0
- package/dist-cjs/diagram/routing/nudge.js.map +1 -0
- package/dist-cjs/diagram/routing/orthogonal.js +62 -0
- package/dist-cjs/diagram/routing/orthogonal.js.map +1 -0
- package/dist-cjs/diagram/routing/path.js +137 -0
- package/dist-cjs/diagram/routing/path.js.map +1 -0
- package/dist-cjs/diagram/routing/sides.js +82 -0
- package/dist-cjs/diagram/routing/sides.js.map +1 -0
- package/dist-cjs/diagram/routing/types.js +15 -0
- package/dist-cjs/diagram/routing/types.js.map +1 -0
- package/dist-cjs/diagram/schema.js +64 -9
- package/dist-cjs/diagram/schema.js.map +1 -1
- package/dist-cjs/diagram/styleInput.js +113 -0
- package/dist-cjs/diagram/styleInput.js.map +1 -0
- package/dist-cjs/diagram/views.js +46 -0
- package/dist-cjs/diagram/views.js.map +1 -0
- package/dist-cjs/http-file/flatImport.js.map +1 -1
- package/dist-cjs/http-file/index.js +2 -1
- package/dist-cjs/http-file/index.js.map +1 -1
- package/dist-cjs/http-file/parseHttpFile.js +42 -9
- package/dist-cjs/http-file/parseHttpFile.js.map +1 -1
- package/dist-cjs/index.js +9 -1
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/request/requestBody.js +206 -0
- package/dist-cjs/request/requestBody.js.map +1 -0
- package/dist-cjs/runner/requestRunner.js +127 -43
- package/dist-cjs/runner/requestRunner.js.map +1 -1
- package/dist-cjs/runner/runCollection.js +9 -2
- package/dist-cjs/runner/runCollection.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js +7 -42
- package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
- package/dist-cjs/scenario-runner/adapters/request-executor.js +3 -30
- package/dist-cjs/scenario-runner/adapters/request-executor.js.map +1 -1
- package/dist-cjs/scenario-runner/index.js +4 -1
- package/dist-cjs/scenario-runner/index.js.map +1 -1
- package/dist-cjs/scenario-runner/labels.js +24 -0
- package/dist-cjs/scenario-runner/labels.js.map +1 -0
- package/dist-cjs/scenario-runner/runScenario.js +4 -11
- package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
- package/dist-cjs/script/legacy.js +24 -9
- package/dist-cjs/script/legacy.js.map +1 -1
- package/dist-cjs/variables/resolver.js +27 -5
- package/dist-cjs/variables/resolver.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assessOpsRisk = exports.placeNewNodesOps = exports.ungroupOps = exports.groupNodesOps = exports.buildDiagramFromInput = exports.lowerPatchOps = exports.edgeStyleFor = exports.assertNotConnector = exports.parentWarning = exports.containerTypes = exports.isContainerType = exports.suggestComponentTypes = void 0;
|
|
4
|
+
// The AUTHORING vocabulary — the compact shape AI models and MCP clients
|
|
5
|
+
// write (`parent` not `parentId`, a `semantic` instead of a dash tuple, CSS
|
|
6
|
+
// colors, optional positions) — lowered onto the canonical ops of ops.ts.
|
|
7
|
+
// One implementation of the merge rules, type checks and suggestions, shared
|
|
8
|
+
// by the MCP server (behind its zod schemas), the AI EDIT mode and imports.
|
|
9
|
+
// Moved from the MCP server's build.ts / patch.ts.
|
|
10
|
+
const types_js_1 = require("./bpmn/types.js");
|
|
11
|
+
const componentCatalog_js_1 = require("./componentCatalog.js");
|
|
12
|
+
const edgeSemantics_js_1 = require("./edgeSemantics.js");
|
|
13
|
+
const geometry_js_1 = require("./geometry.js");
|
|
14
|
+
const ids_js_1 = require("./ids.js");
|
|
15
|
+
const normalize_js_1 = require("./normalize.js");
|
|
16
|
+
const ops_js_1 = require("./ops.js");
|
|
17
|
+
const schema_js_1 = require("./schema.js");
|
|
18
|
+
const styleInput_js_1 = require("./styleInput.js");
|
|
19
|
+
// --- catalog helpers ---------------------------------------------------------------
|
|
20
|
+
const suggestComponentTypes = (type, limit = 5) => {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const out = [];
|
|
23
|
+
const push = (candidate) => {
|
|
24
|
+
if (!seen.has(candidate) && out.length < limit) {
|
|
25
|
+
seen.add(candidate);
|
|
26
|
+
out.push(candidate);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
for (const entry of (0, componentCatalog_js_1.searchDiagramComponents)(type))
|
|
30
|
+
push(entry.type);
|
|
31
|
+
// A typo usually sits at the END of the last segment ("db.postgresqlx"):
|
|
32
|
+
// shrink it until something in the catalog contains it.
|
|
33
|
+
const tail = (type.split(".").pop() ?? type).toLowerCase();
|
|
34
|
+
for (let length = tail.length; length >= 3 && out.length < limit; length -= 1) {
|
|
35
|
+
const needle = tail.slice(0, length);
|
|
36
|
+
for (const entry of componentCatalog_js_1.DIAGRAM_COMPONENT_CATALOG) {
|
|
37
|
+
const haystack = [entry.type, entry.label, ...(entry.aliases ?? [])].join(" ").toLowerCase();
|
|
38
|
+
if (haystack.includes(needle))
|
|
39
|
+
push(entry.type);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Still nothing: offer the same namespace ("db.*", "aws.*").
|
|
43
|
+
const namespace = type.includes(".") ? `${type.split(".")[0].toLowerCase()}.` : null;
|
|
44
|
+
if (namespace) {
|
|
45
|
+
for (const entry of componentCatalog_js_1.DIAGRAM_COMPONENT_CATALOG)
|
|
46
|
+
if (entry.type.toLowerCase().startsWith(namespace))
|
|
47
|
+
push(entry.type);
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
};
|
|
51
|
+
exports.suggestComponentTypes = suggestComponentTypes;
|
|
52
|
+
// Containers hold children through `parent`: frames and swimlane pools.
|
|
53
|
+
const isContainerType = (type) => {
|
|
54
|
+
const def = type ? (0, componentCatalog_js_1.getDiagramComponent)(type) : undefined;
|
|
55
|
+
return Boolean(def?.container || def?.swimlane);
|
|
56
|
+
};
|
|
57
|
+
exports.isContainerType = isContainerType;
|
|
58
|
+
const containerTypes = () => componentCatalog_js_1.DIAGRAM_COMPONENT_CATALOG.filter((entry) => entry.container || entry.swimlane).map((entry) => entry.type);
|
|
59
|
+
exports.containerTypes = containerTypes;
|
|
60
|
+
const parentWarning = (id, parentId, parentType, kind = "canvas") => {
|
|
61
|
+
if (kind === "bpmn") {
|
|
62
|
+
return (0, types_js_1.isBpmnContainerType)(parentType)
|
|
63
|
+
? null
|
|
64
|
+
: `Node ${id} sits inside "${parentId}" (${parentType ?? "unknown"}), which is not a BPMN container — use ${types_js_1.BPMN_CONTAINER_TYPES.join(", ")}.`;
|
|
65
|
+
}
|
|
66
|
+
return (0, exports.isContainerType)(parentType)
|
|
67
|
+
? null
|
|
68
|
+
: `Node ${id} sits inside "${parentId}" (${parentType ?? "unknown"}), which is not a container — use ${(0, exports.containerTypes)().join(", ")} to group nodes.`;
|
|
69
|
+
};
|
|
70
|
+
exports.parentWarning = parentWarning;
|
|
71
|
+
// line / arrow / line.dashed are palette connectors (0-height), not nodes.
|
|
72
|
+
const assertNotConnector = (type, id, opIndex = -1) => {
|
|
73
|
+
if ((0, componentCatalog_js_1.getDiagramComponent)(type)?.variant === "line") {
|
|
74
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_CONNECTOR_NOT_NODE", `"${type}" on ${id} is a connector, not a node — draw it as an edge between two nodes.`, opIndex);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
exports.assertNotConnector = assertNotConnector;
|
|
78
|
+
// Edge input → the stored edge's visual fields: the semantic's line tuple
|
|
79
|
+
// plus an optional color.
|
|
80
|
+
const edgeStyleFor = (semantic, color) => {
|
|
81
|
+
const base = semantic ? (0, edgeSemantics_js_1.semanticStyle)(semantic) : undefined;
|
|
82
|
+
if (!color)
|
|
83
|
+
return base;
|
|
84
|
+
return { ...(base ?? {}), stroke: (0, styleInput_js_1.toTokenRef)(color) };
|
|
85
|
+
};
|
|
86
|
+
exports.edgeStyleFor = edgeStyleFor;
|
|
87
|
+
const resolveType = (type, id, strict, warnings, opIndex, kind = "canvas") => {
|
|
88
|
+
const trimmed = type.trim();
|
|
89
|
+
if (kind === "bpmn") {
|
|
90
|
+
if ((0, types_js_1.getBpmnType)(trimmed))
|
|
91
|
+
return { type: trimmed, known: true };
|
|
92
|
+
const suggestions = (0, types_js_1.suggestBpmnTypes)(trimmed);
|
|
93
|
+
if (strict) {
|
|
94
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_UNKNOWN_COMPONENT_TYPE", `Unknown BPMN type "${trimmed}" on ${id}. Use one of the bpmn.* types (e.g. ${suggestions.join(", ") || "bpmn.user-task, bpmn.exclusive-gateway"}), or pass strictTypes:false to draw it as a task.`, opIndex, { unknownTypes: [{ type: trimmed, suggestions }] });
|
|
95
|
+
}
|
|
96
|
+
warnings.push(`Unknown BPMN type "${trimmed}" on ${id} → drawn as a task (suggestions: ${suggestions.join(", ") || "none"})`);
|
|
97
|
+
return { type: "bpmn.task", known: false };
|
|
98
|
+
}
|
|
99
|
+
if ((0, componentCatalog_js_1.getDiagramComponent)(trimmed)) {
|
|
100
|
+
(0, exports.assertNotConnector)(trimmed, id, opIndex);
|
|
101
|
+
return { type: trimmed, known: true };
|
|
102
|
+
}
|
|
103
|
+
const suggestions = (0, exports.suggestComponentTypes)(trimmed);
|
|
104
|
+
if (strict) {
|
|
105
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_UNKNOWN_COMPONENT_TYPE", `Unknown component type "${trimmed}" on ${id}. Read callman://diagram/components for the catalog, or pass strictTypes:false to draw it as a rectangle.`, opIndex, { unknownTypes: [{ type: trimmed, suggestions }] });
|
|
106
|
+
}
|
|
107
|
+
warnings.push(`Unknown component type "${trimmed}" on ${id} → drawn as a rectangle (suggestions: ${suggestions.join(", ") || "none"})`);
|
|
108
|
+
return { type: "rect", known: false };
|
|
109
|
+
};
|
|
110
|
+
const nodeFromInput = (input, id, strict, warnings, opIndex, kind = "canvas") => {
|
|
111
|
+
const { type, known } = resolveType(input.type, id, strict, warnings, opIndex, kind);
|
|
112
|
+
const def = kind === "bpmn" ? undefined : (0, componentCatalog_js_1.getDiagramComponent)(type);
|
|
113
|
+
const bpmn = kind === "bpmn" ? (0, types_js_1.getBpmnType)(type) : undefined;
|
|
114
|
+
const label = input.label !== undefined || !known ? (input.label ?? input.type) : def?.defaultLabel;
|
|
115
|
+
// A BPMN node always knows which element it stands for.
|
|
116
|
+
const data = kind === "bpmn"
|
|
117
|
+
? { ...(input.data ?? {}), bpmn: { ...(input.data?.bpmn ?? {}), element: (0, types_js_1.bpmnElementForType)(type) ?? "task" } }
|
|
118
|
+
: input.data;
|
|
119
|
+
const node = {
|
|
120
|
+
id,
|
|
121
|
+
type,
|
|
122
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
123
|
+
size: input.size ?? bpmn?.size ?? def?.defaultSize ?? { width: 140, height: 60 },
|
|
124
|
+
...(label !== undefined ? { label } : {}),
|
|
125
|
+
...(input.parent ? { parentId: input.parent } : {}),
|
|
126
|
+
...(input.style ? { style: (0, styleInput_js_1.applyStyleInput)(undefined, input.style) } : {}),
|
|
127
|
+
...(input.rotation ? { rotation: input.rotation } : {}),
|
|
128
|
+
...(input.locked ? { locked: true } : {}),
|
|
129
|
+
...(input.hidden ? { hidden: true } : {}),
|
|
130
|
+
...(input.collapsed ? { collapsed: true } : {}),
|
|
131
|
+
...(data ? { data } : {}),
|
|
132
|
+
};
|
|
133
|
+
if (node.style === undefined)
|
|
134
|
+
delete node.style;
|
|
135
|
+
return node;
|
|
136
|
+
};
|
|
137
|
+
const edgeFromInput = (input, id, typeOf, kind = "canvas") => {
|
|
138
|
+
let semantic = input.semantic;
|
|
139
|
+
// A fresh edge into a broker reads as a bus line — the studio's own rule.
|
|
140
|
+
if (kind === "canvas" && !semantic && ((0, edgeSemantics_js_1.isBusComponentType)(typeOf(input.source)) || (0, edgeSemantics_js_1.isBusComponentType)(typeOf(input.target))))
|
|
141
|
+
semantic = "bus";
|
|
142
|
+
// A BPMN flow is a sequence flow unless said otherwise.
|
|
143
|
+
const data = kind === "bpmn"
|
|
144
|
+
? { ...(input.data ?? {}), bpmn: { flow: "sequence", ...(input.data?.bpmn ?? {}) } }
|
|
145
|
+
: input.data;
|
|
146
|
+
const style = (0, exports.edgeStyleFor)(semantic, input.color);
|
|
147
|
+
return {
|
|
148
|
+
id,
|
|
149
|
+
source: input.source,
|
|
150
|
+
target: input.target,
|
|
151
|
+
...(input.label ? { label: input.label } : {}),
|
|
152
|
+
...(input.routing ? { routing: input.routing } : {}),
|
|
153
|
+
markerEnd: input.markerEnd ?? "classicThin",
|
|
154
|
+
...(input.markerStart && input.markerStart !== "none" ? { markerStart: input.markerStart } : {}),
|
|
155
|
+
...(input.sourceSide ? { sourceHandle: input.sourceSide } : {}),
|
|
156
|
+
...(input.targetSide ? { targetHandle: input.targetSide } : {}),
|
|
157
|
+
...(style && (!(0, edgeSemantics_js_1.isDefaultEdgeStyle)(style) || semantic === "sync" || input.color) ? { style } : {}),
|
|
158
|
+
...(data ? { data } : {}),
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
// --- lowering -----------------------------------------------------------------------
|
|
162
|
+
const lowerPatchOps = (doc, input, options = {}) => {
|
|
163
|
+
const strict = options.strictTypes !== false;
|
|
164
|
+
const kind = options.kind ?? (doc.source?.format === "bpmn" ? "bpmn" : "canvas");
|
|
165
|
+
const warnings = [];
|
|
166
|
+
const unpositionedNodeIds = [];
|
|
167
|
+
const idMap = {};
|
|
168
|
+
const ops = [];
|
|
169
|
+
let relayout;
|
|
170
|
+
// A working view of ids/types/parents so later ops in the same batch can
|
|
171
|
+
// reference nodes added earlier — the ops themselves stay canonical.
|
|
172
|
+
const nodes = new Map(doc.nodes.map((node) => [node.id, { ...node }]));
|
|
173
|
+
const edges = new Map(doc.edges.map((edge) => [edge.id, { ...edge }]));
|
|
174
|
+
const takenIds = () => [...nodes.keys(), ...edges.keys()];
|
|
175
|
+
const genNodeId = options.genNodeId ?? (0, ids_js_1.slugIdFactory)(takenIds(), "n");
|
|
176
|
+
const genEdgeId = options.genEdgeId ?? (0, ids_js_1.sequentialIdFactory)("e", takenIds());
|
|
177
|
+
const typeOf = (id) => nodes.get(id)?.type;
|
|
178
|
+
const mapId = (id) => idMap[id] ?? id;
|
|
179
|
+
const requireNode = (id, index) => {
|
|
180
|
+
const node = nodes.get(mapId(id));
|
|
181
|
+
if (!node)
|
|
182
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_NODE_NOT_FOUND", `Node "${id}" does not exist.`, index);
|
|
183
|
+
return node;
|
|
184
|
+
};
|
|
185
|
+
input.forEach((op, index) => {
|
|
186
|
+
switch (op.op) {
|
|
187
|
+
case "setTitle":
|
|
188
|
+
ops.push({ op: "setTitle", title: op.title });
|
|
189
|
+
return;
|
|
190
|
+
case "addNode": {
|
|
191
|
+
const requested = op.node.id?.trim();
|
|
192
|
+
let id = requested || genNodeId(op.node.label ?? op.node.type);
|
|
193
|
+
if (requested && (nodes.has(requested) || edges.has(requested))) {
|
|
194
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `A node with id "${requested}" already exists.`, index);
|
|
195
|
+
}
|
|
196
|
+
if (!requested && (nodes.has(id) || edges.has(id)))
|
|
197
|
+
id = genNodeId();
|
|
198
|
+
const parent = op.node.parent ? mapId(op.node.parent) : undefined;
|
|
199
|
+
if (parent && !nodes.has(parent))
|
|
200
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${op.node.parent}" does not exist.`, index);
|
|
201
|
+
const node = nodeFromInput({ ...op.node, parent }, id, strict, warnings, index, kind);
|
|
202
|
+
if (parent) {
|
|
203
|
+
const warning = (0, exports.parentWarning)(id, parent, typeOf(parent), kind);
|
|
204
|
+
if (warning)
|
|
205
|
+
warnings.push(warning);
|
|
206
|
+
}
|
|
207
|
+
nodes.set(id, node);
|
|
208
|
+
if (requested && requested !== id)
|
|
209
|
+
idMap[requested] = id;
|
|
210
|
+
if (!op.node.position)
|
|
211
|
+
unpositionedNodeIds.push(id);
|
|
212
|
+
ops.push({ op: "addNode", node });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
case "updateNode": {
|
|
216
|
+
const id = mapId(op.id);
|
|
217
|
+
const node = requireNode(id, index);
|
|
218
|
+
const changes = op.changes;
|
|
219
|
+
const nodeChanges = {};
|
|
220
|
+
if (changes.type !== undefined)
|
|
221
|
+
nodeChanges.type = resolveType(changes.type, id, strict, warnings, index, kind).type;
|
|
222
|
+
if (changes.label !== undefined)
|
|
223
|
+
nodeChanges.label = changes.label;
|
|
224
|
+
if (changes.rotation !== undefined)
|
|
225
|
+
nodeChanges.rotation = changes.rotation;
|
|
226
|
+
if (changes.locked !== undefined)
|
|
227
|
+
nodeChanges.locked = changes.locked;
|
|
228
|
+
if (changes.hidden !== undefined)
|
|
229
|
+
nodeChanges.hidden = changes.hidden;
|
|
230
|
+
if (changes.collapsed !== undefined)
|
|
231
|
+
nodeChanges.collapsed = changes.collapsed;
|
|
232
|
+
if (changes.style !== undefined)
|
|
233
|
+
nodeChanges.style = changes.style === null ? null : (0, styleInput_js_1.styleInputToChanges)(node.style, changes.style);
|
|
234
|
+
if (changes.data !== undefined)
|
|
235
|
+
nodeChanges.data = changes.data;
|
|
236
|
+
if (Object.keys(nodeChanges).length > 0) {
|
|
237
|
+
ops.push({ op: "updateNode", id, changes: nodeChanges });
|
|
238
|
+
const next = { ...node };
|
|
239
|
+
if (nodeChanges.type)
|
|
240
|
+
next.type = nodeChanges.type;
|
|
241
|
+
nodes.set(id, next);
|
|
242
|
+
}
|
|
243
|
+
if (changes.size !== undefined) {
|
|
244
|
+
ops.push({ op: "resizeNode", id, size: changes.size });
|
|
245
|
+
nodes.set(id, { ...nodes.get(id), size: changes.size });
|
|
246
|
+
}
|
|
247
|
+
if (changes.parent !== undefined) {
|
|
248
|
+
const parent = changes.parent ? mapId(changes.parent) : null;
|
|
249
|
+
if (parent && !nodes.has(parent))
|
|
250
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${changes.parent}" does not exist.`, index);
|
|
251
|
+
if (parent === id)
|
|
252
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_PARENT_CYCLE", `Node "${id}" cannot contain itself.`, index);
|
|
253
|
+
const byId = (0, geometry_js_1.indexNodes)([...nodes.values()]);
|
|
254
|
+
const position = changes.position ?? (0, geometry_js_1.toParentRelative)((0, geometry_js_1.absolutePosition)(nodes.get(id), byId), parent, byId);
|
|
255
|
+
ops.push({ op: "reparent", id, parentId: parent, position });
|
|
256
|
+
if (parent) {
|
|
257
|
+
const warning = (0, exports.parentWarning)(id, parent, typeOf(parent), kind);
|
|
258
|
+
if (warning)
|
|
259
|
+
warnings.push(warning);
|
|
260
|
+
}
|
|
261
|
+
const next = { ...nodes.get(id), position };
|
|
262
|
+
if (parent)
|
|
263
|
+
next.parentId = parent;
|
|
264
|
+
else
|
|
265
|
+
delete next.parentId;
|
|
266
|
+
nodes.set(id, next);
|
|
267
|
+
}
|
|
268
|
+
else if (changes.position !== undefined) {
|
|
269
|
+
ops.push({ op: "moveNodes", moves: [{ id, position: changes.position }] });
|
|
270
|
+
nodes.set(id, { ...nodes.get(id), position: changes.position });
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
case "removeNode": {
|
|
275
|
+
const id = mapId(op.id);
|
|
276
|
+
requireNode(id, index);
|
|
277
|
+
ops.push({ op: "removeNode", id, children: "lift" });
|
|
278
|
+
nodes.delete(id);
|
|
279
|
+
for (const [edgeId, edge] of [...edges])
|
|
280
|
+
if (edge.source === id || edge.target === id)
|
|
281
|
+
edges.delete(edgeId);
|
|
282
|
+
for (const node of nodes.values())
|
|
283
|
+
if (node.parentId === id)
|
|
284
|
+
delete node.parentId;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
case "addEdge": {
|
|
288
|
+
const requested = op.edge.id?.trim();
|
|
289
|
+
let id = requested || genEdgeId();
|
|
290
|
+
if (requested && (edges.has(requested) || nodes.has(requested))) {
|
|
291
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DUPLICATE_EDGE_ID", `An edge with id "${requested}" already exists.`, index);
|
|
292
|
+
}
|
|
293
|
+
if (!requested && (edges.has(id) || nodes.has(id)))
|
|
294
|
+
id = genEdgeId();
|
|
295
|
+
const source = mapId(op.edge.source);
|
|
296
|
+
const target = mapId(op.edge.target);
|
|
297
|
+
for (const endpoint of [source, target]) {
|
|
298
|
+
if (!nodes.has(endpoint))
|
|
299
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge endpoint "${endpoint}" does not exist.`, index);
|
|
300
|
+
}
|
|
301
|
+
const edge = edgeFromInput({ ...op.edge, source, target }, id, typeOf, kind);
|
|
302
|
+
edges.set(id, edge);
|
|
303
|
+
ops.push({ op: "addEdge", edge });
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
case "updateEdge": {
|
|
307
|
+
const id = mapId(op.id);
|
|
308
|
+
const edge = edges.get(id);
|
|
309
|
+
if (!edge)
|
|
310
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
311
|
+
const changes = op.changes;
|
|
312
|
+
const edgeChanges = {};
|
|
313
|
+
if (changes.source !== undefined)
|
|
314
|
+
edgeChanges.source = mapId(changes.source);
|
|
315
|
+
if (changes.target !== undefined)
|
|
316
|
+
edgeChanges.target = mapId(changes.target);
|
|
317
|
+
if (changes.label !== undefined)
|
|
318
|
+
edgeChanges.label = changes.label === "" ? null : changes.label;
|
|
319
|
+
if (changes.routing !== undefined)
|
|
320
|
+
edgeChanges.routing = changes.routing;
|
|
321
|
+
if (changes.markerEnd !== undefined)
|
|
322
|
+
edgeChanges.markerEnd = changes.markerEnd;
|
|
323
|
+
if (changes.markerStart !== undefined)
|
|
324
|
+
edgeChanges.markerStart = changes.markerStart === "none" ? null : changes.markerStart;
|
|
325
|
+
if (changes.sourceSide !== undefined)
|
|
326
|
+
edgeChanges.sourceHandle = changes.sourceSide;
|
|
327
|
+
if (changes.targetSide !== undefined)
|
|
328
|
+
edgeChanges.targetHandle = changes.targetSide;
|
|
329
|
+
if (changes.data !== undefined)
|
|
330
|
+
edgeChanges.data = changes.data;
|
|
331
|
+
// The semantic owns the line tuple (dash + width); the color is kept
|
|
332
|
+
// unless it is changed explicitly.
|
|
333
|
+
if (changes.semantic !== undefined || changes.color !== undefined) {
|
|
334
|
+
const style = {};
|
|
335
|
+
if (changes.semantic !== undefined) {
|
|
336
|
+
const line = (0, edgeSemantics_js_1.semanticStyle)(changes.semantic);
|
|
337
|
+
style.dashed = line.dashed ?? null;
|
|
338
|
+
style.dashPattern = line.dashPattern ?? null;
|
|
339
|
+
style.strokeWidth = line.strokeWidth ?? null;
|
|
340
|
+
}
|
|
341
|
+
if (changes.color !== undefined)
|
|
342
|
+
style.stroke = changes.color === null ? null : (0, styleInput_js_1.toTokenRef)(changes.color);
|
|
343
|
+
edgeChanges.style = style;
|
|
344
|
+
}
|
|
345
|
+
for (const endpoint of [edgeChanges.source, edgeChanges.target]) {
|
|
346
|
+
if (endpoint !== undefined && !nodes.has(endpoint)) {
|
|
347
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge endpoint "${endpoint}" does not exist.`, index);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (Object.keys(edgeChanges).length > 0) {
|
|
351
|
+
ops.push({ op: "updateEdge", id, changes: edgeChanges });
|
|
352
|
+
edges.set(id, { ...edge, ...(edgeChanges.source ? { source: edgeChanges.source } : {}), ...(edgeChanges.target ? { target: edgeChanges.target } : {}) });
|
|
353
|
+
}
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
case "removeEdge": {
|
|
357
|
+
const id = mapId(op.id);
|
|
358
|
+
if (!edges.has(id))
|
|
359
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
360
|
+
edges.delete(id);
|
|
361
|
+
ops.push({ op: "removeEdge", id });
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
case "moveNode": {
|
|
365
|
+
const id = mapId(op.id);
|
|
366
|
+
requireNode(id, index);
|
|
367
|
+
ops.push({ op: "moveNodes", moves: [{ id, position: op.position }] });
|
|
368
|
+
nodes.set(id, { ...nodes.get(id), position: op.position });
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
case "reparent": {
|
|
372
|
+
const id = mapId(op.id);
|
|
373
|
+
const node = requireNode(id, index);
|
|
374
|
+
const parent = op.parent ? mapId(op.parent) : null;
|
|
375
|
+
if (parent && !nodes.has(parent))
|
|
376
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${op.parent}" does not exist.`, index);
|
|
377
|
+
const byId = (0, geometry_js_1.indexNodes)([...nodes.values()]);
|
|
378
|
+
const position = op.position ?? (0, geometry_js_1.toParentRelative)((0, geometry_js_1.absolutePosition)(node, byId), parent, byId);
|
|
379
|
+
ops.push({ op: "reparent", id, parentId: parent, position });
|
|
380
|
+
const next = { ...node, position };
|
|
381
|
+
if (parent)
|
|
382
|
+
next.parentId = parent;
|
|
383
|
+
else
|
|
384
|
+
delete next.parentId;
|
|
385
|
+
nodes.set(id, next);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
case "setEdgeRoute": {
|
|
389
|
+
const id = mapId(op.id);
|
|
390
|
+
if (!edges.has(id))
|
|
391
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
392
|
+
const changes = {};
|
|
393
|
+
if (op.routing !== undefined)
|
|
394
|
+
changes.routing = op.routing;
|
|
395
|
+
if (op.sourceSide !== undefined)
|
|
396
|
+
changes.sourceHandle = op.sourceSide;
|
|
397
|
+
if (op.targetSide !== undefined)
|
|
398
|
+
changes.targetHandle = op.targetSide;
|
|
399
|
+
if (op.waypoints !== undefined)
|
|
400
|
+
changes.waypoints = op.waypoints;
|
|
401
|
+
// "Reset routing" when nothing else is asked.
|
|
402
|
+
if (Object.keys(changes).length === 0) {
|
|
403
|
+
changes.waypoints = null;
|
|
404
|
+
changes.sourceAnchor = null;
|
|
405
|
+
changes.targetAnchor = null;
|
|
406
|
+
}
|
|
407
|
+
ops.push({ op: "updateEdge", id, changes });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
case "reorder": {
|
|
411
|
+
const id = mapId(op.id);
|
|
412
|
+
const node = requireNode(id, index);
|
|
413
|
+
const siblings = [...nodes.values()].filter((candidate) => (candidate.parentId ?? undefined) === (node.parentId ?? undefined));
|
|
414
|
+
const target = op.index === "front" ? siblings.length - 1 : op.index === "back" ? 0 : op.index;
|
|
415
|
+
ops.push({ op: "reorder", kind: "node", id, index: target });
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
case "setCanvas":
|
|
419
|
+
ops.push({ op: "setCanvas", changes: op.canvas });
|
|
420
|
+
return;
|
|
421
|
+
case "group": {
|
|
422
|
+
const memberIds = op.ids.map(mapId);
|
|
423
|
+
for (const memberId of memberIds)
|
|
424
|
+
requireNode(memberId, index);
|
|
425
|
+
const type = op.type ?? "frame";
|
|
426
|
+
if (!(0, exports.isContainerType)(type)) {
|
|
427
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_INVALID_OP", `"${type}" is not a container type — use ${(0, exports.containerTypes)().join(", ")}.`, index);
|
|
428
|
+
}
|
|
429
|
+
const requested = op.id?.trim();
|
|
430
|
+
const groupId = requested || genNodeId(op.label ?? "group");
|
|
431
|
+
if (nodes.has(groupId) || edges.has(groupId))
|
|
432
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `A node with id "${groupId}" already exists.`, index);
|
|
433
|
+
const grouped = (0, exports.groupNodesOps)({ ...doc, nodes: [...nodes.values()], edges: [...edges.values()] }, memberIds, { id: groupId, type, label: op.label });
|
|
434
|
+
ops.push(...grouped.ops);
|
|
435
|
+
nodes.set(groupId, grouped.container);
|
|
436
|
+
for (const [memberId, position] of Object.entries(grouped.memberPositions)) {
|
|
437
|
+
nodes.set(memberId, { ...nodes.get(memberId), parentId: groupId, position });
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
case "ungroup": {
|
|
442
|
+
const id = mapId(op.id);
|
|
443
|
+
requireNode(id, index);
|
|
444
|
+
ops.push({ op: "removeNode", id, children: "lift" });
|
|
445
|
+
nodes.delete(id);
|
|
446
|
+
for (const node of nodes.values())
|
|
447
|
+
if (node.parentId === id)
|
|
448
|
+
delete node.parentId;
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
case "relayout":
|
|
452
|
+
relayout = { scope: op.scope, ...(op.direction ? { direction: op.direction } : {}) };
|
|
453
|
+
return;
|
|
454
|
+
default:
|
|
455
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_INVALID_OP", `Unknown op "${op.op}"`, index);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
return { ops, warnings, unpositionedNodeIds, ...(relayout ? { relayout } : {}), idMap };
|
|
459
|
+
};
|
|
460
|
+
exports.lowerPatchOps = lowerPatchOps;
|
|
461
|
+
const buildDiagramFromInput = (input, options = {}) => {
|
|
462
|
+
const kind = options.kind ?? "canvas";
|
|
463
|
+
const strict = options.strictTypes !== false;
|
|
464
|
+
const warnings = [];
|
|
465
|
+
const explicitIds = input.nodes.map((node) => node.id?.trim()).filter((id) => Boolean(id));
|
|
466
|
+
const duplicates = explicitIds.filter((id, index) => explicitIds.indexOf(id) !== index);
|
|
467
|
+
if (duplicates.length > 0) {
|
|
468
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `Duplicate node ids: ${[...new Set(duplicates)].join(", ")}`);
|
|
469
|
+
}
|
|
470
|
+
const genNodeId = options.idStrategy === "sequential" ? (0, ids_js_1.sequentialIdFactory)("n", explicitIds) : (0, ids_js_1.slugIdFactory)(explicitIds, "n");
|
|
471
|
+
const genEdgeId = (0, ids_js_1.sequentialIdFactory)("e", (input.edges ?? []).map((edge) => edge.id).filter((id) => Boolean(id)));
|
|
472
|
+
// Ids first so parents/edges can reference nodes declared later.
|
|
473
|
+
const ids = input.nodes.map((node) => node.id?.trim() || genNodeId(node.label ?? node.type));
|
|
474
|
+
const idSet = new Set(ids);
|
|
475
|
+
const unknown = [];
|
|
476
|
+
const nodes = input.nodes.map((node, index) => {
|
|
477
|
+
const id = ids[index];
|
|
478
|
+
if (node.parent && !idSet.has(node.parent)) {
|
|
479
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Node ${id} references parent "${node.parent}" which is not in nodes.`, index);
|
|
480
|
+
}
|
|
481
|
+
try {
|
|
482
|
+
return nodeFromInput(node, id, strict, warnings, index, kind);
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
if (error instanceof ops_js_1.DiagramOpError && error.code === "DIAGRAM_UNKNOWN_COMPONENT_TYPE") {
|
|
486
|
+
const entry = error.data?.unknownTypes?.[0];
|
|
487
|
+
if (entry)
|
|
488
|
+
unknown.push(entry);
|
|
489
|
+
return nodeFromInput({ ...node, type: kind === "bpmn" ? "bpmn.task" : "rect", label: node.label ?? node.type }, id, false, [], index, kind);
|
|
490
|
+
}
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
if (unknown.length > 0) {
|
|
495
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_UNKNOWN_COMPONENT_TYPE", `Unknown component type(s): ${unknown.map((entry) => entry.type).join(", ")}. Read callman://diagram/components for the catalog, or pass strictTypes:false to draw them as rectangles.`, -1, { unknownTypes: unknown });
|
|
496
|
+
}
|
|
497
|
+
const typeOf = (id) => nodes.find((node) => node.id === id)?.type;
|
|
498
|
+
for (const node of nodes) {
|
|
499
|
+
const warning = node.parentId ? (0, exports.parentWarning)(node.id, node.parentId, typeOf(node.parentId), kind) : null;
|
|
500
|
+
if (warning)
|
|
501
|
+
warnings.push(warning);
|
|
502
|
+
}
|
|
503
|
+
const edgeIds = new Set();
|
|
504
|
+
const edges = (input.edges ?? []).map((edge, index) => {
|
|
505
|
+
const id = edge.id?.trim() || genEdgeId();
|
|
506
|
+
if (edgeIds.has(id) || idSet.has(id))
|
|
507
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DUPLICATE_EDGE_ID", `Duplicate edge id: ${id}`, index);
|
|
508
|
+
edgeIds.add(id);
|
|
509
|
+
for (const endpoint of [edge.source, edge.target]) {
|
|
510
|
+
if (!idSet.has(endpoint)) {
|
|
511
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge ${id} references "${endpoint}" which is not a node id.`, index);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return edgeFromInput(edge, id, typeOf, kind);
|
|
515
|
+
});
|
|
516
|
+
const timestamp = options.createdAt ?? (0, schema_js_1.nowIso)();
|
|
517
|
+
const document = (0, normalize_js_1.normalizeDiagramStyles)({
|
|
518
|
+
schemaVersion: schema_js_1.SCHEMA_VERSION,
|
|
519
|
+
id: options.existingId ?? `doc_${Math.random().toString(36).slice(2, 10)}`,
|
|
520
|
+
meta: { title: input.title.trim(), createdAt: timestamp, updatedAt: options.now ?? (0, schema_js_1.nowIso)() },
|
|
521
|
+
canvas: {
|
|
522
|
+
background: input.canvas?.background ?? "dots",
|
|
523
|
+
gridSize: input.canvas?.gridSize ?? 16,
|
|
524
|
+
...(input.canvas?.defaultRouting ? { defaultRouting: input.canvas.defaultRouting } : {}),
|
|
525
|
+
},
|
|
526
|
+
nodes,
|
|
527
|
+
edges,
|
|
528
|
+
});
|
|
529
|
+
const parsed = (0, schema_js_1.safeParseDiagramDocument)(document);
|
|
530
|
+
if (!parsed.ok) {
|
|
531
|
+
throw new ops_js_1.DiagramOpError("DIAGRAM_DOCUMENT_INVALID", `The diagram document is invalid: ${parsed.errors.join("; ")}`, -1, { errors: parsed.errors });
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
document: parsed.document,
|
|
535
|
+
warnings,
|
|
536
|
+
unpositionedNodeIds: input.nodes.filter((node) => !node.position).map((_node, index) => ids[index]),
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
exports.buildDiagramFromInput = buildDiagramFromInput;
|
|
540
|
+
// A container around the members' bounding box, members re-parented into it
|
|
541
|
+
// with their positions converted so nothing moves on the canvas.
|
|
542
|
+
const groupNodesOps = (doc, memberIds, options) => {
|
|
543
|
+
const byId = (0, geometry_js_1.indexNodes)(doc.nodes);
|
|
544
|
+
const members = memberIds.map((id) => byId.get(id)).filter((node) => Boolean(node));
|
|
545
|
+
const padding = options.padding ?? 24;
|
|
546
|
+
const titleHeight = options.titleHeight ?? 32;
|
|
547
|
+
const rects = members.map((node) => (0, geometry_js_1.absoluteRect)(node, byId));
|
|
548
|
+
const box = (0, geometry_js_1.boundingBox)(rects) ?? { x: 0, y: 0, width: 200, height: 120 };
|
|
549
|
+
// The container joins the first member's parent so nested groups stay nested.
|
|
550
|
+
const parentId = members[0]?.parentId;
|
|
551
|
+
const type = options.type ?? "frame";
|
|
552
|
+
const def = (0, componentCatalog_js_1.getDiagramComponent)(type);
|
|
553
|
+
const containerAbs = { x: box.x - padding, y: box.y - padding - titleHeight };
|
|
554
|
+
const container = {
|
|
555
|
+
id: options.id,
|
|
556
|
+
type,
|
|
557
|
+
position: (0, geometry_js_1.toParentRelative)(containerAbs, parentId, byId),
|
|
558
|
+
size: { width: box.width + padding * 2, height: box.height + padding * 2 + titleHeight },
|
|
559
|
+
label: options.label ?? def?.defaultLabel ?? "Group",
|
|
560
|
+
...(parentId ? { parentId } : {}),
|
|
561
|
+
};
|
|
562
|
+
const ops = [{ op: "addNode", node: container }];
|
|
563
|
+
const memberPositions = {};
|
|
564
|
+
members.forEach((member, index) => {
|
|
565
|
+
const abs = rects[index];
|
|
566
|
+
const position = { x: abs.x - containerAbs.x, y: abs.y - containerAbs.y };
|
|
567
|
+
memberPositions[member.id] = position;
|
|
568
|
+
ops.push({ op: "reparent", id: member.id, parentId: options.id, position });
|
|
569
|
+
});
|
|
570
|
+
return { ops, container, memberPositions };
|
|
571
|
+
};
|
|
572
|
+
exports.groupNodesOps = groupNodesOps;
|
|
573
|
+
const ungroupOps = (containerId) => [{ op: "removeNode", id: containerId, children: "lift" }];
|
|
574
|
+
exports.ungroupOps = ungroupOps;
|
|
575
|
+
// Place ONLY the given nodes (new ones from a patch) below the current
|
|
576
|
+
// bounding box, in rows — nothing that already has a position moves. Nodes
|
|
577
|
+
// inside a container are placed inside it, below its current content.
|
|
578
|
+
const placeNewNodesOps = (doc, nodeIds, gap = 40) => {
|
|
579
|
+
const wanted = new Set(nodeIds);
|
|
580
|
+
if (wanted.size === 0)
|
|
581
|
+
return [];
|
|
582
|
+
const byParent = new Map();
|
|
583
|
+
for (const node of doc.nodes) {
|
|
584
|
+
if (!wanted.has(node.id))
|
|
585
|
+
continue;
|
|
586
|
+
const list = byParent.get(node.parentId) ?? [];
|
|
587
|
+
list.push(node);
|
|
588
|
+
byParent.set(node.parentId, list);
|
|
589
|
+
}
|
|
590
|
+
const moves = [];
|
|
591
|
+
for (const [parentId, newcomers] of byParent) {
|
|
592
|
+
const placed = doc.nodes.filter((node) => !wanted.has(node.id) && (node.parentId ?? undefined) === parentId);
|
|
593
|
+
const maxY = placed.reduce((max, node) => Math.max(max, node.position.y + node.size.height), parentId ? 48 : 0);
|
|
594
|
+
const minX = placed.reduce((min, node) => Math.min(min, node.position.x), placed.length > 0 ? Infinity : parentId ? 24 : 0);
|
|
595
|
+
const startX = Number.isFinite(minX) ? minX : 0;
|
|
596
|
+
let cursorX = startX;
|
|
597
|
+
let cursorY = placed.length > 0 ? maxY + gap * 2 : maxY;
|
|
598
|
+
let rowHeight = 0;
|
|
599
|
+
const rowLimit = 1200;
|
|
600
|
+
for (const node of newcomers) {
|
|
601
|
+
if (cursorX + node.size.width > rowLimit && cursorX > startX) {
|
|
602
|
+
cursorX = startX;
|
|
603
|
+
cursorY += rowHeight + gap;
|
|
604
|
+
rowHeight = 0;
|
|
605
|
+
}
|
|
606
|
+
moves.push({ id: node.id, position: { x: cursorX, y: cursorY } });
|
|
607
|
+
cursorX += node.size.width + gap;
|
|
608
|
+
rowHeight = Math.max(rowHeight, node.size.height);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
return moves.length > 0 ? [{ op: "moveNodes", moves }] : [];
|
|
612
|
+
};
|
|
613
|
+
exports.placeNewNodesOps = placeNewNodesOps;
|
|
614
|
+
// Whether an ops batch (typically from a model) deletes a large part of the
|
|
615
|
+
// diagram — hosts confirm with the user before applying such a batch.
|
|
616
|
+
const assessOpsRisk = (doc, ops, threshold = 0.3, minimum = 3) => {
|
|
617
|
+
const removes = new Set();
|
|
618
|
+
const collect = (list) => {
|
|
619
|
+
for (const op of list) {
|
|
620
|
+
if (op.op === "removeNode")
|
|
621
|
+
removes.add(op.id);
|
|
622
|
+
else if (op.op === "batch")
|
|
623
|
+
collect(op.ops);
|
|
624
|
+
else if (op.op === "replaceDocument")
|
|
625
|
+
for (const node of doc.nodes)
|
|
626
|
+
if (!op.document.nodes.some((n) => n.id === node.id))
|
|
627
|
+
removes.add(node.id);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
collect(ops);
|
|
631
|
+
const totalNodes = doc.nodes.length;
|
|
632
|
+
const ratio = totalNodes === 0 ? 0 : removes.size / totalNodes;
|
|
633
|
+
return { removesNodes: removes.size, totalNodes, ratio, destructive: removes.size >= minimum && ratio > threshold };
|
|
634
|
+
};
|
|
635
|
+
exports.assessOpsRisk = assessOpsRisk;
|
|
636
|
+
//# sourceMappingURL=patchInput.js.map
|