ice-entity-designer-dsl 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +48 -10
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/types/compiler/dslToScene.d.ts +3 -2
- package/dist/types/compiler/flowToScene.d.ts +37 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/runtime/renderDsl.d.ts +17 -2
- package/dist/types/types.d.ts +55 -1
- package/dist/types/validate.d.ts +4 -1
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 大漠穷秋
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# ice-entity-designer-dsl
|
|
2
2
|
|
|
3
|
-
JSON-first
|
|
3
|
+
JSON-first DSL for AI agents to drive `ice-entity-designer` without learning the imperative canvas API.
|
|
4
|
+
|
|
5
|
+
One document kind, two shapes:
|
|
6
|
+
|
|
7
|
+
- **ER document** (`entities` / `relations`): entity-relation models and database schemas.
|
|
8
|
+
- **Flowchart document** (`kind: "flowchart"` with `nodes` / `edges`): process flows,
|
|
9
|
+
decision trees, and algorithms, with optional coordinates (layered auto-layout).
|
|
4
10
|
|
|
5
11
|
The package contains:
|
|
6
12
|
|
|
7
|
-
- DSL types and schema
|
|
13
|
+
- DSL types and schema (ER + flowchart)
|
|
8
14
|
- structural validator
|
|
9
|
-
-
|
|
15
|
+
- compilers from DSL to Entity/Relation or FlowNode/FlowEdge props
|
|
10
16
|
- browser runtime that renders DSL through `ice-entity-designer`
|
|
11
|
-
- browser
|
|
17
|
+
- browser examples with a JSON editor (`examples/entity-editor-dsl.html`, `examples/flowchart-dsl.html`)
|
|
12
18
|
|
|
13
19
|
## Install
|
|
14
20
|
|
|
@@ -44,19 +50,51 @@ npm run build
|
|
|
44
50
|
## Node/ESM usage
|
|
45
51
|
|
|
46
52
|
```ts
|
|
47
|
-
import { validateDsl, compileDsl, renderDsl } from 'ice-
|
|
53
|
+
import { validateDsl, compileDsl, compileFlowDsl, renderDsl } from 'ice-entity-designer-dsl';
|
|
48
54
|
```
|
|
49
55
|
|
|
56
|
+
## Flowchart usage
|
|
57
|
+
|
|
58
|
+
Node coordinates are optional: if any node omits `left`/`top`, the whole graph is laid
|
|
59
|
+
out in layers (layer 0 = nodes without incoming edges; every other node = max
|
|
60
|
+
predecessor layer + 1).
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
const flowchart = {
|
|
64
|
+
schemaVersion: 1,
|
|
65
|
+
kind: 'flowchart',
|
|
66
|
+
nodes: [
|
|
67
|
+
{ id: 'start', kind: 'terminator', title: '开始' },
|
|
68
|
+
{ id: 'check', kind: 'decision', title: '库存充足?' },
|
|
69
|
+
{ id: 'done', kind: 'terminator', title: '结束' },
|
|
70
|
+
{ id: 'restock', kind: 'io', title: '通知补货' },
|
|
71
|
+
],
|
|
72
|
+
edges: [
|
|
73
|
+
{ source: 'start', target: 'check' },
|
|
74
|
+
{ source: 'check', target: 'done', label: '是' },
|
|
75
|
+
{ source: 'check', target: 'restock', label: '否', sourcePort: 'R', targetPort: 'L' },
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// kind === 'flowchart' 时 result.designer 是 FlowDesigner(createNode / createEdge / undo / …)
|
|
80
|
+
const result = ICEDSL.renderDsl('canvas', flowchart);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Node kinds: `terminator` (start/end pill) / `process` (action, default) / `decision`
|
|
84
|
+
(diamond) / `io` (parallelogram). Edge ports are `T` / `R` / `B` / `L` / `C` (default
|
|
85
|
+
`B` → `T`); `linkShape` is `visio` (orthogonal, default) or `bezier`.
|
|
86
|
+
|
|
50
87
|
## API
|
|
51
88
|
|
|
52
|
-
- `validateDsl(dsl)`
|
|
53
|
-
- `compileDsl(dsl)`
|
|
54
|
-
- `
|
|
89
|
+
- `validateDsl(dsl)` —— ER / flowchart documents (dispatches on `kind`); `validateFlowDsl(dsl)` for flowcharts only
|
|
90
|
+
- `compileDsl(dsl)` —— ER document → `Entity` / `Relation` props
|
|
91
|
+
- `compileFlowDsl(dsl)` —— flowchart document → `FlowNode` / `FlowEdge` props (with layered auto-layout)
|
|
92
|
+
- `renderDsl(canvasOrId, dsl)` —— renders either kind, returns `{ kind, ice, designer }`
|
|
55
93
|
- `DSL_SCHEMA_VERSION`
|
|
56
94
|
|
|
57
95
|
## Example
|
|
58
96
|
|
|
59
|
-
Open `examples/entity-editor-dsl.html` after building.
|
|
97
|
+
Open `examples/entity-editor-dsl.html` (ER) or `examples/flowchart-dsl.html` (flowchart) after building.
|
|
60
98
|
|
|
61
99
|
## Agent discovery
|
|
62
100
|
|
|
@@ -64,7 +102,7 @@ Agents can use this project through:
|
|
|
64
102
|
|
|
65
103
|
1. npm package exports
|
|
66
104
|
2. `AGENTS.md`
|
|
67
|
-
3. `skills/ice-
|
|
105
|
+
3. `skills/ice-entity-designer-dsl/SKILL.md`
|
|
68
106
|
4. optional MCP wrapper in a separate package
|
|
69
107
|
|
|
70
108
|
The core runtime does not require MCP.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("ice-entity-designer");function validateDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("ice-entity-designer");function isFlowDsl(e){return!!e&&"object"==typeof e&&"flowchart"===e.kind}const t=["terminator","process","decision","io"],i=["T","R","B","L","C"];function validateDsl(e){return isFlowDsl(e)?validateFlowDsl(e):function validateErDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&t.push("Unsupported schemaVersion: "+e.schemaVersion);if(Array.isArray(e.entities)){const i=new Set;e.entities.forEach((e,o)=>{const r=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):i.add(e.id):t.push(r+".id must be a non-empty string"),Array.isArray(e.fields)?e.fields.forEach((e,i)=>{e&&"object"==typeof e&&"string"==typeof e.name&&e.name.trim()||t.push(`${r}.fields[${i}].name must be a non-empty string`)}):t.push(r+".fields must be an array")):t.push(r+" must be an object")})}else t.push("entities must be an array");void 0===e.relations||Array.isArray(e.relations)?(e.relations||[]).forEach((e,i)=>{const o=`relations[${i}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()||t.push(o+".source must be a non-empty string"),"string"==typeof e.target&&e.target.trim()||t.push(o+".target must be a non-empty string")):t.push(o+" must be an object")}):t.push("relations must be an array");return{valid:0===t.length,errors:t}}(e)}function validateFlowDsl(e){const o=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&o.push("Unsupported schemaVersion: "+e.schemaVersion);const r=new Set;return Array.isArray(e.nodes)?e.nodes.forEach((e,i)=>{const s=`nodes[${i}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?r.has(e.id)?o.push(`${s}.id is duplicated: ${e.id}`):r.add(e.id):o.push(s+".id must be a non-empty string"),void 0!==e.kind&&-1===t.indexOf(e.kind)&&o.push(`${s}.kind must be one of ${t.join("/")}`),["left","top","width","height"].forEach(t=>{const i=e[t];void 0!==i&&"number"!=typeof i&&o.push(`${s}.${t} must be a number when present`)})):o.push(s+" must be an object")}):o.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,t)=>{const s=`edges[${t}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&r.has(e.source)||o.push(s+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&r.has(e.target)||o.push(s+".target must reference an existing node id"),void 0!==e.label&&"string"!=typeof e.label&&o.push(s+".label must be a string when present"),void 0!==e.sourcePort&&-1===i.indexOf(e.sourcePort)&&o.push(`${s}.sourcePort must be one of ${i.join("/")}`),void 0!==e.targetPort&&-1===i.indexOf(e.targetPort)&&o.push(`${s}.targetPort must be one of ${i.join("/")}`),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&o.push(s+'.linkShape must be "visio" or "bezier" when present')):o.push(s+" must be an object")}):o.push("edges must be an array when present"),{valid:0===o.length,errors:o}}function entityName(e){return e.entityName||e.name||e.id}function relationType(e){return e.relationType||e.type||"one-to-many"}function compileDsl(e){if(isFlowDsl(e))throw new Error("compileDsl() 只处理 ER 文档;流程图文档请使用 compileFlowDsl()");if(!e||!Array.isArray(e.entities))throw new Error("ER 文档必须包含 entities 数组");return{entities:e.entities.map(e=>({id:e.id,entityName:entityName(e),fields:e.fields||[],left:e.left,top:e.top,width:e.width,height:e.height,style:e.style,headerStyle:e.headerStyle,fieldStyle:e.fieldStyle,dividerStyle:e.dividerStyle,draggable:e.draggable,interactive:e.interactive})),relations:(e.relations||[]).map((e,t)=>({id:e.id||"relation-"+t,relationType:relationType(e),sourceId:e.source,targetId:e.target,sourceField:e.sourceField||"id",targetField:e.targetField||"id",nullable:e.nullable,onDelete:e.onDelete,onUpdate:e.onUpdate,joinTableName:e.joinTableName,fromKey:e.fromKey,toKey:e.toKey,sourceCardinality:e.sourceCardinality,targetCardinality:e.targetCardinality,label:e.label,style:e.style,arrow:e.arrow,linkShape:e.linkShape,routeType:e.routeType,routeOffset:e.routeOffset,curveType:e.curveType,lineDash:e.lineDash})),layout:e.layout,options:e.options}}const o={terminator:{width:e.FLOW_NODE_KINDS.terminator.width,height:e.FLOW_NODE_KINDS.terminator.height,fill:e.FLOW_NODE_KINDS.terminator.fill,stroke:e.FLOW_NODE_KINDS.terminator.stroke},process:{width:e.FLOW_NODE_KINDS.process.width,height:e.FLOW_NODE_KINDS.process.height,fill:e.FLOW_NODE_KINDS.process.fill,stroke:e.FLOW_NODE_KINDS.process.stroke},decision:{width:e.FLOW_NODE_KINDS.decision.width,height:e.FLOW_NODE_KINDS.decision.height,fill:e.FLOW_NODE_KINDS.decision.fill,stroke:e.FLOW_NODE_KINDS.decision.stroke},io:{width:e.FLOW_NODE_KINDS.io.width,height:e.FLOW_NODE_KINDS.io.height,fill:e.FLOW_NODE_KINDS.io.fill,stroke:e.FLOW_NODE_KINDS.io.stroke}};function compileFlowDsl(e){const t=e.options||{},i=(e.nodes||[]).map(e=>{const t=function nodeKind(e){return e.kind&&o[e.kind]?e.kind:"process"}(e),i=o[t];return{id:e.id,typeId:"FlowNode",kind:t,title:(r=e,r.title||r.name||r.id),left:"number"==typeof e.left?e.left:Number.NaN,top:"number"==typeof e.top?e.top:Number.NaN,width:"number"==typeof e.width?e.width:i.width,height:"number"==typeof e.height?e.height:i.height,fillColor:e.fillColor||i.fill,strokeColor:e.strokeColor||i.stroke};var r}),r=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,sourcePort:e.sourcePort||"B",targetPort:e.targetPort||"T",label:e.label||"",linkShape:e.linkShape||"visio"})),s=t.layout||"layered";return"none"!==s&&i.some(e=>Number.isNaN(e.left)||Number.isNaN(e.top))&&(i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),function autoLayout(e,t,i,o){const r=new Map;e.forEach(e=>r.set(e.id,e));const s=new Map,n=new Map;e.forEach(e=>{s.set(e.id,0),n.set(e.id,[])}),t.forEach(e=>{r.has(e.sourceId)&&r.has(e.targetId)&&(s.set(e.targetId,(s.get(e.targetId)||0)+1),n.get(e.sourceId).push(e.targetId))});const a=new Map,l=[];e.forEach(e=>{0===(s.get(e.id)||0)&&(a.set(e.id,0),l.push(e.id))}),!l.length&&e.length&&(a.set(e[0].id,0),l.push(e[0].id));let d=e.length*e.length+e.length;for(;l.length&&d-- >0;){const e=l.shift(),t=a.get(e)||0;(n.get(e)||[]).forEach(e=>{const i=t+1;(a.get(e)??-1)<i&&(a.set(e,i),l.push(e))})}e.forEach(e=>{a.has(e.id)||a.set(e.id,0)});const p=new Map;e.forEach(e=>{const t=a.get(e.id)||0;p.has(t)||p.set(t,[]),p.get(t).push(e)});const h=[...p.keys()].sort((e,t)=>e-t),c=h.map(e=>Math.max(...p.get(e).map(e=>e.height)));c.reduce((e,t)=>e+t,0),Math.max(h.length-1,0);let u=0;h.forEach((e,t)=>{const r=p.get(e);let s=-(r.reduce((e,t)=>e+t.width,0)+Math.max(r.length-1,0)*i)/2;r.forEach(e=>{e.left=Math.round(s),e.top=Math.round(u+(c[t]-e.height)/2),s+=e.width+i}),u+=c[t]+o});const f=Math.min(...e.map(e=>e.left)),m=Math.min(...e.map(e=>e.top));e.forEach(e=>{e.left+=80-f,e.top+=80-m})}(i,r,Number(t.gapX)||90,Number(t.gapY)||90)),i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),{kind:"flowchart",nodes:i,edges:r,layout:s,options:t}}function renderFlowDsl(t,i){const o=compileFlowDsl(i),r=o.options||{},s=(new e.ICE).init(t),n=new e.FlowDesigner(s);return o.nodes.forEach(e=>{n.createNode(e.kind,e)}),o.edges.forEach(e=>{n.createEdge(e)}),n.select(null),r.viewport?s.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):!1!==r.fitViewport&&n.fitViewport(r.fitViewportPadding),n.resetHistory(),{kind:"flowchart",ice:s,designer:n}}exports.DSL_SCHEMA_VERSION=1,exports.compileDsl=compileDsl,exports.compileFlowDsl=compileFlowDsl,exports.isFlowDsl=isFlowDsl,exports.renderDsl=function renderDsl(t,i){const o=validateDsl(i);if(!o.valid)throw new Error(o.errors.join("\n"));return isFlowDsl(i)?renderFlowDsl(t,i):function renderErDsl(t,i){const o=compileDsl(i),r=o.options||{},s=(new e.ICE).init(t),n=new e.EntityDesigner(s);o.entities.forEach(e=>{n.createEntity(e)}),function positionLinks(e,t,i){const o=new Map;return e.entities.forEach(e=>{o.set(e.state.id,e.getMinBoundingBox(!0))}),t.relations.map(e=>{const t=o.get(e.sourceId),r=o.get(e.targetId);let s="R",n="L";if(t&&r){const e=r.center[0]-t.center[0],i=r.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(s=e>=0?"R":"L",n=e>=0?"L":"R"):(s=i>=0?"B":"T",n=i>=0?"T":"B")}return{...e,routeType:e.routeType||i||"orthogonal",linkShape:e.linkShape||"visio",links:{start:{id:e.sourceId,position:s},end:{id:e.targetId,position:n}}}})}(n,o,r.routeType).forEach(e=>{n.createRelation(e)}),("layered"===o.layout||"horizontal"===o.layout)&&new e.ICELayeredLayout({gapX:r.gapX||120,gapY:r.gapY||50}).layoutContainer(s);r.viewport?s.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):r.fitViewport&&function fitViewport(e,t,i){const o=t.entities||[];let r=1/0,s=1/0,n=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();r=Math.min(r,t.minX),s=Math.min(s,t.minY),n=Math.max(n,t.maxX),a=Math.max(a,t.maxY)});const l=n-r,d=a-s,p=e.canvasWidth||0,h=e.canvasHeight||0;if(!p||!h||l<=0||d<=0)return;const c=Number.isFinite(i)&&i>=0?i:40,u=Math.max(1,p-2*c),f=Math.max(1,h-2*c),m=Math.min(u/l,f/d,1),g=(p-l*m)/2-r*m,y=(h-d*m)/2-s*m;e.setViewport(m,g,y)}(s,n,r.fitViewportPadding);return{kind:"entity",ice:s,designer:n}}(t,i)},exports.renderFlowDsl=renderFlowDsl,exports.validateDsl=validateDsl,exports.validateFlowDsl=validateFlowDsl;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{FLOW_NODE_KINDS as e,ICE as t,FlowDesigner as i,EntityDesigner as o,ICELayeredLayout as r}from"ice-entity-designer";function isFlowDsl(e){return!!e&&"object"==typeof e&&"flowchart"===e.kind}const n=1,s=["terminator","process","decision","io"],a=["T","R","B","L","C"];function validateDsl(e){return isFlowDsl(e)?validateFlowDsl(e):function validateErDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&t.push("Unsupported schemaVersion: "+e.schemaVersion);if(Array.isArray(e.entities)){const i=new Set;e.entities.forEach((e,o)=>{const r=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):i.add(e.id):t.push(r+".id must be a non-empty string"),Array.isArray(e.fields)?e.fields.forEach((e,i)=>{e&&"object"==typeof e&&"string"==typeof e.name&&e.name.trim()||t.push(`${r}.fields[${i}].name must be a non-empty string`)}):t.push(r+".fields must be an array")):t.push(r+" must be an object")})}else t.push("entities must be an array");void 0===e.relations||Array.isArray(e.relations)?(e.relations||[]).forEach((e,i)=>{const o=`relations[${i}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()||t.push(o+".source must be a non-empty string"),"string"==typeof e.target&&e.target.trim()||t.push(o+".target must be a non-empty string")):t.push(o+" must be an object")}):t.push("relations must be an array");return{valid:0===t.length,errors:t}}(e)}function validateFlowDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&t.push("Unsupported schemaVersion: "+e.schemaVersion);const i=new Set;return Array.isArray(e.nodes)?e.nodes.forEach((e,o)=>{const r=`nodes[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):i.add(e.id):t.push(r+".id must be a non-empty string"),void 0!==e.kind&&-1===s.indexOf(e.kind)&&t.push(`${r}.kind must be one of ${s.join("/")}`),["left","top","width","height"].forEach(i=>{const o=e[i];void 0!==o&&"number"!=typeof o&&t.push(`${r}.${i} must be a number when present`)})):t.push(r+" must be an object")}):t.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,o)=>{const r=`edges[${o}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&i.has(e.source)||t.push(r+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&i.has(e.target)||t.push(r+".target must reference an existing node id"),void 0!==e.label&&"string"!=typeof e.label&&t.push(r+".label must be a string when present"),void 0!==e.sourcePort&&-1===a.indexOf(e.sourcePort)&&t.push(`${r}.sourcePort must be one of ${a.join("/")}`),void 0!==e.targetPort&&-1===a.indexOf(e.targetPort)&&t.push(`${r}.targetPort must be one of ${a.join("/")}`),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&t.push(r+'.linkShape must be "visio" or "bezier" when present')):t.push(r+" must be an object")}):t.push("edges must be an array when present"),{valid:0===t.length,errors:t}}function entityName(e){return e.entityName||e.name||e.id}function relationType(e){return e.relationType||e.type||"one-to-many"}function compileDsl(e){if(isFlowDsl(e))throw new Error("compileDsl() 只处理 ER 文档;流程图文档请使用 compileFlowDsl()");if(!e||!Array.isArray(e.entities))throw new Error("ER 文档必须包含 entities 数组");return{entities:e.entities.map(e=>({id:e.id,entityName:entityName(e),fields:e.fields||[],left:e.left,top:e.top,width:e.width,height:e.height,style:e.style,headerStyle:e.headerStyle,fieldStyle:e.fieldStyle,dividerStyle:e.dividerStyle,draggable:e.draggable,interactive:e.interactive})),relations:(e.relations||[]).map((e,t)=>({id:e.id||"relation-"+t,relationType:relationType(e),sourceId:e.source,targetId:e.target,sourceField:e.sourceField||"id",targetField:e.targetField||"id",nullable:e.nullable,onDelete:e.onDelete,onUpdate:e.onUpdate,joinTableName:e.joinTableName,fromKey:e.fromKey,toKey:e.toKey,sourceCardinality:e.sourceCardinality,targetCardinality:e.targetCardinality,label:e.label,style:e.style,arrow:e.arrow,linkShape:e.linkShape,routeType:e.routeType,routeOffset:e.routeOffset,curveType:e.curveType,lineDash:e.lineDash})),layout:e.layout,options:e.options}}const l={terminator:{width:e.terminator.width,height:e.terminator.height,fill:e.terminator.fill,stroke:e.terminator.stroke},process:{width:e.process.width,height:e.process.height,fill:e.process.fill,stroke:e.process.stroke},decision:{width:e.decision.width,height:e.decision.height,fill:e.decision.fill,stroke:e.decision.stroke},io:{width:e.io.width,height:e.io.height,fill:e.io.fill,stroke:e.io.stroke}};function compileFlowDsl(e){const t=e.options||{},i=(e.nodes||[]).map(e=>{const t=function nodeKind(e){return e.kind&&l[e.kind]?e.kind:"process"}(e),i=l[t];return{id:e.id,typeId:"FlowNode",kind:t,title:(o=e,o.title||o.name||o.id),left:"number"==typeof e.left?e.left:Number.NaN,top:"number"==typeof e.top?e.top:Number.NaN,width:"number"==typeof e.width?e.width:i.width,height:"number"==typeof e.height?e.height:i.height,fillColor:e.fillColor||i.fill,strokeColor:e.strokeColor||i.stroke};var o}),o=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,sourcePort:e.sourcePort||"B",targetPort:e.targetPort||"T",label:e.label||"",linkShape:e.linkShape||"visio"})),r=t.layout||"layered";return"none"!==r&&i.some(e=>Number.isNaN(e.left)||Number.isNaN(e.top))&&(i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),function autoLayout(e,t,i,o){const r=new Map;e.forEach(e=>r.set(e.id,e));const n=new Map,s=new Map;e.forEach(e=>{n.set(e.id,0),s.set(e.id,[])}),t.forEach(e=>{r.has(e.sourceId)&&r.has(e.targetId)&&(n.set(e.targetId,(n.get(e.targetId)||0)+1),s.get(e.sourceId).push(e.targetId))});const a=new Map,l=[];e.forEach(e=>{0===(n.get(e.id)||0)&&(a.set(e.id,0),l.push(e.id))}),!l.length&&e.length&&(a.set(e[0].id,0),l.push(e[0].id));let d=e.length*e.length+e.length;for(;l.length&&d-- >0;){const e=l.shift(),t=a.get(e)||0;(s.get(e)||[]).forEach(e=>{const i=t+1;(a.get(e)??-1)<i&&(a.set(e,i),l.push(e))})}e.forEach(e=>{a.has(e.id)||a.set(e.id,0)});const h=new Map;e.forEach(e=>{const t=a.get(e.id)||0;h.has(t)||h.set(t,[]),h.get(t).push(e)});const p=[...h.keys()].sort((e,t)=>e-t),c=p.map(e=>Math.max(...h.get(e).map(e=>e.height)));c.reduce((e,t)=>e+t,0),Math.max(p.length-1,0);let u=0;p.forEach((e,t)=>{const r=h.get(e);let n=-(r.reduce((e,t)=>e+t.width,0)+Math.max(r.length-1,0)*i)/2;r.forEach(e=>{e.left=Math.round(n),e.top=Math.round(u+(c[t]-e.height)/2),n+=e.width+i}),u+=c[t]+o});const f=Math.min(...e.map(e=>e.left)),m=Math.min(...e.map(e=>e.top));e.forEach(e=>{e.left+=80-f,e.top+=80-m})}(i,o,Number(t.gapX)||90,Number(t.gapY)||90)),i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),{kind:"flowchart",nodes:i,edges:o,layout:r,options:t}}function renderDsl(e,i){const n=validateDsl(i);if(!n.valid)throw new Error(n.errors.join("\n"));return isFlowDsl(i)?renderFlowDsl(e,i):function renderErDsl(e,i){const n=compileDsl(i),s=n.options||{},a=(new t).init(e),l=new o(a);n.entities.forEach(e=>{l.createEntity(e)}),function positionLinks(e,t,i){const o=new Map;return e.entities.forEach(e=>{o.set(e.state.id,e.getMinBoundingBox(!0))}),t.relations.map(e=>{const t=o.get(e.sourceId),r=o.get(e.targetId);let n="R",s="L";if(t&&r){const e=r.center[0]-t.center[0],i=r.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(n=e>=0?"R":"L",s=e>=0?"L":"R"):(n=i>=0?"B":"T",s=i>=0?"T":"B")}return{...e,routeType:e.routeType||i||"orthogonal",linkShape:e.linkShape||"visio",links:{start:{id:e.sourceId,position:n},end:{id:e.targetId,position:s}}}})}(l,n,s.routeType).forEach(e=>{l.createRelation(e)}),("layered"===n.layout||"horizontal"===n.layout)&&new r({gapX:s.gapX||120,gapY:s.gapY||50}).layoutContainer(a);s.viewport?a.setViewport(s.viewport.scale,s.viewport.tx,s.viewport.ty):s.fitViewport&&function fitViewport(e,t,i){const o=t.entities||[];let r=1/0,n=1/0,s=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();r=Math.min(r,t.minX),n=Math.min(n,t.minY),s=Math.max(s,t.maxX),a=Math.max(a,t.maxY)});const l=s-r,d=a-n,h=e.canvasWidth||0,p=e.canvasHeight||0;if(!h||!p||l<=0||d<=0)return;const c=Number.isFinite(i)&&i>=0?i:40,u=Math.max(1,h-2*c),f=Math.max(1,p-2*c),m=Math.min(u/l,f/d,1),g=(h-l*m)/2-r*m,y=(p-d*m)/2-n*m;e.setViewport(m,g,y)}(a,l,s.fitViewportPadding);return{kind:"entity",ice:a,designer:l}}(e,i)}function renderFlowDsl(e,o){const r=compileFlowDsl(o),n=r.options||{},s=(new t).init(e),a=new i(s);return r.nodes.forEach(e=>{a.createNode(e.kind,e)}),r.edges.forEach(e=>{a.createEdge(e)}),a.select(null),n.viewport?s.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):!1!==n.fitViewport&&a.fitViewport(n.fitViewportPadding),a.resetHistory(),{kind:"flowchart",ice:s,designer:a}}export{n as DSL_SCHEMA_VERSION,compileDsl,compileFlowDsl,isFlowDsl,renderDsl,renderFlowDsl,validateDsl,validateFlowDsl};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("ice-entity-designer")):"function"==typeof define&&define.amd?define(["exports","ice-entity-designer"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ICEDSL={},e.IED)}(this,(function(e,t){"use strict";function validateDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("ice-entity-designer")):"function"==typeof define&&define.amd?define(["exports","ice-entity-designer"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ICEDSL={},e.IED)}(this,(function(e,t){"use strict";function isFlowDsl(e){return!!e&&"object"==typeof e&&"flowchart"===e.kind}const i=["terminator","process","decision","io"],o=["T","R","B","L","C"];function validateDsl(e){return isFlowDsl(e)?validateFlowDsl(e):function validateErDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&t.push("Unsupported schemaVersion: "+e.schemaVersion);if(Array.isArray(e.entities)){const i=new Set;e.entities.forEach((e,o)=>{const r=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):i.add(e.id):t.push(r+".id must be a non-empty string"),Array.isArray(e.fields)?e.fields.forEach((e,i)=>{e&&"object"==typeof e&&"string"==typeof e.name&&e.name.trim()||t.push(`${r}.fields[${i}].name must be a non-empty string`)}):t.push(r+".fields must be an array")):t.push(r+" must be an object")})}else t.push("entities must be an array");void 0===e.relations||Array.isArray(e.relations)?(e.relations||[]).forEach((e,i)=>{const o=`relations[${i}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()||t.push(o+".source must be a non-empty string"),"string"==typeof e.target&&e.target.trim()||t.push(o+".target must be a non-empty string")):t.push(o+" must be an object")}):t.push("relations must be an array");return{valid:0===t.length,errors:t}}(e)}function validateFlowDsl(e){const t=[];if(!e||"object"!=typeof e||Array.isArray(e))return{valid:!1,errors:["DSL root must be an object"]};void 0!==e.schemaVersion&&1!==e.schemaVersion&&t.push("Unsupported schemaVersion: "+e.schemaVersion);const r=new Set;return Array.isArray(e.nodes)?e.nodes.forEach((e,o)=>{const n=`nodes[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?r.has(e.id)?t.push(`${n}.id is duplicated: ${e.id}`):r.add(e.id):t.push(n+".id must be a non-empty string"),void 0!==e.kind&&-1===i.indexOf(e.kind)&&t.push(`${n}.kind must be one of ${i.join("/")}`),["left","top","width","height"].forEach(i=>{const o=e[i];void 0!==o&&"number"!=typeof o&&t.push(`${n}.${i} must be a number when present`)})):t.push(n+" must be an object")}):t.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,i)=>{const n=`edges[${i}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&r.has(e.source)||t.push(n+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&r.has(e.target)||t.push(n+".target must reference an existing node id"),void 0!==e.label&&"string"!=typeof e.label&&t.push(n+".label must be a string when present"),void 0!==e.sourcePort&&-1===o.indexOf(e.sourcePort)&&t.push(`${n}.sourcePort must be one of ${o.join("/")}`),void 0!==e.targetPort&&-1===o.indexOf(e.targetPort)&&t.push(`${n}.targetPort must be one of ${o.join("/")}`),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&t.push(n+'.linkShape must be "visio" or "bezier" when present')):t.push(n+" must be an object")}):t.push("edges must be an array when present"),{valid:0===t.length,errors:t}}function entityName(e){return e.entityName||e.name||e.id}function relationType(e){return e.relationType||e.type||"one-to-many"}function compileDsl(e){if(isFlowDsl(e))throw new Error("compileDsl() 只处理 ER 文档;流程图文档请使用 compileFlowDsl()");if(!e||!Array.isArray(e.entities))throw new Error("ER 文档必须包含 entities 数组");return{entities:e.entities.map(e=>({id:e.id,entityName:entityName(e),fields:e.fields||[],left:e.left,top:e.top,width:e.width,height:e.height,style:e.style,headerStyle:e.headerStyle,fieldStyle:e.fieldStyle,dividerStyle:e.dividerStyle,draggable:e.draggable,interactive:e.interactive})),relations:(e.relations||[]).map((e,t)=>({id:e.id||"relation-"+t,relationType:relationType(e),sourceId:e.source,targetId:e.target,sourceField:e.sourceField||"id",targetField:e.targetField||"id",nullable:e.nullable,onDelete:e.onDelete,onUpdate:e.onUpdate,joinTableName:e.joinTableName,fromKey:e.fromKey,toKey:e.toKey,sourceCardinality:e.sourceCardinality,targetCardinality:e.targetCardinality,label:e.label,style:e.style,arrow:e.arrow,linkShape:e.linkShape,routeType:e.routeType,routeOffset:e.routeOffset,curveType:e.curveType,lineDash:e.lineDash})),layout:e.layout,options:e.options}}const r={terminator:{width:t.FLOW_NODE_KINDS.terminator.width,height:t.FLOW_NODE_KINDS.terminator.height,fill:t.FLOW_NODE_KINDS.terminator.fill,stroke:t.FLOW_NODE_KINDS.terminator.stroke},process:{width:t.FLOW_NODE_KINDS.process.width,height:t.FLOW_NODE_KINDS.process.height,fill:t.FLOW_NODE_KINDS.process.fill,stroke:t.FLOW_NODE_KINDS.process.stroke},decision:{width:t.FLOW_NODE_KINDS.decision.width,height:t.FLOW_NODE_KINDS.decision.height,fill:t.FLOW_NODE_KINDS.decision.fill,stroke:t.FLOW_NODE_KINDS.decision.stroke},io:{width:t.FLOW_NODE_KINDS.io.width,height:t.FLOW_NODE_KINDS.io.height,fill:t.FLOW_NODE_KINDS.io.fill,stroke:t.FLOW_NODE_KINDS.io.stroke}};function compileFlowDsl(e){const t=e.options||{},i=(e.nodes||[]).map(e=>{const t=function nodeKind(e){return e.kind&&r[e.kind]?e.kind:"process"}(e),i=r[t];return{id:e.id,typeId:"FlowNode",kind:t,title:(o=e,o.title||o.name||o.id),left:"number"==typeof e.left?e.left:Number.NaN,top:"number"==typeof e.top?e.top:Number.NaN,width:"number"==typeof e.width?e.width:i.width,height:"number"==typeof e.height?e.height:i.height,fillColor:e.fillColor||i.fill,strokeColor:e.strokeColor||i.stroke};var o}),o=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,sourcePort:e.sourcePort||"B",targetPort:e.targetPort||"T",label:e.label||"",linkShape:e.linkShape||"visio"})),n=t.layout||"layered";return"none"!==n&&i.some(e=>Number.isNaN(e.left)||Number.isNaN(e.top))&&(i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),function autoLayout(e,t,i,o){const r=new Map;e.forEach(e=>r.set(e.id,e));const n=new Map,s=new Map;e.forEach(e=>{n.set(e.id,0),s.set(e.id,[])}),t.forEach(e=>{r.has(e.sourceId)&&r.has(e.targetId)&&(n.set(e.targetId,(n.get(e.targetId)||0)+1),s.get(e.sourceId).push(e.targetId))});const a=new Map,l=[];e.forEach(e=>{0===(n.get(e.id)||0)&&(a.set(e.id,0),l.push(e.id))}),!l.length&&e.length&&(a.set(e[0].id,0),l.push(e[0].id));let d=e.length*e.length+e.length;for(;l.length&&d-- >0;){const e=l.shift(),t=a.get(e)||0;(s.get(e)||[]).forEach(e=>{const i=t+1;(a.get(e)??-1)<i&&(a.set(e,i),l.push(e))})}e.forEach(e=>{a.has(e.id)||a.set(e.id,0)});const h=new Map;e.forEach(e=>{const t=a.get(e.id)||0;h.has(t)||h.set(t,[]),h.get(t).push(e)});const p=[...h.keys()].sort((e,t)=>e-t),c=p.map(e=>Math.max(...h.get(e).map(e=>e.height)));c.reduce((e,t)=>e+t,0),Math.max(p.length-1,0);let u=0;p.forEach((e,t)=>{const r=h.get(e);let n=-(r.reduce((e,t)=>e+t.width,0)+Math.max(r.length-1,0)*i)/2;r.forEach(e=>{e.left=Math.round(n),e.top=Math.round(u+(c[t]-e.height)/2),n+=e.width+i}),u+=c[t]+o});const f=Math.min(...e.map(e=>e.left)),m=Math.min(...e.map(e=>e.top));e.forEach(e=>{e.left+=80-f,e.top+=80-m})}(i,o,Number(t.gapX)||90,Number(t.gapY)||90)),i.forEach(e=>{Number.isNaN(e.left)&&(e.left=0),Number.isNaN(e.top)&&(e.top=0)}),{kind:"flowchart",nodes:i,edges:o,layout:n,options:t}}function renderFlowDsl(e,i){const o=compileFlowDsl(i),r=o.options||{},n=(new t.ICE).init(e),s=new t.FlowDesigner(n);return o.nodes.forEach(e=>{s.createNode(e.kind,e)}),o.edges.forEach(e=>{s.createEdge(e)}),s.select(null),r.viewport?n.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):!1!==r.fitViewport&&s.fitViewport(r.fitViewportPadding),s.resetHistory(),{kind:"flowchart",ice:n,designer:s}}e.DSL_SCHEMA_VERSION=1,e.compileDsl=compileDsl,e.compileFlowDsl=compileFlowDsl,e.isFlowDsl=isFlowDsl,e.renderDsl=function renderDsl(e,i){const o=validateDsl(i);if(!o.valid)throw new Error(o.errors.join("\n"));return isFlowDsl(i)?renderFlowDsl(e,i):function renderErDsl(e,i){const o=compileDsl(i),r=o.options||{},n=(new t.ICE).init(e),s=new t.EntityDesigner(n);o.entities.forEach(e=>{s.createEntity(e)}),function positionLinks(e,t,i){const o=new Map;return e.entities.forEach(e=>{o.set(e.state.id,e.getMinBoundingBox(!0))}),t.relations.map(e=>{const t=o.get(e.sourceId),r=o.get(e.targetId);let n="R",s="L";if(t&&r){const e=r.center[0]-t.center[0],i=r.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(n=e>=0?"R":"L",s=e>=0?"L":"R"):(n=i>=0?"B":"T",s=i>=0?"T":"B")}return{...e,routeType:e.routeType||i||"orthogonal",linkShape:e.linkShape||"visio",links:{start:{id:e.sourceId,position:n},end:{id:e.targetId,position:s}}}})}(s,o,r.routeType).forEach(e=>{s.createRelation(e)}),("layered"===o.layout||"horizontal"===o.layout)&&new t.ICELayeredLayout({gapX:r.gapX||120,gapY:r.gapY||50}).layoutContainer(n);r.viewport?n.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):r.fitViewport&&function fitViewport(e,t,i){const o=t.entities||[];let r=1/0,n=1/0,s=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();r=Math.min(r,t.minX),n=Math.min(n,t.minY),s=Math.max(s,t.maxX),a=Math.max(a,t.maxY)});const l=s-r,d=a-n,h=e.canvasWidth||0,p=e.canvasHeight||0;if(!h||!p||l<=0||d<=0)return;const c=Number.isFinite(i)&&i>=0?i:40,u=Math.max(1,h-2*c),f=Math.max(1,p-2*c),m=Math.min(u/l,f/d,1),g=(h-l*m)/2-r*m,y=(p-d*m)/2-n*m;e.setViewport(m,g,y)}(n,s,r.fitViewportPadding);return{kind:"entity",ice:n,designer:s}}(e,i)},e.renderFlowDsl=renderFlowDsl,e.validateDsl=validateDsl,e.validateFlowDsl=validateFlowDsl,Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DslErDocument } from '../types';
|
|
2
2
|
export declare type CompiledScene = {
|
|
3
3
|
entities: Array<Record<string, any>>;
|
|
4
4
|
relations: Array<Record<string, any>>;
|
|
5
5
|
layout?: string;
|
|
6
6
|
options?: Record<string, any>;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
/** ER 文档 → Entity / Relation 构造参数(流程图请用 compileFlowDsl) */
|
|
9
|
+
export declare function compileDsl(dsl: DslErDocument): CompiledScene;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DslFlowDocument, DslFlowNodeKind } from '../types';
|
|
2
|
+
export declare type CompiledFlowNode = {
|
|
3
|
+
id: string;
|
|
4
|
+
typeId: string;
|
|
5
|
+
kind: DslFlowNodeKind;
|
|
6
|
+
title: string;
|
|
7
|
+
left: number;
|
|
8
|
+
top: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
fillColor: string;
|
|
12
|
+
strokeColor: string;
|
|
13
|
+
};
|
|
14
|
+
export declare type CompiledFlowEdge = {
|
|
15
|
+
id: string;
|
|
16
|
+
sourceId: string;
|
|
17
|
+
targetId: string;
|
|
18
|
+
sourcePort: string;
|
|
19
|
+
targetPort: string;
|
|
20
|
+
label: string;
|
|
21
|
+
linkShape: string;
|
|
22
|
+
};
|
|
23
|
+
export declare type CompiledFlowScene = {
|
|
24
|
+
kind: 'flowchart';
|
|
25
|
+
nodes: CompiledFlowNode[];
|
|
26
|
+
edges: CompiledFlowEdge[];
|
|
27
|
+
layout: string;
|
|
28
|
+
options?: Record<string, any>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* 流程图 DSL → FlowNode / FlowEdge 构造参数。
|
|
32
|
+
*
|
|
33
|
+
* - 节点缺省尺寸/配色取 `FLOW_NODE_KINDS` 预设;
|
|
34
|
+
* - 只要有一个节点缺坐标(或显式 `layout: 'layered'`),就对全部节点做分层自动布局;
|
|
35
|
+
* - 连线的端口默认「下出上入」(B → T),分支标签走 label。
|
|
36
|
+
*/
|
|
37
|
+
export declare function compileFlowDsl(dsl: DslFlowDocument): CompiledFlowScene;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './types';
|
|
2
|
-
export { DSL_SCHEMA_VERSION, validateDsl } from './validate';
|
|
2
|
+
export { DSL_SCHEMA_VERSION, validateDsl, validateFlowDsl } from './validate';
|
|
3
3
|
export { compileDsl } from './compiler/dslToScene';
|
|
4
4
|
export type { CompiledScene } from './compiler/dslToScene';
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
5
|
+
export { compileFlowDsl } from './compiler/flowToScene';
|
|
6
|
+
export type { CompiledFlowScene, CompiledFlowNode, CompiledFlowEdge } from './compiler/flowToScene';
|
|
7
|
+
export { renderDsl, renderFlowDsl } from './runtime/renderDsl';
|
|
8
|
+
export type { RenderDslResult, RenderErDslResult, RenderFlowDslResult } from './runtime/renderDsl';
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import type { DslDocument } from '../types';
|
|
2
|
-
export declare type
|
|
1
|
+
import type { DslDocument, DslFlowDocument } from '../types';
|
|
2
|
+
export declare type RenderErDslResult = {
|
|
3
|
+
kind: 'entity';
|
|
3
4
|
ice: any;
|
|
4
5
|
designer: any;
|
|
5
6
|
};
|
|
7
|
+
export declare type RenderFlowDslResult = {
|
|
8
|
+
kind: 'flowchart';
|
|
9
|
+
ice: any;
|
|
10
|
+
designer: any;
|
|
11
|
+
};
|
|
12
|
+
export declare type RenderDslResult = RenderErDslResult | RenderFlowDslResult;
|
|
13
|
+
/**
|
|
14
|
+
* 渲染一份 DSL 文档:ER 文档(entities/relations)或流程图文档(kind: 'flowchart')。
|
|
15
|
+
*
|
|
16
|
+
* 两种文档共用同一个入口,返回的 `kind` 表明实际渲染的是哪一类,
|
|
17
|
+
* `designer` 分别是 `EntityDesigner` / `FlowDesigner` 实例。
|
|
18
|
+
*/
|
|
6
19
|
export declare function renderDsl(canvasOrId: any, dsl: DslDocument): RenderDslResult;
|
|
20
|
+
/** 渲染流程图文档:节点缺坐标时已由 compileFlowDsl 做过分层自动布局 */
|
|
21
|
+
export declare function renderFlowDsl(canvasOrId: any, dsl: DslFlowDocument): RenderFlowDslResult;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -55,7 +55,8 @@ export declare type DslRelation = {
|
|
|
55
55
|
lineDash?: number[];
|
|
56
56
|
};
|
|
57
57
|
export declare type DslLayout = 'grid' | 'layered' | 'horizontal' | 'vertical';
|
|
58
|
-
|
|
58
|
+
/** ER 文档(实体 / 关系) */
|
|
59
|
+
export declare type DslErDocument = {
|
|
59
60
|
schemaVersion?: number;
|
|
60
61
|
entities: DslEntity[];
|
|
61
62
|
relations?: DslRelation[];
|
|
@@ -67,7 +68,60 @@ export declare type DslDocument = {
|
|
|
67
68
|
gapY?: number;
|
|
68
69
|
};
|
|
69
70
|
};
|
|
71
|
+
export declare type DslPort = 'T' | 'R' | 'B' | 'L' | 'C';
|
|
72
|
+
export declare type DslFlowNodeKind = 'terminator' | 'process' | 'decision' | 'io';
|
|
73
|
+
export declare type DslFlowNode = {
|
|
74
|
+
id: string;
|
|
75
|
+
/** 节点类型,默认 process */
|
|
76
|
+
kind?: DslFlowNodeKind;
|
|
77
|
+
/** 节点文字(title / name 二者取一,name 兼容 ER 文档写法) */
|
|
78
|
+
title?: string;
|
|
79
|
+
name?: string;
|
|
80
|
+
left?: number;
|
|
81
|
+
top?: number;
|
|
82
|
+
width?: number;
|
|
83
|
+
height?: number;
|
|
84
|
+
fillColor?: string;
|
|
85
|
+
strokeColor?: string;
|
|
86
|
+
};
|
|
87
|
+
export declare type DslFlowEdge = {
|
|
88
|
+
id?: string;
|
|
89
|
+
source: string;
|
|
90
|
+
target: string;
|
|
91
|
+
/** 分支标签,例如「是 / 否」 */
|
|
92
|
+
label?: string;
|
|
93
|
+
/** 连线离开源节点的位置,默认 B(下) */
|
|
94
|
+
sourcePort?: DslPort;
|
|
95
|
+
/** 连线进入目标节点的位置,默认 T(上) */
|
|
96
|
+
targetPort?: DslPort;
|
|
97
|
+
linkShape?: 'visio' | 'bezier';
|
|
98
|
+
};
|
|
99
|
+
export declare type DslFlowDocumentOptions = {
|
|
100
|
+
/** 是否自动适应视图,默认 true */
|
|
101
|
+
fitViewport?: boolean;
|
|
102
|
+
fitViewportPadding?: number;
|
|
103
|
+
viewport?: {
|
|
104
|
+
scale: number;
|
|
105
|
+
tx: number;
|
|
106
|
+
ty: number;
|
|
107
|
+
};
|
|
108
|
+
/** 节点缺坐标时的自动布局,默认 layered */
|
|
109
|
+
layout?: 'layered' | 'none';
|
|
110
|
+
gapX?: number;
|
|
111
|
+
gapY?: number;
|
|
112
|
+
};
|
|
113
|
+
export declare type DslFlowDocument = {
|
|
114
|
+
schemaVersion?: number;
|
|
115
|
+
kind: 'flowchart';
|
|
116
|
+
nodes: DslFlowNode[];
|
|
117
|
+
edges?: DslFlowEdge[];
|
|
118
|
+
options?: DslFlowDocumentOptions;
|
|
119
|
+
};
|
|
120
|
+
/** 一份 DSL 文档:ER(默认)或 流程图(kind: 'flowchart') */
|
|
121
|
+
export declare type DslDocument = DslErDocument | DslFlowDocument;
|
|
70
122
|
export declare type DslValidationResult = {
|
|
71
123
|
valid: boolean;
|
|
72
124
|
errors: string[];
|
|
73
125
|
};
|
|
126
|
+
/** 运行时判别:带 kind: 'flowchart' 的按流程图文档处理 */
|
|
127
|
+
export declare function isFlowDsl(dsl: any): dsl is DslFlowDocument;
|
package/dist/types/validate.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
import type { DslDocument, DslValidationResult } from './types';
|
|
1
|
+
import type { DslDocument, DslFlowDocument, DslValidationResult } from './types';
|
|
2
2
|
export declare const DSL_SCHEMA_VERSION = 1;
|
|
3
|
+
/** 校验一份 DSL 文档:ER 文档(entities/relations)或流程图文档(kind: 'flowchart' + nodes/edges) */
|
|
3
4
|
export declare function validateDsl(dsl: DslDocument): DslValidationResult;
|
|
5
|
+
/** 流程图文档校验:结构 + 端点必须指向已存在的节点(与 ER 的关系校验同一口径) */
|
|
6
|
+
export declare function validateFlowDsl(dsl: DslFlowDocument): DslValidationResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ice-entity-designer-dsl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A JSON-first DSL layer for AI agents to drive ice-entity-designer.",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"types:check": "tsc --noEmit"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"ice-entity-designer": "^0.0.
|
|
22
|
+
"ice-entity-designer": "^0.0.20"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@babel/core": "7.17.8",
|