callman-core 1.28.1 → 1.30.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/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.d.ts.map +1 -1
- 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 +61 -5
- package/dist/ai/prompts/diagram.js.map +1 -1
- 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/componentCatalog.d.ts +3 -0
- package/dist/diagram/componentCatalog.d.ts.map +1 -1
- package/dist/diagram/componentCatalog.js +5 -1
- package/dist/diagram/componentCatalog.js.map +1 -1
- package/dist/diagram/database/derive.d.ts +14 -0
- package/dist/diagram/database/derive.d.ts.map +1 -0
- package/dist/diagram/database/derive.js +114 -0
- package/dist/diagram/database/derive.js.map +1 -0
- package/dist/diagram/database/diff.d.ts +48 -0
- package/dist/diagram/database/diff.d.ts.map +1 -0
- package/dist/diagram/database/diff.js +109 -0
- package/dist/diagram/database/diff.js.map +1 -0
- package/dist/diagram/database/edit.d.ts +113 -0
- package/dist/diagram/database/edit.d.ts.map +1 -0
- package/dist/diagram/database/edit.js +359 -0
- package/dist/diagram/database/edit.js.map +1 -0
- package/dist/diagram/database/fromSchema.d.ts +12 -0
- package/dist/diagram/database/fromSchema.d.ts.map +1 -0
- package/dist/diagram/database/fromSchema.js +182 -0
- package/dist/diagram/database/fromSchema.js.map +1 -0
- package/dist/diagram/database/index.d.ts +9 -0
- package/dist/diagram/database/index.d.ts.map +1 -0
- package/dist/diagram/database/index.js +14 -0
- package/dist/diagram/database/index.js.map +1 -0
- package/dist/diagram/database/model.d.ts +93 -0
- package/dist/diagram/database/model.d.ts.map +1 -0
- package/dist/diagram/database/model.js +294 -0
- package/dist/diagram/database/model.js.map +1 -0
- package/dist/diagram/database/patch.d.ts +14 -0
- package/dist/diagram/database/patch.d.ts.map +1 -0
- package/dist/diagram/database/patch.js +186 -0
- package/dist/diagram/database/patch.js.map +1 -0
- package/dist/diagram/database/place.d.ts +4 -0
- package/dist/diagram/database/place.d.ts.map +1 -0
- package/dist/diagram/database/place.js +22 -0
- package/dist/diagram/database/place.js.map +1 -0
- package/dist/diagram/database/types.d.ts +50 -0
- package/dist/diagram/database/types.d.ts.map +1 -0
- package/dist/diagram/database/types.js +106 -0
- package/dist/diagram/database/types.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 +15 -2
- package/dist/diagram/index.d.ts.map +1 -1
- package/dist/diagram/index.js +21 -8
- package/dist/diagram/index.js.map +1 -1
- package/dist/diagram/layout.d.ts +108 -0
- package/dist/diagram/layout.d.ts.map +1 -0
- package/dist/diagram/layout.js +357 -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 +865 -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 +60 -0
- package/dist/diagram/opsReference.js.map +1 -0
- package/dist/diagram/patchInput.d.ts +257 -0
- package/dist/diagram/patchInput.d.ts.map +1 -0
- package/dist/diagram/patchInput.js +1024 -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 +71 -38
- 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 +22 -0
- package/dist/diagram/views.d.ts.map +1 -0
- package/dist/diagram/views.js +91 -0
- package/dist/diagram/views.js.map +1 -0
- package/dist/host/db/introspection/index.d.ts +9 -0
- package/dist/host/db/introspection/index.d.ts.map +1 -0
- package/dist/host/db/introspection/index.js +35 -0
- package/dist/host/db/introspection/index.js.map +1 -0
- package/dist/host/db/introspection/mongo.d.ts +7 -0
- package/dist/host/db/introspection/mongo.d.ts.map +1 -0
- package/dist/host/db/introspection/mongo.js +183 -0
- package/dist/host/db/introspection/mongo.js.map +1 -0
- package/dist/host/db/introspection/mssql.d.ts +6 -0
- package/dist/host/db/introspection/mssql.d.ts.map +1 -0
- package/dist/host/db/introspection/mssql.js +211 -0
- package/dist/host/db/introspection/mssql.js.map +1 -0
- package/dist/host/db/introspection/mysql.d.ts +5 -0
- package/dist/host/db/introspection/mysql.d.ts.map +1 -0
- package/dist/host/db/introspection/mysql.js +163 -0
- package/dist/host/db/introspection/mysql.js.map +1 -0
- package/dist/host/db/introspection/oracle.d.ts +12 -0
- package/dist/host/db/introspection/oracle.d.ts.map +1 -0
- package/dist/host/db/introspection/oracle.js +225 -0
- package/dist/host/db/introspection/oracle.js.map +1 -0
- package/dist/host/db/introspection/postgres.d.ts +5 -0
- package/dist/host/db/introspection/postgres.d.ts.map +1 -0
- package/dist/host/db/introspection/postgres.js +172 -0
- package/dist/host/db/introspection/postgres.js.map +1 -0
- package/dist/host/db/introspection/shared.d.ts +29 -0
- package/dist/host/db/introspection/shared.d.ts.map +1 -0
- package/dist/host/db/introspection/shared.js +119 -0
- package/dist/host/db/introspection/shared.js.map +1 -0
- package/dist/host/db/introspection/types.d.ts +58 -0
- package/dist/host/db/introspection/types.d.ts.map +1 -0
- package/dist/host/db/introspection/types.js +6 -0
- package/dist/host/db/introspection/types.js.map +1 -0
- package/dist/host/db/mongoAdapter.d.ts +1 -0
- package/dist/host/db/mongoAdapter.d.ts.map +1 -1
- package/dist/host/db/mongoAdapter.js +13 -0
- package/dist/host/db/mongoAdapter.js.map +1 -1
- package/dist/host/db/mssqlAdapter.d.ts +1 -0
- package/dist/host/db/mssqlAdapter.d.ts.map +1 -1
- package/dist/host/db/mssqlAdapter.js +3 -1
- package/dist/host/db/mssqlAdapter.js.map +1 -1
- package/dist/host/db/mysqlAdapter.d.ts +1 -0
- package/dist/host/db/mysqlAdapter.d.ts.map +1 -1
- package/dist/host/db/mysqlAdapter.js +11 -0
- package/dist/host/db/mysqlAdapter.js.map +1 -1
- package/dist/host/db/oracleAdapter.d.ts +1 -0
- package/dist/host/db/oracleAdapter.d.ts.map +1 -1
- package/dist/host/db/oracleAdapter.js +22 -0
- package/dist/host/db/oracleAdapter.js.map +1 -1
- package/dist/host/db/postgresAdapter.d.ts +1 -0
- package/dist/host/db/postgresAdapter.d.ts.map +1 -1
- package/dist/host/db/postgresAdapter.js +13 -0
- package/dist/host/db/postgresAdapter.js.map +1 -1
- package/dist/host/db/queryExecutor.d.ts +2 -1
- package/dist/host/db/queryExecutor.d.ts.map +1 -1
- package/dist/host/db/queryExecutor.js +1 -1
- package/dist/host/db/queryExecutor.js.map +1 -1
- package/dist/host/index.d.ts +7 -0
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js +9 -0
- package/dist/host/index.js.map +1 -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 +61 -5
- package/dist-cjs/ai/prompts/diagram.js.map +1 -1
- 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/componentCatalog.js +5 -1
- package/dist-cjs/diagram/componentCatalog.js.map +1 -1
- package/dist-cjs/diagram/database/derive.js +119 -0
- package/dist-cjs/diagram/database/derive.js.map +1 -0
- package/dist-cjs/diagram/database/diff.js +115 -0
- package/dist-cjs/diagram/database/diff.js.map +1 -0
- package/dist-cjs/diagram/database/edit.js +366 -0
- package/dist-cjs/diagram/database/edit.js.map +1 -0
- package/dist-cjs/diagram/database/fromSchema.js +188 -0
- package/dist-cjs/diagram/database/fromSchema.js.map +1 -0
- package/dist-cjs/diagram/database/index.js +32 -0
- package/dist-cjs/diagram/database/index.js.map +1 -0
- package/dist-cjs/diagram/database/model.js +311 -0
- package/dist-cjs/diagram/database/model.js.map +1 -0
- package/dist-cjs/diagram/database/patch.js +190 -0
- package/dist-cjs/diagram/database/patch.js.map +1 -0
- package/dist-cjs/diagram/database/place.js +26 -0
- package/dist-cjs/diagram/database/place.js.map +1 -0
- package/dist-cjs/diagram/database/types.js +122 -0
- package/dist-cjs/diagram/database/types.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 +24 -8
- package/dist-cjs/diagram/index.js.map +1 -1
- package/dist-cjs/diagram/layout.js +365 -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 +871 -0
- package/dist-cjs/diagram/ops.js.map +1 -0
- package/dist-cjs/diagram/opsReference.js +64 -0
- package/dist-cjs/diagram/opsReference.js.map +1 -0
- package/dist-cjs/diagram/patchInput.js +1039 -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 +96 -0
- package/dist-cjs/diagram/views.js.map +1 -0
- package/dist-cjs/host/db/introspection/index.js +59 -0
- package/dist-cjs/host/db/introspection/index.js.map +1 -0
- package/dist-cjs/host/db/introspection/mongo.js +189 -0
- package/dist-cjs/host/db/introspection/mongo.js.map +1 -0
- package/dist-cjs/host/db/introspection/mssql.js +216 -0
- package/dist-cjs/host/db/introspection/mssql.js.map +1 -0
- package/dist-cjs/host/db/introspection/mysql.js +167 -0
- package/dist-cjs/host/db/introspection/mysql.js.map +1 -0
- package/dist-cjs/host/db/introspection/oracle.js +230 -0
- package/dist-cjs/host/db/introspection/oracle.js.map +1 -0
- package/dist-cjs/host/db/introspection/postgres.js +176 -0
- package/dist-cjs/host/db/introspection/postgres.js.map +1 -0
- package/dist-cjs/host/db/introspection/shared.js +133 -0
- package/dist-cjs/host/db/introspection/shared.js.map +1 -0
- package/dist-cjs/host/db/introspection/types.js +7 -0
- package/dist-cjs/host/db/introspection/types.js.map +1 -0
- package/dist-cjs/host/db/mongoAdapter.js +15 -1
- package/dist-cjs/host/db/mongoAdapter.js.map +1 -1
- package/dist-cjs/host/db/mssqlAdapter.js +5 -2
- package/dist-cjs/host/db/mssqlAdapter.js.map +1 -1
- package/dist-cjs/host/db/mysqlAdapter.js +13 -1
- package/dist-cjs/host/db/mysqlAdapter.js.map +1 -1
- package/dist-cjs/host/db/oracleAdapter.js +24 -1
- package/dist-cjs/host/db/oracleAdapter.js.map +1 -1
- package/dist-cjs/host/db/postgresAdapter.js +15 -1
- package/dist-cjs/host/db/postgresAdapter.js.map +1 -1
- package/dist-cjs/host/db/queryExecutor.js +5 -4
- package/dist-cjs/host/db/queryExecutor.js.map +1 -1
- package/dist-cjs/host/index.js +24 -1
- package/dist-cjs/host/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1024 @@
|
|
|
1
|
+
// The AUTHORING vocabulary — the compact shape AI models and MCP clients
|
|
2
|
+
// write (`parent` not `parentId`, a `semantic` instead of a dash tuple, CSS
|
|
3
|
+
// colors, optional positions) — lowered onto the canonical ops of ops.ts.
|
|
4
|
+
// One implementation of the merge rules, type checks and suggestions, shared
|
|
5
|
+
// by the MCP server (behind its zod schemas), the AI EDIT mode and imports.
|
|
6
|
+
// Moved from the MCP server's build.ts / patch.ts.
|
|
7
|
+
import { BPMN_CONTAINER_TYPES, bpmnElementForType, getBpmnType, isBpmnContainerType, suggestBpmnTypes } from "./bpmn/types.js";
|
|
8
|
+
import { applyDatabaseEdits, DATABASE_GRAMMAR_VERSION, DatabaseEditError, databaseEntitySize, DB_NODE_TYPES, emptyDatabaseModel, findEntity, isValidCardinality, kindForDatabaseType, markersForCardinality, parseDatabaseModel, serializeDatabaseModel, suggestDatabaseTypes, } from "./database/index.js";
|
|
9
|
+
import { DIAGRAM_COMPONENT_CATALOG, getDiagramComponent, searchDiagramComponents } from "./componentCatalog.js";
|
|
10
|
+
import { isBusComponentType, isDefaultEdgeStyle, semanticStyle } from "./edgeSemantics.js";
|
|
11
|
+
import { absolutePosition, absoluteRect, boundingBox, indexNodes, toParentRelative } from "./geometry.js";
|
|
12
|
+
import { sequentialIdFactory, slugIdFactory } from "./ids.js";
|
|
13
|
+
import { normalizeDiagramStyles } from "./normalize.js";
|
|
14
|
+
import { DiagramOpError } from "./ops.js";
|
|
15
|
+
import { nowIso, safeParseDiagramDocument, SCHEMA_VERSION, } from "./schema.js";
|
|
16
|
+
import { applyStyleInput, styleInputToChanges, toTokenRef } from "./styleInput.js";
|
|
17
|
+
// --- catalog helpers ---------------------------------------------------------------
|
|
18
|
+
export const suggestComponentTypes = (type, limit = 5) => {
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
const out = [];
|
|
21
|
+
const push = (candidate) => {
|
|
22
|
+
if (!seen.has(candidate) && out.length < limit) {
|
|
23
|
+
seen.add(candidate);
|
|
24
|
+
out.push(candidate);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
for (const entry of searchDiagramComponents(type))
|
|
28
|
+
push(entry.type);
|
|
29
|
+
// A typo usually sits at the END of the last segment ("db.postgresqlx"):
|
|
30
|
+
// shrink it until something in the catalog contains it.
|
|
31
|
+
const tail = (type.split(".").pop() ?? type).toLowerCase();
|
|
32
|
+
for (let length = tail.length; length >= 3 && out.length < limit; length -= 1) {
|
|
33
|
+
const needle = tail.slice(0, length);
|
|
34
|
+
for (const entry of DIAGRAM_COMPONENT_CATALOG) {
|
|
35
|
+
const haystack = [entry.type, entry.label, ...(entry.aliases ?? [])].join(" ").toLowerCase();
|
|
36
|
+
if (haystack.includes(needle))
|
|
37
|
+
push(entry.type);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Still nothing: offer the same namespace ("db.*", "aws.*").
|
|
41
|
+
const namespace = type.includes(".") ? `${type.split(".")[0].toLowerCase()}.` : null;
|
|
42
|
+
if (namespace) {
|
|
43
|
+
for (const entry of DIAGRAM_COMPONENT_CATALOG)
|
|
44
|
+
if (entry.type.toLowerCase().startsWith(namespace))
|
|
45
|
+
push(entry.type);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
};
|
|
49
|
+
// Containers hold children through `parent`: frames and swimlane pools.
|
|
50
|
+
export const isContainerType = (type) => {
|
|
51
|
+
const def = type ? getDiagramComponent(type) : undefined;
|
|
52
|
+
return Boolean(def?.container || def?.swimlane);
|
|
53
|
+
};
|
|
54
|
+
export const containerTypes = () => DIAGRAM_COMPONENT_CATALOG.filter((entry) => entry.container || entry.swimlane).map((entry) => entry.type);
|
|
55
|
+
export const parentWarning = (id, parentId, parentType, kind = "canvas") => {
|
|
56
|
+
if (kind === "database")
|
|
57
|
+
return `Node ${id} sits inside "${parentId}" — database diagrams have no containers; the parent is ignored.`;
|
|
58
|
+
if (kind === "bpmn") {
|
|
59
|
+
return isBpmnContainerType(parentType)
|
|
60
|
+
? null
|
|
61
|
+
: `Node ${id} sits inside "${parentId}" (${parentType ?? "unknown"}), which is not a BPMN container — use ${BPMN_CONTAINER_TYPES.join(", ")}.`;
|
|
62
|
+
}
|
|
63
|
+
return isContainerType(parentType)
|
|
64
|
+
? null
|
|
65
|
+
: `Node ${id} sits inside "${parentId}" (${parentType ?? "unknown"}), which is not a container — use ${containerTypes().join(", ")} to group nodes.`;
|
|
66
|
+
};
|
|
67
|
+
// line / arrow / line.dashed are palette connectors (0-height), not nodes.
|
|
68
|
+
export const assertNotConnector = (type, id, opIndex = -1) => {
|
|
69
|
+
if (getDiagramComponent(type)?.variant === "line") {
|
|
70
|
+
throw new DiagramOpError("DIAGRAM_CONNECTOR_NOT_NODE", `"${type}" on ${id} is a connector, not a node — draw it as an edge between two nodes.`, opIndex);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
// Edge input → the stored edge's visual fields: the semantic's line tuple
|
|
74
|
+
// plus an optional color.
|
|
75
|
+
export const edgeStyleFor = (semantic, color) => {
|
|
76
|
+
const base = semantic ? semanticStyle(semantic) : undefined;
|
|
77
|
+
if (!color)
|
|
78
|
+
return base;
|
|
79
|
+
return { ...(base ?? {}), stroke: toTokenRef(color) };
|
|
80
|
+
};
|
|
81
|
+
const resolveType = (type, id, strict, warnings, opIndex, kind = "canvas") => {
|
|
82
|
+
const trimmed = type.trim();
|
|
83
|
+
if (kind === "database") {
|
|
84
|
+
if (DB_NODE_TYPES.includes(trimmed))
|
|
85
|
+
return { type: trimmed, known: true };
|
|
86
|
+
const suggestions = suggestDatabaseTypes(trimmed);
|
|
87
|
+
if (strict) {
|
|
88
|
+
throw new DiagramOpError("DIAGRAM_UNKNOWN_COMPONENT_TYPE", `Unknown database type "${trimmed}" on ${id}. A database diagram has db.table, db.view and db.collection (prefer the DATABASE OPS: addTable, addColumn, addRelationship …), or pass strictTypes:false to draw it as a table.`, opIndex, { unknownTypes: [{ type: trimmed, suggestions }] });
|
|
89
|
+
}
|
|
90
|
+
warnings.push(`Unknown database type "${trimmed}" on ${id} → drawn as a table`);
|
|
91
|
+
return { type: "db.table", known: false };
|
|
92
|
+
}
|
|
93
|
+
if (kind === "bpmn") {
|
|
94
|
+
if (getBpmnType(trimmed))
|
|
95
|
+
return { type: trimmed, known: true };
|
|
96
|
+
const suggestions = suggestBpmnTypes(trimmed);
|
|
97
|
+
if (strict) {
|
|
98
|
+
throw new 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 }] });
|
|
99
|
+
}
|
|
100
|
+
warnings.push(`Unknown BPMN type "${trimmed}" on ${id} → drawn as a task (suggestions: ${suggestions.join(", ") || "none"})`);
|
|
101
|
+
return { type: "bpmn.task", known: false };
|
|
102
|
+
}
|
|
103
|
+
if (getDiagramComponent(trimmed)) {
|
|
104
|
+
assertNotConnector(trimmed, id, opIndex);
|
|
105
|
+
return { type: trimmed, known: true };
|
|
106
|
+
}
|
|
107
|
+
const suggestions = suggestComponentTypes(trimmed);
|
|
108
|
+
if (strict) {
|
|
109
|
+
throw new 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 }] });
|
|
110
|
+
}
|
|
111
|
+
warnings.push(`Unknown component type "${trimmed}" on ${id} → drawn as a rectangle (suggestions: ${suggestions.join(", ") || "none"})`);
|
|
112
|
+
return { type: "rect", known: false };
|
|
113
|
+
};
|
|
114
|
+
const nodeFromInput = (input, id, strict, warnings, opIndex, kind = "canvas") => {
|
|
115
|
+
const { type, known } = resolveType(input.type, id, strict, warnings, opIndex, kind);
|
|
116
|
+
const def = kind === "canvas" ? getDiagramComponent(type) : undefined;
|
|
117
|
+
const bpmn = kind === "bpmn" ? getBpmnType(type) : undefined;
|
|
118
|
+
const dbRaw = kind === "database" ? (input.data?.db ?? {}) : undefined;
|
|
119
|
+
const label = kind === "database"
|
|
120
|
+
? (typeof dbRaw?.name === "string" && dbRaw.name.trim()) || input.label || id
|
|
121
|
+
: input.label !== undefined || !known
|
|
122
|
+
? (input.label ?? input.type)
|
|
123
|
+
: def?.defaultLabel;
|
|
124
|
+
// A BPMN node always knows which element it stands for; a database node its
|
|
125
|
+
// table name and kind (its `columns` stay the authoring input until the
|
|
126
|
+
// model absorbs them).
|
|
127
|
+
const data = kind === "bpmn"
|
|
128
|
+
? { ...(input.data ?? {}), bpmn: { ...(input.data?.bpmn ?? {}), element: bpmnElementForType(type) ?? "task" } }
|
|
129
|
+
: kind === "database"
|
|
130
|
+
? { ...(input.data ?? {}), db: { ...dbRaw, name: label, kind: kindForDatabaseType(type) } }
|
|
131
|
+
: input.data;
|
|
132
|
+
const dbColumns = Array.isArray(dbRaw?.columns) ? dbRaw.columns : [];
|
|
133
|
+
const dbSize = kind === "database"
|
|
134
|
+
? databaseEntitySize({
|
|
135
|
+
name: String(label),
|
|
136
|
+
...(typeof dbRaw?.schema === "string" ? { schema: dbRaw.schema } : {}),
|
|
137
|
+
columns: dbColumns.map((column) => {
|
|
138
|
+
const raw = (column ?? {});
|
|
139
|
+
return { name: typeof raw.name === "string" ? raw.name : "", dataType: typeof raw.dataType === "string" ? raw.dataType : typeof raw.type === "string" ? raw.type : "" };
|
|
140
|
+
}),
|
|
141
|
+
})
|
|
142
|
+
: undefined;
|
|
143
|
+
const node = {
|
|
144
|
+
id,
|
|
145
|
+
type,
|
|
146
|
+
position: input.position ?? { x: 0, y: 0 },
|
|
147
|
+
size: input.size ?? bpmn?.size ?? dbSize ?? def?.defaultSize ?? { width: 140, height: 60 },
|
|
148
|
+
...(label !== undefined ? { label } : {}),
|
|
149
|
+
...(input.parent ? { parentId: input.parent } : {}),
|
|
150
|
+
...(input.style ? { style: applyStyleInput(undefined, input.style) } : {}),
|
|
151
|
+
...(input.rotation ? { rotation: input.rotation } : {}),
|
|
152
|
+
...(input.locked ? { locked: true } : {}),
|
|
153
|
+
...(input.hidden ? { hidden: true } : {}),
|
|
154
|
+
...(input.collapsed ? { collapsed: true } : {}),
|
|
155
|
+
...(data ? { data } : {}),
|
|
156
|
+
};
|
|
157
|
+
if (node.style === undefined)
|
|
158
|
+
delete node.style;
|
|
159
|
+
return node;
|
|
160
|
+
};
|
|
161
|
+
const edgeFromInput = (input, id, typeOf, kind = "canvas") => {
|
|
162
|
+
let semantic = input.semantic;
|
|
163
|
+
// A fresh edge into a broker reads as a bus line — the studio's own rule.
|
|
164
|
+
if (kind === "canvas" && !semantic && (isBusComponentType(typeOf(input.source)) || isBusComponentType(typeOf(input.target))))
|
|
165
|
+
semantic = "bus";
|
|
166
|
+
// A BPMN flow is a sequence flow unless said otherwise; a database edge is
|
|
167
|
+
// a relationship (manual, N:1 unless said otherwise) with crow's-foot ends.
|
|
168
|
+
const dbRaw = kind === "database" ? (input.data?.db ?? {}) : undefined;
|
|
169
|
+
const cardinality = isValidCardinality(dbRaw?.cardinality) ? dbRaw.cardinality : "N:1";
|
|
170
|
+
const data = kind === "bpmn"
|
|
171
|
+
? { ...(input.data ?? {}), bpmn: { flow: "sequence", ...(input.data?.bpmn ?? {}) } }
|
|
172
|
+
: kind === "database"
|
|
173
|
+
? { ...(input.data ?? {}), db: { kind: "manual", sourceColumns: [], targetColumns: [], ...dbRaw, cardinality } }
|
|
174
|
+
: input.data;
|
|
175
|
+
const dbMarkers = kind === "database" ? markersForCardinality(cardinality) : undefined;
|
|
176
|
+
const style = edgeStyleFor(semantic, input.color);
|
|
177
|
+
const markerStart = input.markerStart ?? dbMarkers?.markerStart;
|
|
178
|
+
return {
|
|
179
|
+
id,
|
|
180
|
+
source: input.source,
|
|
181
|
+
target: input.target,
|
|
182
|
+
...(input.label ? { label: input.label } : {}),
|
|
183
|
+
...(input.routing ? { routing: input.routing } : {}),
|
|
184
|
+
markerEnd: input.markerEnd ?? dbMarkers?.markerEnd ?? "classicThin",
|
|
185
|
+
...(markerStart && markerStart !== "none" ? { markerStart } : {}),
|
|
186
|
+
...(input.sourceSide ? { sourceHandle: input.sourceSide } : {}),
|
|
187
|
+
...(input.targetSide ? { targetHandle: input.targetSide } : {}),
|
|
188
|
+
...(style && (!isDefaultEdgeStyle(style) || semantic === "sync" || input.color) ? { style } : {}),
|
|
189
|
+
...(data ? { data } : {}),
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
// --- lowering -----------------------------------------------------------------------
|
|
193
|
+
export const lowerPatchOps = (doc, input, options = {}) => {
|
|
194
|
+
const strict = options.strictTypes !== false;
|
|
195
|
+
const kind = options.kind ?? (doc.source?.format === "bpmn" ? "bpmn" : doc.source?.format === "database" ? "database" : "canvas");
|
|
196
|
+
if (kind === "database")
|
|
197
|
+
return lowerDatabasePatchOps(doc, input, { ...options, strict });
|
|
198
|
+
const warnings = [];
|
|
199
|
+
const unpositionedNodeIds = [];
|
|
200
|
+
const idMap = {};
|
|
201
|
+
const ops = [];
|
|
202
|
+
let relayout;
|
|
203
|
+
// A working view of ids/types/parents so later ops in the same batch can
|
|
204
|
+
// reference nodes added earlier — the ops themselves stay canonical.
|
|
205
|
+
const nodes = new Map(doc.nodes.map((node) => [node.id, { ...node }]));
|
|
206
|
+
const edges = new Map(doc.edges.map((edge) => [edge.id, { ...edge }]));
|
|
207
|
+
const takenIds = () => [...nodes.keys(), ...edges.keys()];
|
|
208
|
+
const genNodeId = options.genNodeId ?? slugIdFactory(takenIds(), "n");
|
|
209
|
+
const genEdgeId = options.genEdgeId ?? sequentialIdFactory("e", takenIds());
|
|
210
|
+
const typeOf = (id) => nodes.get(id)?.type;
|
|
211
|
+
const mapId = (id) => idMap[id] ?? id;
|
|
212
|
+
const requireNode = (id, index) => {
|
|
213
|
+
const node = nodes.get(mapId(id));
|
|
214
|
+
if (!node)
|
|
215
|
+
throw new DiagramOpError("DIAGRAM_NODE_NOT_FOUND", `Node "${id}" does not exist.`, index);
|
|
216
|
+
return node;
|
|
217
|
+
};
|
|
218
|
+
input.forEach((op, index) => {
|
|
219
|
+
switch (op.op) {
|
|
220
|
+
case "setTitle":
|
|
221
|
+
ops.push({ op: "setTitle", title: op.title });
|
|
222
|
+
return;
|
|
223
|
+
case "addNode": {
|
|
224
|
+
const requested = op.node.id?.trim();
|
|
225
|
+
let id = requested || genNodeId(op.node.label ?? op.node.type);
|
|
226
|
+
if (requested && (nodes.has(requested) || edges.has(requested))) {
|
|
227
|
+
throw new DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `A node with id "${requested}" already exists.`, index);
|
|
228
|
+
}
|
|
229
|
+
if (!requested && (nodes.has(id) || edges.has(id)))
|
|
230
|
+
id = genNodeId();
|
|
231
|
+
const parent = op.node.parent ? mapId(op.node.parent) : undefined;
|
|
232
|
+
if (parent && !nodes.has(parent))
|
|
233
|
+
throw new DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${op.node.parent}" does not exist.`, index);
|
|
234
|
+
const node = nodeFromInput({ ...op.node, parent }, id, strict, warnings, index, kind);
|
|
235
|
+
if (parent) {
|
|
236
|
+
const warning = parentWarning(id, parent, typeOf(parent), kind);
|
|
237
|
+
if (warning)
|
|
238
|
+
warnings.push(warning);
|
|
239
|
+
}
|
|
240
|
+
nodes.set(id, node);
|
|
241
|
+
if (requested && requested !== id)
|
|
242
|
+
idMap[requested] = id;
|
|
243
|
+
if (!op.node.position)
|
|
244
|
+
unpositionedNodeIds.push(id);
|
|
245
|
+
ops.push({ op: "addNode", node });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
case "updateNode": {
|
|
249
|
+
const id = mapId(op.id);
|
|
250
|
+
const node = requireNode(id, index);
|
|
251
|
+
const changes = op.changes;
|
|
252
|
+
const nodeChanges = {};
|
|
253
|
+
if (changes.type !== undefined)
|
|
254
|
+
nodeChanges.type = resolveType(changes.type, id, strict, warnings, index, kind).type;
|
|
255
|
+
if (changes.label !== undefined)
|
|
256
|
+
nodeChanges.label = changes.label;
|
|
257
|
+
if (changes.rotation !== undefined)
|
|
258
|
+
nodeChanges.rotation = changes.rotation;
|
|
259
|
+
if (changes.locked !== undefined)
|
|
260
|
+
nodeChanges.locked = changes.locked;
|
|
261
|
+
if (changes.hidden !== undefined)
|
|
262
|
+
nodeChanges.hidden = changes.hidden;
|
|
263
|
+
if (changes.collapsed !== undefined)
|
|
264
|
+
nodeChanges.collapsed = changes.collapsed;
|
|
265
|
+
if (changes.style !== undefined)
|
|
266
|
+
nodeChanges.style = changes.style === null ? null : styleInputToChanges(node.style, changes.style);
|
|
267
|
+
if (changes.data !== undefined)
|
|
268
|
+
nodeChanges.data = changes.data;
|
|
269
|
+
if (Object.keys(nodeChanges).length > 0) {
|
|
270
|
+
ops.push({ op: "updateNode", id, changes: nodeChanges });
|
|
271
|
+
const next = { ...node };
|
|
272
|
+
if (nodeChanges.type)
|
|
273
|
+
next.type = nodeChanges.type;
|
|
274
|
+
nodes.set(id, next);
|
|
275
|
+
}
|
|
276
|
+
if (changes.size !== undefined) {
|
|
277
|
+
ops.push({ op: "resizeNode", id, size: changes.size });
|
|
278
|
+
nodes.set(id, { ...nodes.get(id), size: changes.size });
|
|
279
|
+
}
|
|
280
|
+
if (changes.parent !== undefined) {
|
|
281
|
+
const parent = changes.parent ? mapId(changes.parent) : null;
|
|
282
|
+
if (parent && !nodes.has(parent))
|
|
283
|
+
throw new DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${changes.parent}" does not exist.`, index);
|
|
284
|
+
if (parent === id)
|
|
285
|
+
throw new DiagramOpError("DIAGRAM_PARENT_CYCLE", `Node "${id}" cannot contain itself.`, index);
|
|
286
|
+
const byId = indexNodes([...nodes.values()]);
|
|
287
|
+
const position = changes.position ?? toParentRelative(absolutePosition(nodes.get(id), byId), parent, byId);
|
|
288
|
+
ops.push({ op: "reparent", id, parentId: parent, position });
|
|
289
|
+
if (parent) {
|
|
290
|
+
const warning = parentWarning(id, parent, typeOf(parent), kind);
|
|
291
|
+
if (warning)
|
|
292
|
+
warnings.push(warning);
|
|
293
|
+
}
|
|
294
|
+
const next = { ...nodes.get(id), position };
|
|
295
|
+
if (parent)
|
|
296
|
+
next.parentId = parent;
|
|
297
|
+
else
|
|
298
|
+
delete next.parentId;
|
|
299
|
+
nodes.set(id, next);
|
|
300
|
+
}
|
|
301
|
+
else if (changes.position !== undefined) {
|
|
302
|
+
ops.push({ op: "moveNodes", moves: [{ id, position: changes.position }] });
|
|
303
|
+
nodes.set(id, { ...nodes.get(id), position: changes.position });
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
case "removeNode": {
|
|
308
|
+
const id = mapId(op.id);
|
|
309
|
+
requireNode(id, index);
|
|
310
|
+
ops.push({ op: "removeNode", id, children: "lift" });
|
|
311
|
+
nodes.delete(id);
|
|
312
|
+
for (const [edgeId, edge] of [...edges])
|
|
313
|
+
if (edge.source === id || edge.target === id)
|
|
314
|
+
edges.delete(edgeId);
|
|
315
|
+
for (const node of nodes.values())
|
|
316
|
+
if (node.parentId === id)
|
|
317
|
+
delete node.parentId;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
case "addEdge": {
|
|
321
|
+
const requested = op.edge.id?.trim();
|
|
322
|
+
let id = requested || genEdgeId();
|
|
323
|
+
if (requested && (edges.has(requested) || nodes.has(requested))) {
|
|
324
|
+
throw new DiagramOpError("DIAGRAM_DUPLICATE_EDGE_ID", `An edge with id "${requested}" already exists.`, index);
|
|
325
|
+
}
|
|
326
|
+
if (!requested && (edges.has(id) || nodes.has(id)))
|
|
327
|
+
id = genEdgeId();
|
|
328
|
+
const source = mapId(op.edge.source);
|
|
329
|
+
const target = mapId(op.edge.target);
|
|
330
|
+
for (const endpoint of [source, target]) {
|
|
331
|
+
if (!nodes.has(endpoint))
|
|
332
|
+
throw new DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge endpoint "${endpoint}" does not exist.`, index);
|
|
333
|
+
}
|
|
334
|
+
const edge = edgeFromInput({ ...op.edge, source, target }, id, typeOf, kind);
|
|
335
|
+
edges.set(id, edge);
|
|
336
|
+
ops.push({ op: "addEdge", edge });
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
case "updateEdge": {
|
|
340
|
+
const id = mapId(op.id);
|
|
341
|
+
const edge = edges.get(id);
|
|
342
|
+
if (!edge)
|
|
343
|
+
throw new DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
344
|
+
const changes = op.changes;
|
|
345
|
+
const edgeChanges = {};
|
|
346
|
+
if (changes.source !== undefined)
|
|
347
|
+
edgeChanges.source = mapId(changes.source);
|
|
348
|
+
if (changes.target !== undefined)
|
|
349
|
+
edgeChanges.target = mapId(changes.target);
|
|
350
|
+
if (changes.label !== undefined)
|
|
351
|
+
edgeChanges.label = changes.label === "" ? null : changes.label;
|
|
352
|
+
if (changes.routing !== undefined)
|
|
353
|
+
edgeChanges.routing = changes.routing;
|
|
354
|
+
if (changes.markerEnd !== undefined)
|
|
355
|
+
edgeChanges.markerEnd = changes.markerEnd;
|
|
356
|
+
if (changes.markerStart !== undefined)
|
|
357
|
+
edgeChanges.markerStart = changes.markerStart === "none" ? null : changes.markerStart;
|
|
358
|
+
if (changes.sourceSide !== undefined)
|
|
359
|
+
edgeChanges.sourceHandle = changes.sourceSide;
|
|
360
|
+
if (changes.targetSide !== undefined)
|
|
361
|
+
edgeChanges.targetHandle = changes.targetSide;
|
|
362
|
+
if (changes.data !== undefined)
|
|
363
|
+
edgeChanges.data = changes.data;
|
|
364
|
+
// The semantic owns the line tuple (dash + width); the color is kept
|
|
365
|
+
// unless it is changed explicitly.
|
|
366
|
+
if (changes.semantic !== undefined || changes.color !== undefined) {
|
|
367
|
+
const style = {};
|
|
368
|
+
if (changes.semantic !== undefined) {
|
|
369
|
+
const line = semanticStyle(changes.semantic);
|
|
370
|
+
style.dashed = line.dashed ?? null;
|
|
371
|
+
style.dashPattern = line.dashPattern ?? null;
|
|
372
|
+
style.strokeWidth = line.strokeWidth ?? null;
|
|
373
|
+
}
|
|
374
|
+
if (changes.color !== undefined)
|
|
375
|
+
style.stroke = changes.color === null ? null : toTokenRef(changes.color);
|
|
376
|
+
edgeChanges.style = style;
|
|
377
|
+
}
|
|
378
|
+
for (const endpoint of [edgeChanges.source, edgeChanges.target]) {
|
|
379
|
+
if (endpoint !== undefined && !nodes.has(endpoint)) {
|
|
380
|
+
throw new DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge endpoint "${endpoint}" does not exist.`, index);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (Object.keys(edgeChanges).length > 0) {
|
|
384
|
+
ops.push({ op: "updateEdge", id, changes: edgeChanges });
|
|
385
|
+
edges.set(id, { ...edge, ...(edgeChanges.source ? { source: edgeChanges.source } : {}), ...(edgeChanges.target ? { target: edgeChanges.target } : {}) });
|
|
386
|
+
}
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
case "removeEdge": {
|
|
390
|
+
const id = mapId(op.id);
|
|
391
|
+
if (!edges.has(id))
|
|
392
|
+
throw new DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
393
|
+
edges.delete(id);
|
|
394
|
+
ops.push({ op: "removeEdge", id });
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
case "moveNode": {
|
|
398
|
+
const id = mapId(op.id);
|
|
399
|
+
requireNode(id, index);
|
|
400
|
+
ops.push({ op: "moveNodes", moves: [{ id, position: op.position }] });
|
|
401
|
+
nodes.set(id, { ...nodes.get(id), position: op.position });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
case "reparent": {
|
|
405
|
+
const id = mapId(op.id);
|
|
406
|
+
const node = requireNode(id, index);
|
|
407
|
+
const parent = op.parent ? mapId(op.parent) : null;
|
|
408
|
+
if (parent && !nodes.has(parent))
|
|
409
|
+
throw new DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Parent "${op.parent}" does not exist.`, index);
|
|
410
|
+
const byId = indexNodes([...nodes.values()]);
|
|
411
|
+
const position = op.position ?? toParentRelative(absolutePosition(node, byId), parent, byId);
|
|
412
|
+
ops.push({ op: "reparent", id, parentId: parent, position });
|
|
413
|
+
const next = { ...node, position };
|
|
414
|
+
if (parent)
|
|
415
|
+
next.parentId = parent;
|
|
416
|
+
else
|
|
417
|
+
delete next.parentId;
|
|
418
|
+
nodes.set(id, next);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
case "setEdgeRoute": {
|
|
422
|
+
const id = mapId(op.id);
|
|
423
|
+
if (!edges.has(id))
|
|
424
|
+
throw new DiagramOpError("DIAGRAM_EDGE_NOT_FOUND", `Edge "${op.id}" does not exist.`, index);
|
|
425
|
+
const changes = {};
|
|
426
|
+
if (op.routing !== undefined)
|
|
427
|
+
changes.routing = op.routing;
|
|
428
|
+
if (op.sourceSide !== undefined)
|
|
429
|
+
changes.sourceHandle = op.sourceSide;
|
|
430
|
+
if (op.targetSide !== undefined)
|
|
431
|
+
changes.targetHandle = op.targetSide;
|
|
432
|
+
if (op.waypoints !== undefined)
|
|
433
|
+
changes.waypoints = op.waypoints;
|
|
434
|
+
// "Reset routing" when nothing else is asked.
|
|
435
|
+
if (Object.keys(changes).length === 0) {
|
|
436
|
+
changes.waypoints = null;
|
|
437
|
+
changes.sourceAnchor = null;
|
|
438
|
+
changes.targetAnchor = null;
|
|
439
|
+
}
|
|
440
|
+
ops.push({ op: "updateEdge", id, changes });
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
case "reorder": {
|
|
444
|
+
const id = mapId(op.id);
|
|
445
|
+
const node = requireNode(id, index);
|
|
446
|
+
const siblings = [...nodes.values()].filter((candidate) => (candidate.parentId ?? undefined) === (node.parentId ?? undefined));
|
|
447
|
+
const target = op.index === "front" ? siblings.length - 1 : op.index === "back" ? 0 : op.index;
|
|
448
|
+
ops.push({ op: "reorder", kind: "node", id, index: target });
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
case "setCanvas":
|
|
452
|
+
ops.push({ op: "setCanvas", changes: op.canvas });
|
|
453
|
+
return;
|
|
454
|
+
case "group": {
|
|
455
|
+
const memberIds = op.ids.map(mapId);
|
|
456
|
+
for (const memberId of memberIds)
|
|
457
|
+
requireNode(memberId, index);
|
|
458
|
+
const type = op.type ?? "frame";
|
|
459
|
+
if (!isContainerType(type)) {
|
|
460
|
+
throw new DiagramOpError("DIAGRAM_INVALID_OP", `"${type}" is not a container type — use ${containerTypes().join(", ")}.`, index);
|
|
461
|
+
}
|
|
462
|
+
const requested = op.id?.trim();
|
|
463
|
+
const groupId = requested || genNodeId(op.label ?? "group");
|
|
464
|
+
if (nodes.has(groupId) || edges.has(groupId))
|
|
465
|
+
throw new DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `A node with id "${groupId}" already exists.`, index);
|
|
466
|
+
const grouped = groupNodesOps({ ...doc, nodes: [...nodes.values()], edges: [...edges.values()] }, memberIds, { id: groupId, type, label: op.label });
|
|
467
|
+
ops.push(...grouped.ops);
|
|
468
|
+
nodes.set(groupId, grouped.container);
|
|
469
|
+
for (const [memberId, position] of Object.entries(grouped.memberPositions)) {
|
|
470
|
+
nodes.set(memberId, { ...nodes.get(memberId), parentId: groupId, position });
|
|
471
|
+
}
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
case "ungroup": {
|
|
475
|
+
const id = mapId(op.id);
|
|
476
|
+
requireNode(id, index);
|
|
477
|
+
ops.push({ op: "removeNode", id, children: "lift" });
|
|
478
|
+
nodes.delete(id);
|
|
479
|
+
for (const node of nodes.values())
|
|
480
|
+
if (node.parentId === id)
|
|
481
|
+
delete node.parentId;
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
case "relayout":
|
|
485
|
+
relayout = { scope: op.scope, ...(op.direction ? { direction: op.direction } : {}) };
|
|
486
|
+
return;
|
|
487
|
+
case "addTable":
|
|
488
|
+
case "renameTable":
|
|
489
|
+
case "removeTable":
|
|
490
|
+
case "setTableComment":
|
|
491
|
+
case "addColumn":
|
|
492
|
+
case "alterColumn":
|
|
493
|
+
case "removeColumn":
|
|
494
|
+
case "setPrimaryKey":
|
|
495
|
+
case "addRelationship":
|
|
496
|
+
case "updateRelationship":
|
|
497
|
+
case "removeRelationship":
|
|
498
|
+
case "hideTable":
|
|
499
|
+
case "showTable":
|
|
500
|
+
throw new DiagramOpError("DIAGRAM_INVALID_OP", `"${op.op}" is a database-diagram op; this diagram is a ${kind} diagram.`, index);
|
|
501
|
+
default:
|
|
502
|
+
throw new DiagramOpError("DIAGRAM_INVALID_OP", `Unknown op "${op.op}"`, index);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
return { ops, warnings, unpositionedNodeIds, ...(relayout ? { relayout } : {}), idMap };
|
|
506
|
+
};
|
|
507
|
+
// --- database diagrams -------------------------------------------------------------
|
|
508
|
+
//
|
|
509
|
+
// Every structural op (semantic or generic) becomes an edit of the database
|
|
510
|
+
// model; the batch then yields ONE setSource op (the model re-derives the
|
|
511
|
+
// nodes/edges) followed by the presentation ops (positions, visibility,
|
|
512
|
+
// routing) that address nodes by their entity ids.
|
|
513
|
+
const DATABASE_ERROR_CODES = {
|
|
514
|
+
DIAGRAM_TABLE_NOT_FOUND: "DIAGRAM_TABLE_NOT_FOUND",
|
|
515
|
+
DIAGRAM_COLUMN_NOT_FOUND: "DIAGRAM_COLUMN_NOT_FOUND",
|
|
516
|
+
DIAGRAM_RELATIONSHIP_NOT_FOUND: "DIAGRAM_RELATIONSHIP_NOT_FOUND",
|
|
517
|
+
DIAGRAM_DUPLICATE_TABLE: "DIAGRAM_DUPLICATE_TABLE",
|
|
518
|
+
DIAGRAM_DUPLICATE_COLUMN: "DIAGRAM_DUPLICATE_COLUMN",
|
|
519
|
+
DIAGRAM_INVALID_OP: "DIAGRAM_INVALID_OP",
|
|
520
|
+
};
|
|
521
|
+
const columnInputsOf = (value) => {
|
|
522
|
+
if (!Array.isArray(value))
|
|
523
|
+
return undefined;
|
|
524
|
+
return value
|
|
525
|
+
.filter((item) => Boolean(item) && typeof item === "object" && typeof item.name === "string")
|
|
526
|
+
.map((item) => ({
|
|
527
|
+
...(typeof item.id === "string" ? { id: item.id } : {}),
|
|
528
|
+
name: String(item.name),
|
|
529
|
+
dataType: typeof item.dataType === "string" ? item.dataType : typeof item.type === "string" ? item.type : "",
|
|
530
|
+
...(typeof item.nullable === "boolean" ? { nullable: item.nullable } : {}),
|
|
531
|
+
...(typeof item.primaryKey === "boolean" ? { primaryKey: item.primaryKey } : {}),
|
|
532
|
+
...(typeof item.unique === "boolean" ? { unique: item.unique } : {}),
|
|
533
|
+
...(item.defaultValue !== undefined && item.defaultValue !== null ? { defaultValue: String(item.defaultValue) } : {}),
|
|
534
|
+
...(typeof item.autoIncrement === "boolean" ? { autoIncrement: item.autoIncrement } : {}),
|
|
535
|
+
...(typeof item.comment === "string" ? { comment: item.comment } : {}),
|
|
536
|
+
}));
|
|
537
|
+
};
|
|
538
|
+
const lowerDatabasePatchOps = (doc, input, options) => {
|
|
539
|
+
const warnings = [];
|
|
540
|
+
const idMap = {};
|
|
541
|
+
const presentation = [];
|
|
542
|
+
const positioned = new Map();
|
|
543
|
+
const unpositionedNodeIds = [];
|
|
544
|
+
let relayout;
|
|
545
|
+
const parsed = doc.source?.format === "database" ? parseDatabaseModel(doc.source.text) : null;
|
|
546
|
+
if (parsed && !parsed.ok)
|
|
547
|
+
throw new DiagramOpError("DIAGRAM_DOCUMENT_INVALID", `The database model cannot be read: ${parsed.errors.join("; ")}`);
|
|
548
|
+
let model = parsed?.model ?? emptyDatabaseModel();
|
|
549
|
+
let changed = false;
|
|
550
|
+
const mapId = (id) => idMap[id] ?? id;
|
|
551
|
+
const run = (edits, index) => {
|
|
552
|
+
try {
|
|
553
|
+
const result = applyDatabaseEdits(model, edits);
|
|
554
|
+
model = result.model;
|
|
555
|
+
changed = changed || result.changed;
|
|
556
|
+
warnings.push(...result.warnings);
|
|
557
|
+
Object.assign(idMap, result.idMap);
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
if (error instanceof DatabaseEditError)
|
|
562
|
+
throw new DiagramOpError(DATABASE_ERROR_CODES[error.code], error.message, index);
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
const entityIdOf = (ref, index) => {
|
|
567
|
+
const entity = findEntity(model, mapId(ref));
|
|
568
|
+
if (!entity)
|
|
569
|
+
throw new DiagramOpError("DIAGRAM_TABLE_NOT_FOUND", `Table "${ref}" does not exist.`, index);
|
|
570
|
+
return entity.id;
|
|
571
|
+
};
|
|
572
|
+
const relationshipIdOf = (ref) => mapId(ref);
|
|
573
|
+
const noContainers = (index) => {
|
|
574
|
+
throw new DiagramOpError("DIAGRAM_INVALID_OP", "Database diagrams have no containers (group / ungroup / reparent do not apply).", index);
|
|
575
|
+
};
|
|
576
|
+
const endInput = (value) => (typeof value === "string" ? value : { ...value, table: mapId(value.table) });
|
|
577
|
+
input.forEach((op, index) => {
|
|
578
|
+
switch (op.op) {
|
|
579
|
+
case "setTitle":
|
|
580
|
+
presentation.push({ op: "setTitle", title: op.title });
|
|
581
|
+
return;
|
|
582
|
+
case "addTable": {
|
|
583
|
+
const result = run([{ kind: "addTable", table: op.table }], index);
|
|
584
|
+
const id = result.addedEntityIds[0];
|
|
585
|
+
if (op.position)
|
|
586
|
+
positioned.set(id, op.position);
|
|
587
|
+
else
|
|
588
|
+
unpositionedNodeIds.push(id);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
case "renameTable":
|
|
592
|
+
run([{ kind: "renameTable", table: mapId(op.table), name: op.name, ...(op.schema !== undefined ? { schema: op.schema } : {}) }], index);
|
|
593
|
+
return;
|
|
594
|
+
case "removeTable":
|
|
595
|
+
run([{ kind: "removeTable", table: mapId(op.table) }], index);
|
|
596
|
+
return;
|
|
597
|
+
case "setTableComment":
|
|
598
|
+
run([{ kind: "setTableComment", table: mapId(op.table), comment: op.comment }], index);
|
|
599
|
+
return;
|
|
600
|
+
case "addColumn":
|
|
601
|
+
run([{ kind: "addColumn", table: mapId(op.table), column: op.column, ...(op.after !== undefined ? { after: op.after } : {}) }], index);
|
|
602
|
+
return;
|
|
603
|
+
case "alterColumn":
|
|
604
|
+
run([{ kind: "alterColumn", table: mapId(op.table), column: op.column, changes: op.changes }], index);
|
|
605
|
+
return;
|
|
606
|
+
case "removeColumn":
|
|
607
|
+
run([{ kind: "removeColumn", table: mapId(op.table), column: op.column }], index);
|
|
608
|
+
return;
|
|
609
|
+
case "setPrimaryKey":
|
|
610
|
+
run([{ kind: "setPrimaryKey", table: mapId(op.table), columns: op.columns }], index);
|
|
611
|
+
return;
|
|
612
|
+
case "addRelationship":
|
|
613
|
+
run([
|
|
614
|
+
{
|
|
615
|
+
kind: "addRelationship",
|
|
616
|
+
...(op.id ? { id: op.id } : {}),
|
|
617
|
+
source: endInput(op.source),
|
|
618
|
+
target: endInput(op.target),
|
|
619
|
+
...(op.cardinality ? { cardinality: op.cardinality } : {}),
|
|
620
|
+
...(op.kind ? { relationshipKind: op.kind } : {}),
|
|
621
|
+
...(op.name ? { name: op.name } : {}),
|
|
622
|
+
...(op.label ? { label: op.label } : {}),
|
|
623
|
+
},
|
|
624
|
+
], index);
|
|
625
|
+
return;
|
|
626
|
+
case "updateRelationship": {
|
|
627
|
+
const { kind: relationshipKind, source, target, ...rest } = op.changes;
|
|
628
|
+
run([
|
|
629
|
+
{
|
|
630
|
+
kind: "updateRelationship",
|
|
631
|
+
relationship: relationshipIdOf(op.relationship),
|
|
632
|
+
changes: { ...rest, ...(source !== undefined ? { source: endInput(source) } : {}), ...(target !== undefined ? { target: endInput(target) } : {}), ...(relationshipKind ? { relationshipKind } : {}) },
|
|
633
|
+
},
|
|
634
|
+
], index);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
case "removeRelationship":
|
|
638
|
+
run([{ kind: "removeRelationship", relationship: relationshipIdOf(op.relationship) }], index);
|
|
639
|
+
return;
|
|
640
|
+
case "hideTable":
|
|
641
|
+
presentation.push({ op: "updateNode", id: entityIdOf(op.table, index), changes: { hidden: true } });
|
|
642
|
+
return;
|
|
643
|
+
case "showTable":
|
|
644
|
+
presentation.push({ op: "updateNode", id: entityIdOf(op.table, index), changes: { hidden: false } });
|
|
645
|
+
return;
|
|
646
|
+
case "addNode": {
|
|
647
|
+
const { type } = resolveType(op.node.type, op.node.id ?? op.node.label ?? "node", options.strict, warnings, index, "database");
|
|
648
|
+
if (op.node.parent)
|
|
649
|
+
warnings.push(parentWarning(op.node.id ?? "node", op.node.parent, undefined, "database") ?? "");
|
|
650
|
+
const raw = op.node.data?.db ?? {};
|
|
651
|
+
const name = (typeof raw.name === "string" && raw.name.trim()) || (op.node.label ?? "").trim() || op.node.id?.trim() || "table";
|
|
652
|
+
const result = run([
|
|
653
|
+
{
|
|
654
|
+
kind: "addTable",
|
|
655
|
+
table: {
|
|
656
|
+
...(op.node.id?.trim() ? { id: op.node.id.trim() } : {}),
|
|
657
|
+
name,
|
|
658
|
+
...(typeof raw.schema === "string" && raw.schema.trim() ? { schema: raw.schema.trim() } : {}),
|
|
659
|
+
kind: kindForDatabaseType(type),
|
|
660
|
+
...(columnInputsOf(raw.columns ?? raw.columnInputs) ? { columns: columnInputsOf(raw.columns ?? raw.columnInputs) } : {}),
|
|
661
|
+
...(typeof raw.comment === "string" && raw.comment.trim() ? { comment: raw.comment.trim() } : {}),
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
], index);
|
|
665
|
+
const id = result.addedEntityIds[0];
|
|
666
|
+
if (op.node.position)
|
|
667
|
+
positioned.set(id, op.node.position);
|
|
668
|
+
else
|
|
669
|
+
unpositionedNodeIds.push(id);
|
|
670
|
+
if (op.node.hidden)
|
|
671
|
+
presentation.push({ op: "updateNode", id, changes: { hidden: true } });
|
|
672
|
+
if (op.node.collapsed)
|
|
673
|
+
presentation.push({ op: "updateNode", id, changes: { collapsed: true } });
|
|
674
|
+
if (op.node.locked)
|
|
675
|
+
presentation.push({ op: "updateNode", id, changes: { locked: true } });
|
|
676
|
+
if (op.node.style)
|
|
677
|
+
presentation.push({ op: "updateNode", id, changes: { style: styleInputToChanges(undefined, op.node.style) } });
|
|
678
|
+
if (op.node.size)
|
|
679
|
+
presentation.push({ op: "resizeNode", id, size: op.node.size });
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
case "updateNode": {
|
|
683
|
+
const id = entityIdOf(op.id, index);
|
|
684
|
+
const changes = op.changes;
|
|
685
|
+
if (changes.parent)
|
|
686
|
+
noContainers(index);
|
|
687
|
+
const edits = [];
|
|
688
|
+
if (changes.type !== undefined) {
|
|
689
|
+
const { type } = resolveType(changes.type, id, options.strict, warnings, index, "database");
|
|
690
|
+
edits.push({ kind: "setTableKind", table: id, entityKind: kindForDatabaseType(type) });
|
|
691
|
+
}
|
|
692
|
+
const raw = changes.data && typeof changes.data.db === "object" && changes.data.db ? changes.data.db : undefined;
|
|
693
|
+
const requestedName = typeof raw?.name === "string" ? raw.name : typeof changes.label === "string" ? changes.label : undefined;
|
|
694
|
+
if (requestedName !== undefined) {
|
|
695
|
+
const dot = requestedName.lastIndexOf(".");
|
|
696
|
+
const schema = typeof raw?.schema === "string" ? raw.schema : dot > 0 ? requestedName.slice(0, dot) : undefined;
|
|
697
|
+
edits.push({ kind: "renameTable", table: id, name: dot > 0 && typeof raw?.name !== "string" ? requestedName.slice(dot + 1) : requestedName, ...(schema !== undefined ? { schema } : {}) });
|
|
698
|
+
}
|
|
699
|
+
else if (typeof raw?.schema === "string") {
|
|
700
|
+
const entity = findEntity(model, id);
|
|
701
|
+
if (entity)
|
|
702
|
+
edits.push({ kind: "renameTable", table: id, name: entity.name, schema: raw.schema || null });
|
|
703
|
+
}
|
|
704
|
+
if (raw && "comment" in raw)
|
|
705
|
+
edits.push({ kind: "setTableComment", table: id, comment: typeof raw.comment === "string" ? raw.comment : null });
|
|
706
|
+
const columns = raw ? columnInputsOf(raw.columns ?? raw.columnInputs) : undefined;
|
|
707
|
+
if (columns)
|
|
708
|
+
edits.push({ kind: "setColumns", table: id, columns });
|
|
709
|
+
if (edits.length > 0)
|
|
710
|
+
run(edits, index);
|
|
711
|
+
const nodeChanges = {};
|
|
712
|
+
if (changes.rotation !== undefined)
|
|
713
|
+
nodeChanges.rotation = changes.rotation;
|
|
714
|
+
if (changes.locked !== undefined)
|
|
715
|
+
nodeChanges.locked = changes.locked;
|
|
716
|
+
if (changes.hidden !== undefined)
|
|
717
|
+
nodeChanges.hidden = changes.hidden;
|
|
718
|
+
if (changes.collapsed !== undefined)
|
|
719
|
+
nodeChanges.collapsed = changes.collapsed;
|
|
720
|
+
if (changes.style !== undefined)
|
|
721
|
+
nodeChanges.style = changes.style === null ? null : styleInputToChanges(doc.nodes.find((node) => node.id === id)?.style, changes.style);
|
|
722
|
+
if (Object.keys(nodeChanges).length > 0)
|
|
723
|
+
presentation.push({ op: "updateNode", id, changes: nodeChanges });
|
|
724
|
+
if (changes.size !== undefined)
|
|
725
|
+
presentation.push({ op: "resizeNode", id, size: changes.size });
|
|
726
|
+
if (changes.position !== undefined)
|
|
727
|
+
presentation.push({ op: "moveNodes", moves: [{ id, position: changes.position }] });
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
case "removeNode":
|
|
731
|
+
run([{ kind: "removeTable", table: entityIdOf(op.id, index) }], index);
|
|
732
|
+
return;
|
|
733
|
+
case "addEdge": {
|
|
734
|
+
const raw = op.edge.data?.db ?? {};
|
|
735
|
+
const refs = (value) => (Array.isArray(value) ? value.filter((item) => typeof item === "string") : []);
|
|
736
|
+
const result = run([
|
|
737
|
+
{
|
|
738
|
+
kind: "addRelationship",
|
|
739
|
+
...(op.edge.id?.trim() ? { id: op.edge.id.trim() } : {}),
|
|
740
|
+
source: { table: entityIdOf(op.edge.source, index), columns: refs(raw.sourceColumns) },
|
|
741
|
+
target: { table: entityIdOf(op.edge.target, index), columns: refs(raw.targetColumns) },
|
|
742
|
+
...(isValidCardinality(raw.cardinality) ? { cardinality: raw.cardinality } : {}),
|
|
743
|
+
relationshipKind: raw.kind === "foreignKey" ? "foreignKey" : "manual",
|
|
744
|
+
...(typeof raw.name === "string" ? { name: raw.name } : {}),
|
|
745
|
+
...(op.edge.label ? { label: op.edge.label } : {}),
|
|
746
|
+
},
|
|
747
|
+
], index);
|
|
748
|
+
const id = result.addedRelationshipIds[0];
|
|
749
|
+
if (id && (op.edge.routing || op.edge.sourceSide || op.edge.targetSide || op.edge.color)) {
|
|
750
|
+
const edgeChanges = {};
|
|
751
|
+
if (op.edge.routing)
|
|
752
|
+
edgeChanges.routing = op.edge.routing;
|
|
753
|
+
if (op.edge.sourceSide)
|
|
754
|
+
edgeChanges.sourceHandle = op.edge.sourceSide;
|
|
755
|
+
if (op.edge.targetSide)
|
|
756
|
+
edgeChanges.targetHandle = op.edge.targetSide;
|
|
757
|
+
if (op.edge.color)
|
|
758
|
+
edgeChanges.style = { stroke: toTokenRef(op.edge.color) };
|
|
759
|
+
presentation.push({ op: "updateEdge", id, changes: edgeChanges });
|
|
760
|
+
}
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
case "updateEdge": {
|
|
764
|
+
const id = relationshipIdOf(op.id);
|
|
765
|
+
const changes = op.changes;
|
|
766
|
+
const raw = changes.data && typeof changes.data.db === "object" && changes.data.db ? changes.data.db : undefined;
|
|
767
|
+
const refs = (value) => (Array.isArray(value) ? value.filter((item) => typeof item === "string") : undefined);
|
|
768
|
+
const relationshipChanges = {};
|
|
769
|
+
if (changes.source !== undefined || refs(raw?.sourceColumns))
|
|
770
|
+
relationshipChanges.source = { table: changes.source !== undefined ? entityIdOf(changes.source, index) : (findEntity(model, id) ? model.relationships.find((r) => r.id === id)?.source.entityId ?? "" : ""), columns: refs(raw?.sourceColumns) ?? (changes.source !== undefined ? [] : undefined) };
|
|
771
|
+
if (changes.target !== undefined || refs(raw?.targetColumns))
|
|
772
|
+
relationshipChanges.target = { table: changes.target !== undefined ? entityIdOf(changes.target, index) : model.relationships.find((r) => r.id === id)?.target.entityId ?? "", columns: refs(raw?.targetColumns) ?? (changes.target !== undefined ? [] : undefined) };
|
|
773
|
+
if (isValidCardinality(raw?.cardinality))
|
|
774
|
+
relationshipChanges.cardinality = raw.cardinality;
|
|
775
|
+
if (raw && (raw.kind === "manual" || raw.kind === "foreignKey"))
|
|
776
|
+
relationshipChanges.relationshipKind = raw.kind;
|
|
777
|
+
if (raw && "name" in raw)
|
|
778
|
+
relationshipChanges.name = typeof raw.name === "string" ? raw.name : null;
|
|
779
|
+
if (changes.label !== undefined)
|
|
780
|
+
relationshipChanges.label = changes.label === "" ? null : changes.label;
|
|
781
|
+
if (Object.keys(relationshipChanges).length > 0)
|
|
782
|
+
run([{ kind: "updateRelationship", relationship: id, changes: relationshipChanges }], index);
|
|
783
|
+
const edgeChanges = {};
|
|
784
|
+
if (changes.routing !== undefined)
|
|
785
|
+
edgeChanges.routing = changes.routing;
|
|
786
|
+
if (changes.sourceSide !== undefined)
|
|
787
|
+
edgeChanges.sourceHandle = changes.sourceSide;
|
|
788
|
+
if (changes.targetSide !== undefined)
|
|
789
|
+
edgeChanges.targetHandle = changes.targetSide;
|
|
790
|
+
if (changes.color !== undefined)
|
|
791
|
+
edgeChanges.style = { stroke: changes.color === null ? null : toTokenRef(changes.color) };
|
|
792
|
+
if (Object.keys(edgeChanges).length > 0)
|
|
793
|
+
presentation.push({ op: "updateEdge", id, changes: edgeChanges });
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
case "removeEdge":
|
|
797
|
+
run([{ kind: "removeRelationship", relationship: relationshipIdOf(op.id) }], index);
|
|
798
|
+
return;
|
|
799
|
+
case "moveNode":
|
|
800
|
+
presentation.push({ op: "moveNodes", moves: [{ id: entityIdOf(op.id, index), position: op.position }] });
|
|
801
|
+
return;
|
|
802
|
+
case "setEdgeRoute": {
|
|
803
|
+
const changes = {};
|
|
804
|
+
if (op.routing !== undefined)
|
|
805
|
+
changes.routing = op.routing;
|
|
806
|
+
if (op.sourceSide !== undefined)
|
|
807
|
+
changes.sourceHandle = op.sourceSide;
|
|
808
|
+
if (op.targetSide !== undefined)
|
|
809
|
+
changes.targetHandle = op.targetSide;
|
|
810
|
+
if (op.waypoints !== undefined)
|
|
811
|
+
changes.waypoints = op.waypoints;
|
|
812
|
+
if (Object.keys(changes).length === 0) {
|
|
813
|
+
changes.waypoints = null;
|
|
814
|
+
changes.sourceAnchor = null;
|
|
815
|
+
changes.targetAnchor = null;
|
|
816
|
+
}
|
|
817
|
+
presentation.push({ op: "updateEdge", id: relationshipIdOf(op.id), changes });
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
case "reorder": {
|
|
821
|
+
const id = entityIdOf(op.id, index);
|
|
822
|
+
const count = doc.nodes.filter((node) => !node.parentId).length;
|
|
823
|
+
presentation.push({ op: "reorder", kind: "node", id, index: op.index === "front" ? Math.max(0, count - 1) : op.index === "back" ? 0 : op.index });
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
case "setCanvas":
|
|
827
|
+
presentation.push({ op: "setCanvas", changes: op.canvas });
|
|
828
|
+
return;
|
|
829
|
+
case "relayout":
|
|
830
|
+
relayout = { scope: op.scope, ...(op.direction ? { direction: op.direction } : {}) };
|
|
831
|
+
return;
|
|
832
|
+
case "reparent":
|
|
833
|
+
case "group":
|
|
834
|
+
case "ungroup":
|
|
835
|
+
noContainers(index);
|
|
836
|
+
return;
|
|
837
|
+
default:
|
|
838
|
+
throw new DiagramOpError("DIAGRAM_INVALID_OP", `Unknown op "${op.op}"`, index);
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
const ops = [];
|
|
842
|
+
if (changed) {
|
|
843
|
+
ops.push({
|
|
844
|
+
op: "setSource",
|
|
845
|
+
source: { format: "database", text: serializeDatabaseModel(model), diagramType: "database", grammar: DATABASE_GRAMMAR_VERSION, valid: true },
|
|
846
|
+
resync: true,
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
for (const [id, position] of positioned)
|
|
850
|
+
ops.push({ op: "moveNodes", moves: [{ id, position }] });
|
|
851
|
+
ops.push(...presentation);
|
|
852
|
+
return { ops, warnings: warnings.filter(Boolean), unpositionedNodeIds, ...(relayout ? { relayout } : {}), idMap };
|
|
853
|
+
};
|
|
854
|
+
export const buildDiagramFromInput = (input, options = {}) => {
|
|
855
|
+
const kind = options.kind ?? "canvas";
|
|
856
|
+
const strict = options.strictTypes !== false;
|
|
857
|
+
const warnings = [];
|
|
858
|
+
const explicitIds = input.nodes.map((node) => node.id?.trim()).filter((id) => Boolean(id));
|
|
859
|
+
const duplicates = explicitIds.filter((id, index) => explicitIds.indexOf(id) !== index);
|
|
860
|
+
if (duplicates.length > 0) {
|
|
861
|
+
throw new DiagramOpError("DIAGRAM_DUPLICATE_NODE_ID", `Duplicate node ids: ${[...new Set(duplicates)].join(", ")}`);
|
|
862
|
+
}
|
|
863
|
+
const genNodeId = options.idStrategy === "sequential" ? sequentialIdFactory("n", explicitIds) : slugIdFactory(explicitIds, "n");
|
|
864
|
+
const genEdgeId = sequentialIdFactory("e", (input.edges ?? []).map((edge) => edge.id).filter((id) => Boolean(id)));
|
|
865
|
+
// Ids first so parents/edges can reference nodes declared later.
|
|
866
|
+
const ids = input.nodes.map((node) => node.id?.trim() || genNodeId(node.label ?? node.type));
|
|
867
|
+
const idSet = new Set(ids);
|
|
868
|
+
const unknown = [];
|
|
869
|
+
const nodes = input.nodes.map((node, index) => {
|
|
870
|
+
const id = ids[index];
|
|
871
|
+
if (node.parent && !idSet.has(node.parent)) {
|
|
872
|
+
throw new DiagramOpError("DIAGRAM_PARENT_NOT_FOUND", `Node ${id} references parent "${node.parent}" which is not in nodes.`, index);
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
return nodeFromInput(node, id, strict, warnings, index, kind);
|
|
876
|
+
}
|
|
877
|
+
catch (error) {
|
|
878
|
+
if (error instanceof DiagramOpError && error.code === "DIAGRAM_UNKNOWN_COMPONENT_TYPE") {
|
|
879
|
+
const entry = error.data?.unknownTypes?.[0];
|
|
880
|
+
if (entry)
|
|
881
|
+
unknown.push(entry);
|
|
882
|
+
return nodeFromInput({ ...node, type: kind === "bpmn" ? "bpmn.task" : kind === "database" ? "db.table" : "rect", label: node.label ?? node.type }, id, false, [], index, kind);
|
|
883
|
+
}
|
|
884
|
+
throw error;
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
if (unknown.length > 0) {
|
|
888
|
+
throw new 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 });
|
|
889
|
+
}
|
|
890
|
+
const typeOf = (id) => nodes.find((node) => node.id === id)?.type;
|
|
891
|
+
for (const node of nodes) {
|
|
892
|
+
const warning = node.parentId ? parentWarning(node.id, node.parentId, typeOf(node.parentId), kind) : null;
|
|
893
|
+
if (warning)
|
|
894
|
+
warnings.push(warning);
|
|
895
|
+
}
|
|
896
|
+
const edgeIds = new Set();
|
|
897
|
+
const edges = (input.edges ?? []).map((edge, index) => {
|
|
898
|
+
const id = edge.id?.trim() || genEdgeId();
|
|
899
|
+
if (edgeIds.has(id) || idSet.has(id))
|
|
900
|
+
throw new DiagramOpError("DIAGRAM_DUPLICATE_EDGE_ID", `Duplicate edge id: ${id}`, index);
|
|
901
|
+
edgeIds.add(id);
|
|
902
|
+
for (const endpoint of [edge.source, edge.target]) {
|
|
903
|
+
if (!idSet.has(endpoint)) {
|
|
904
|
+
throw new DiagramOpError("DIAGRAM_EDGE_ENDPOINT_NOT_FOUND", `Edge ${id} references "${endpoint}" which is not a node id.`, index);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
return edgeFromInput(edge, id, typeOf, kind);
|
|
908
|
+
});
|
|
909
|
+
const timestamp = options.createdAt ?? nowIso();
|
|
910
|
+
const document = normalizeDiagramStyles({
|
|
911
|
+
schemaVersion: SCHEMA_VERSION,
|
|
912
|
+
id: options.existingId ?? `doc_${Math.random().toString(36).slice(2, 10)}`,
|
|
913
|
+
meta: { title: input.title.trim(), createdAt: timestamp, updatedAt: options.now ?? nowIso() },
|
|
914
|
+
canvas: {
|
|
915
|
+
background: input.canvas?.background ?? "dots",
|
|
916
|
+
gridSize: input.canvas?.gridSize ?? 16,
|
|
917
|
+
...(input.canvas?.defaultRouting ? { defaultRouting: input.canvas.defaultRouting } : {}),
|
|
918
|
+
},
|
|
919
|
+
nodes,
|
|
920
|
+
edges,
|
|
921
|
+
});
|
|
922
|
+
const parsed = safeParseDiagramDocument(document);
|
|
923
|
+
if (!parsed.ok) {
|
|
924
|
+
throw new DiagramOpError("DIAGRAM_DOCUMENT_INVALID", `The diagram document is invalid: ${parsed.errors.join("; ")}`, -1, { errors: parsed.errors });
|
|
925
|
+
}
|
|
926
|
+
return {
|
|
927
|
+
document: parsed.document,
|
|
928
|
+
warnings,
|
|
929
|
+
unpositionedNodeIds: input.nodes.filter((node) => !node.position).map((_node, index) => ids[index]),
|
|
930
|
+
};
|
|
931
|
+
};
|
|
932
|
+
// A container around the members' bounding box, members re-parented into it
|
|
933
|
+
// with their positions converted so nothing moves on the canvas.
|
|
934
|
+
export const groupNodesOps = (doc, memberIds, options) => {
|
|
935
|
+
const byId = indexNodes(doc.nodes);
|
|
936
|
+
const members = memberIds.map((id) => byId.get(id)).filter((node) => Boolean(node));
|
|
937
|
+
const padding = options.padding ?? 24;
|
|
938
|
+
const titleHeight = options.titleHeight ?? 32;
|
|
939
|
+
const rects = members.map((node) => absoluteRect(node, byId));
|
|
940
|
+
const box = boundingBox(rects) ?? { x: 0, y: 0, width: 200, height: 120 };
|
|
941
|
+
// The container joins the first member's parent so nested groups stay nested.
|
|
942
|
+
const parentId = members[0]?.parentId;
|
|
943
|
+
const type = options.type ?? "frame";
|
|
944
|
+
const def = getDiagramComponent(type);
|
|
945
|
+
const containerAbs = { x: box.x - padding, y: box.y - padding - titleHeight };
|
|
946
|
+
const container = {
|
|
947
|
+
id: options.id,
|
|
948
|
+
type,
|
|
949
|
+
position: toParentRelative(containerAbs, parentId, byId),
|
|
950
|
+
size: { width: box.width + padding * 2, height: box.height + padding * 2 + titleHeight },
|
|
951
|
+
label: options.label ?? def?.defaultLabel ?? "Group",
|
|
952
|
+
...(parentId ? { parentId } : {}),
|
|
953
|
+
};
|
|
954
|
+
const ops = [{ op: "addNode", node: container }];
|
|
955
|
+
const memberPositions = {};
|
|
956
|
+
members.forEach((member, index) => {
|
|
957
|
+
const abs = rects[index];
|
|
958
|
+
const position = { x: abs.x - containerAbs.x, y: abs.y - containerAbs.y };
|
|
959
|
+
memberPositions[member.id] = position;
|
|
960
|
+
ops.push({ op: "reparent", id: member.id, parentId: options.id, position });
|
|
961
|
+
});
|
|
962
|
+
return { ops, container, memberPositions };
|
|
963
|
+
};
|
|
964
|
+
export const ungroupOps = (containerId) => [{ op: "removeNode", id: containerId, children: "lift" }];
|
|
965
|
+
// Place ONLY the given nodes (new ones from a patch) below the current
|
|
966
|
+
// bounding box, in rows — nothing that already has a position moves. Nodes
|
|
967
|
+
// inside a container are placed inside it, below its current content.
|
|
968
|
+
export const placeNewNodesOps = (doc, nodeIds, gap = 40) => {
|
|
969
|
+
const wanted = new Set(nodeIds);
|
|
970
|
+
if (wanted.size === 0)
|
|
971
|
+
return [];
|
|
972
|
+
const byParent = new Map();
|
|
973
|
+
for (const node of doc.nodes) {
|
|
974
|
+
if (!wanted.has(node.id))
|
|
975
|
+
continue;
|
|
976
|
+
const list = byParent.get(node.parentId) ?? [];
|
|
977
|
+
list.push(node);
|
|
978
|
+
byParent.set(node.parentId, list);
|
|
979
|
+
}
|
|
980
|
+
const moves = [];
|
|
981
|
+
for (const [parentId, newcomers] of byParent) {
|
|
982
|
+
const placed = doc.nodes.filter((node) => !wanted.has(node.id) && (node.parentId ?? undefined) === parentId);
|
|
983
|
+
const maxY = placed.reduce((max, node) => Math.max(max, node.position.y + node.size.height), parentId ? 48 : 0);
|
|
984
|
+
const minX = placed.reduce((min, node) => Math.min(min, node.position.x), placed.length > 0 ? Infinity : parentId ? 24 : 0);
|
|
985
|
+
const startX = Number.isFinite(minX) ? minX : 0;
|
|
986
|
+
let cursorX = startX;
|
|
987
|
+
let cursorY = placed.length > 0 ? maxY + gap * 2 : maxY;
|
|
988
|
+
let rowHeight = 0;
|
|
989
|
+
const rowLimit = 1200;
|
|
990
|
+
for (const node of newcomers) {
|
|
991
|
+
if (cursorX + node.size.width > rowLimit && cursorX > startX) {
|
|
992
|
+
cursorX = startX;
|
|
993
|
+
cursorY += rowHeight + gap;
|
|
994
|
+
rowHeight = 0;
|
|
995
|
+
}
|
|
996
|
+
moves.push({ id: node.id, position: { x: cursorX, y: cursorY } });
|
|
997
|
+
cursorX += node.size.width + gap;
|
|
998
|
+
rowHeight = Math.max(rowHeight, node.size.height);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return moves.length > 0 ? [{ op: "moveNodes", moves }] : [];
|
|
1002
|
+
};
|
|
1003
|
+
// Whether an ops batch (typically from a model) deletes a large part of the
|
|
1004
|
+
// diagram — hosts confirm with the user before applying such a batch.
|
|
1005
|
+
export const assessOpsRisk = (doc, ops, threshold = 0.3, minimum = 3) => {
|
|
1006
|
+
const removes = new Set();
|
|
1007
|
+
const collect = (list) => {
|
|
1008
|
+
for (const op of list) {
|
|
1009
|
+
if (op.op === "removeNode")
|
|
1010
|
+
removes.add(op.id);
|
|
1011
|
+
else if (op.op === "batch")
|
|
1012
|
+
collect(op.ops);
|
|
1013
|
+
else if (op.op === "replaceDocument")
|
|
1014
|
+
for (const node of doc.nodes)
|
|
1015
|
+
if (!op.document.nodes.some((n) => n.id === node.id))
|
|
1016
|
+
removes.add(node.id);
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
collect(ops);
|
|
1020
|
+
const totalNodes = doc.nodes.length;
|
|
1021
|
+
const ratio = totalNodes === 0 ? 0 : removes.size / totalNodes;
|
|
1022
|
+
return { removesNodes: removes.size, totalNodes, ratio, destructive: removes.size >= minimum && ratio > threshold };
|
|
1023
|
+
};
|
|
1024
|
+
//# sourceMappingURL=patchInput.js.map
|