ice-entity-designer-dsl 0.0.6 → 0.0.7
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/README.md +58 -7
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/types/compiler/bpmnToScene.d.ts +50 -0
- package/dist/types/compiler/layout.d.ts +38 -0
- package/dist/types/index.d.ts +7 -3
- package/dist/types/runtime/renderDsl.d.ts +15 -2
- package/dist/types/types.d.ts +76 -2
- package/dist/types/validate.d.ts +13 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
JSON-first DSL for AI agents to drive `ice-entity-designer` without learning the imperative canvas API.
|
|
4
4
|
|
|
5
|
-
One document kind,
|
|
5
|
+
One document kind, three shapes:
|
|
6
6
|
|
|
7
7
|
- **ER document** (`entities` / `relations`): entity-relation models and database schemas.
|
|
8
8
|
- **Flowchart document** (`kind: "flowchart"` with `nodes` / `edges`): process flows,
|
|
9
9
|
decision trees, and algorithms, with optional coordinates (layered auto-layout).
|
|
10
|
+
- **BPMN document** (`kind: "bpmn"` with `nodes` / `edges`): business processes with
|
|
11
|
+
participants (pools), lanes, events, gateways and message flows. Containers are
|
|
12
|
+
nodes too, so the document stays a flat list; geometries are optional.
|
|
10
13
|
|
|
11
14
|
The package contains:
|
|
12
15
|
|
|
13
|
-
- DSL types and schema (ER + flowchart)
|
|
16
|
+
- DSL types and schema (ER + flowchart + BPMN)
|
|
14
17
|
- structural validator
|
|
15
|
-
- compilers from DSL to Entity/Relation or FlowNode/FlowEdge props
|
|
18
|
+
- compilers from DSL to Entity/Relation or FlowNode/FlowEdge props (shared layered layout)
|
|
16
19
|
- browser runtime that renders DSL through `ice-entity-designer`
|
|
17
|
-
- browser examples with a JSON editor (`examples/entity-editor-dsl.html`,
|
|
20
|
+
- browser examples with a JSON editor (`examples/entity-editor-dsl.html`,
|
|
21
|
+
`examples/flowchart-dsl.html`, `examples/bpmn-dsl.html`)
|
|
18
22
|
|
|
19
23
|
## Install
|
|
20
24
|
|
|
@@ -84,17 +88,64 @@ Node kinds: `terminator` (start/end pill) / `process` (action, default) / `decis
|
|
|
84
88
|
(diamond) / `io` (parallelogram). Edge ports are `T` / `R` / `B` / `L` / `C` (default
|
|
85
89
|
`B` → `T`); `linkShape` is `visio` (orthogonal, default) or `bezier`.
|
|
86
90
|
|
|
91
|
+
## BPMN usage
|
|
92
|
+
|
|
93
|
+
Pools and lanes are nodes (`kind: "pool"` / `kind: "lane"`); everything else points
|
|
94
|
+
into a container with `parent`. Give coordinates and the compiler is the identity —
|
|
95
|
+
omit them and containers are sized from their contents while the flow nodes are laid
|
|
96
|
+
out left-to-right inside their container.
|
|
97
|
+
|
|
98
|
+
左侧是这份 DSL,右侧是它的渲染结果(`examples/bpmn-dsl.html`)——节点坐标全部省略,
|
|
99
|
+
池高、泳道条带与图元落位都是编译期算出来的:
|
|
100
|
+
|
|
101
|
+
<img src="https://raw.githubusercontent.com/ice-render/ice-entity-designer-dsl/main/examples/bpmn-dsl.png" alt="BPMN DSL 渲染示例" />
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const bpmn = {
|
|
105
|
+
schemaVersion: 1,
|
|
106
|
+
kind: 'bpmn',
|
|
107
|
+
nodes: [
|
|
108
|
+
{ id: 'bank', kind: 'pool', title: '银行' },
|
|
109
|
+
{ id: 'accept', kind: 'lane', title: '受理岗', parent: 'bank' },
|
|
110
|
+
{ id: 'risk', kind: 'lane', title: '风控岗', parent: 'bank' },
|
|
111
|
+
{ id: 'submit', kind: 'event', title: '申请提交', eventKind: 'start', parent: 'accept' },
|
|
112
|
+
{ id: 'verify', kind: 'task', title: '身份核验', taskType: 'service', parent: 'accept' },
|
|
113
|
+
{ id: 'ok', kind: 'event', title: '申请通过', eventKind: 'end', parent: 'risk' },
|
|
114
|
+
],
|
|
115
|
+
edges: [
|
|
116
|
+
{ source: 'submit', target: 'verify', label: '受理' },
|
|
117
|
+
{ source: 'verify', target: 'ok' },
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const result = ICEDSL.renderDsl('canvas', bpmn);
|
|
122
|
+
// result.kind === 'bpmn'; result.designer is a BpmnDesigner
|
|
123
|
+
result.designer.validateBpmn(); // 语义检查:每个池一个开始事件、顺序流不跨池…
|
|
124
|
+
const xml = IED.toBpmnXml(result.designer); // BPMN 2.0 + BPMNDI(互操作格式,不是执行模型)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Node kinds: `pool` / `lane` (containers), `task` (default), `event`, `gateway`,
|
|
128
|
+
`subprocess`, `dataObject`, `annotation`; events carry `eventKind` (start /
|
|
129
|
+
intermediate / end) + `trigger`, gateways carry `gatewayType` (exclusive / parallel
|
|
130
|
+
/ inclusive / event), tasks carry `taskType` (none / user / service / script / send
|
|
131
|
+
/ receive / manual). Edge `type`: `sequence` (default) / `message` (across pools) /
|
|
132
|
+
`association` (data objects, annotations); sequence flows also take `condition` and
|
|
133
|
+
`isDefault`.
|
|
134
|
+
|
|
87
135
|
## API
|
|
88
136
|
|
|
89
|
-
- `validateDsl(dsl)` —— ER / flowchart documents (dispatches on `kind`); `validateFlowDsl(dsl)` for
|
|
137
|
+
- `validateDsl(dsl)` —— ER / flowchart / BPMN documents (dispatches on `kind`); `validateFlowDsl(dsl)` / `validateBpmnDsl(dsl)` for one kind only
|
|
90
138
|
- `compileDsl(dsl)` —— ER document → `Entity` / `Relation` props
|
|
91
139
|
- `compileFlowDsl(dsl)` —— flowchart document → `FlowNode` / `FlowEdge` props (with layered auto-layout)
|
|
92
|
-
- `
|
|
140
|
+
- `compileBpmnDsl(dsl)` —— BPMN document → `FlowNode` / `FlowEdge` props (container auto-geometry + container-scoped auto-layout)
|
|
141
|
+
- `layeredLayout(items, edges, options)` —— the shared layered layout (`direction: "vertical" | "horizontal"`)
|
|
142
|
+
- `renderDsl(canvasOrId, dsl)` —— renders any kind, returns `{ kind, ice, designer }`
|
|
93
143
|
- `DSL_SCHEMA_VERSION`
|
|
94
144
|
|
|
95
145
|
## Example
|
|
96
146
|
|
|
97
|
-
Open `examples/entity-editor-dsl.html` (ER)
|
|
147
|
+
Open `examples/entity-editor-dsl.html` (ER), `examples/flowchart-dsl.html`
|
|
148
|
+
(flowchart) or `examples/bpmn-dsl.html` (BPMN) after building.
|
|
98
149
|
|
|
99
150
|
## Agent discovery
|
|
100
151
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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}function isBpmnDsl(e){return!!e&&"object"==typeof e&&"bpmn"===e.kind}const t=["terminator","process","decision","io"],i=["T","R","B","L","C"],o=["pool","lane","task","event","gateway","subprocess","dataObject","annotation"],n=["start","intermediate","end"],r=["none","message","timer","error","terminate"],s=["exclusive","parallel","inclusive","event"],a=["none","user","service","script","send","receive","manual"],l=["sequence","message","association"];function validateDsl(e){return isBpmnDsl(e)?validateBpmnDsl(e):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 n=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${n}.id is duplicated: ${e.id}`):i.add(e.id):t.push(n+".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(`${n}.fields[${i}].name must be a non-empty string`)}):t.push(n+".fields must be an array")):t.push(n+" 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 validateBpmnDsl(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,p=new Map;return Array.isArray(e.nodes)?(e.nodes.forEach((e,l)=>{const d=`nodes[${l}]`;if(!e||"object"!=typeof e)return void t.push(d+" must be an object");"string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${d}.id is duplicated: ${e.id}`):(i.add(e.id),p.set(e.id,e.kind||"task")):t.push(d+".id must be a non-empty string"),void 0!==e.kind&&-1===o.indexOf(e.kind)&&t.push(`${d}.kind must be one of ${o.join("/")}`),["left","top","width","height"].forEach(i=>{const o=e[i];void 0!==o&&"number"!=typeof o&&t.push(`${d}.${i} must be a number when present`)});[["eventKind",n],["trigger",r],["gatewayType",s],["taskType",a]].forEach(([i,o])=>{const n=e[i];void 0!==n&&-1===o.indexOf(n)&&t.push(`${d}.${i} must be one of ${o.join("/")}`)})}),e.nodes.forEach((e,o)=>{if(!e||"object"!=typeof e||void 0===e.parent)return;const n=`nodes[${o}]`;if("string"!=typeof e.parent||!e.parent.trim())return void t.push(n+".parent must be a non-empty string when present");if(!i.has(e.parent))return void t.push(n+".parent must reference an existing node id");if(e.parent===e.id)return void t.push(n+".parent must not reference itself");const r=p.get(e.parent);"pool"===e.kind?t.push(n+".parent is not allowed on a pool (池是最外层容器)"):"lane"===e.kind&&"pool"!==r?t.push(n+".parent must reference a pool"):"pool"!==r&&"lane"!==r&&t.push(n+".parent must reference a pool or a lane")})):t.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,o)=>{const n=`edges[${o}]`;if(!e||"object"!=typeof e)return void t.push(n+" must be an object");"string"==typeof e.source&&e.source.trim()&&i.has(e.source)||t.push(n+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&i.has(e.target)||t.push(n+".target must reference an existing node id");const r=void 0!==e.type?e.type:e.flowType;void 0!==r&&-1===l.indexOf(r)&&t.push(`${n}.type must be one of ${l.join("/")}`),void 0!==e.label&&"string"!=typeof e.label&&t.push(n+".label must be a string when present"),void 0!==e.condition&&"string"!=typeof e.condition&&t.push(n+".condition must be a string when present"),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&t.push(n+'.linkShape must be "visio" or "bezier" when present')}):t.push("edges must be an array when present"),{valid:0===t.length,errors:t}}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 n=new Set;return Array.isArray(e.nodes)?e.nodes.forEach((e,i)=>{const r=`nodes[${i}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?n.has(e.id)?o.push(`${r}.id is duplicated: ${e.id}`):n.add(e.id):o.push(r+".id must be a non-empty string"),void 0!==e.kind&&-1===t.indexOf(e.kind)&&o.push(`${r}.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(`${r}.${t} must be a number when present`)})):o.push(r+" 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 r=`edges[${t}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&n.has(e.source)||o.push(r+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&n.has(e.target)||o.push(r+".target must reference an existing node id"),void 0!==e.label&&"string"!=typeof e.label&&o.push(r+".label must be a string when present"),void 0!==e.sourcePort&&-1===i.indexOf(e.sourcePort)&&o.push(`${r}.sourcePort must be one of ${i.join("/")}`),void 0!==e.targetPort&&-1===i.indexOf(e.targetPort)&&o.push(`${r}.targetPort must be one of ${i.join("/")}`),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&o.push(r+'.linkShape must be "visio" or "bezier" when present')):o.push(r+" 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}}function layeredLayout(e,t,i={}){const o=Number(i.gapX)||90,n=Number(i.gapY)||90,r=void 0===i.originX?80:i.originX,s=void 0===i.originY?80:i.originY,a=new Map;if(!e.length)return a;const l=new Map;e.forEach(e=>l.set(e.id,e));const p=new Map,d=new Map;e.forEach(e=>{p.set(e.id,0),d.set(e.id,[])}),t.forEach(e=>{l.has(e.sourceId)&&l.has(e.targetId)&&(p.set(e.targetId,(p.get(e.targetId)||0)+1),d.get(e.sourceId).push(e.targetId))});const h=new Map,c=[];e.forEach(e=>{0===(p.get(e.id)||0)&&(h.set(e.id,0),c.push(e.id))}),c.length||(h.set(e[0].id,0),c.push(e[0].id));let u=e.length*e.length+e.length;for(;c.length&&u-- >0;){const e=c.shift(),t=h.get(e)||0;(d.get(e)||[]).forEach(e=>{const i=t+1;(void 0===h.get(e)?-1:h.get(e))<i&&(h.set(e,i),c.push(e))})}e.forEach(e=>{h.has(e.id)||h.set(e.id,0)});const f=new Map;e.forEach(e=>{const t=h.get(e.id)||0;f.has(t)||f.set(t,[]),f.get(t).push(e)});const m=[...f.keys()].sort((e,t)=>e-t);if("horizontal"===i.direction){const e=m.map(e=>Math.max(...f.get(e).map(e=>e.width)));let t=0;m.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.height,0)+Math.max(s.length-1,0)*n)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(t+(e[r]-i.width)/2),top:Math.round(l)}),l+=i.height+n}),t+=e[r]+o})}else{const e=m.map(e=>Math.max(...f.get(e).map(e=>e.height)));let t=0;m.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.width,0)+Math.max(s.length-1,0)*o)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(l),top:Math.round(t+(e[r]-i.height)/2)}),l+=i.width+o}),t+=e[r]+n})}const g=Math.min(...e.map(e=>a.get(e.id).left)),y=Math.min(...e.map(e=>a.get(e.id).top));return a.forEach(e=>{e.left+=r-g,e.top+=s-y}),a}const p={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&&p[e.kind]?e.kind:"process"}(e),i=p[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 n=layeredLayout(e,t,{gapX:i,gapY:o});e.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)})}(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}}const d={pool:"bpmnPool",lane:"bpmnLane",task:"bpmnTask",event:"bpmnEvent",gateway:"bpmnGateway",subprocess:"bpmnSubprocess",dataObject:"bpmnDataObject",annotation:"bpmnAnnotation"},h=Number(e.FLOW_NODE_KINDS.bpmnPool.bandSize)||32,c=Number(e.FLOW_NODE_KINDS.bpmnLane.bandSize)||32,u=Number(e.FLOW_NODE_KINDS.bpmnLane.height)||130,f=Number(e.FLOW_NODE_KINDS.bpmnPool.width)||900;function toWorkingNode(t){const i=t.kind||"task",o=function presetOf(t){return e.FLOW_NODE_KINDS[t]||e.FLOW_NODE_KINDS.bpmnTask}(d[i]||"bpmnTask"),n={id:t.id,typeId:"FlowNode",kind:d[i]||"bpmnTask",title:t.title||t.name||t.id,left:"number"==typeof t.left?t.left:0,top:"number"==typeof t.top?t.top:0,width:"number"==typeof t.width?t.width:o.width,height:"number"==typeof t.height?t.height:o.height,fillColor:t.fillColor,strokeColor:t.strokeColor,dslKind:i,parent:t.parent,explicitLeft:"number"==typeof t.left,explicitTop:"number"==typeof t.top,explicitWidth:"number"==typeof t.width,explicitHeight:"number"==typeof t.height};return"event"===i&&(n.eventKind=t.eventKind||o.eventKind||"start",n.trigger=t.trigger||o.trigger||"none"),"gateway"===i&&(n.gatewayType=t.gatewayType||o.gatewayType||"exclusive"),"task"!==i&&"subprocess"!==i||(n.taskType=t.taskType||o.taskType||"none"),n}function buildGroups(e,t){const i=new Map;t.forEach(e=>i.set(e.id,e));const o=1===t.length?t[0]:null,n=[];return e.forEach(e=>{(e=>{let t=n.filter(t=>t.owner===e)[0];return t||(t={owner:e,nodes:[],box:null,didLayout:!1},n.push(t)),t})((e.parent?i.get(e.parent):void 0)||o).nodes.push(e)}),n}function layoutGroups(e,t,i,o){e.forEach(e=>{if(e.nodes.some(e=>!e.explicitLeft||!e.explicitTop)){const n=layeredLayout(e.nodes,t,{gapX:i,gapY:o,originX:0,originY:0,direction:"horizontal"});e.nodes.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)}),e.didLayout=!0}e.box=function unionBox(e){if(!e.length)return null;let t=1/0,i=1/0,o=-1/0,n=-1/0;return e.forEach(e=>{t=Math.min(t,e.left),i=Math.min(i,e.top),o=Math.max(o,e.left+e.width),n=Math.max(n,e.top+e.height)}),{minX:t,minY:i,maxX:o,maxY:n}}(e.nodes)})}function compileBpmnDsl(e){const t=e.options||{},i=(e.nodes||[]).map(toWorkingNode),o=i.filter(e=>"pool"===e.dslKind),n=i.filter(e=>"lane"===e.dslKind),r=i.filter(e=>!function isContainer(e){return"pool"===e.dslKind||"lane"===e.dslKind}(e)),s=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,flowType:e.type||e.flowType||"sequence",label:e.label||"",condition:e.condition||"",isDefault:!!e.isDefault,linkShape:e.linkShape||"visio"})),a=t.layout||"auto",l=function resolveLaneOwners(e,t){const i=new Map;return e.forEach(e=>{let o=e.parent;o||1!==t.length||(o=t[0].id),o&&i.set(e.id,o)}),i}(n,o),lanesOf=e=>n.filter(t=>l.get(t.id)===e);let p=[];"none"!==a&&(p=buildGroups(r,o.concat(n)),layoutGroups(p,s,Number(t.gapX)||90,Number(t.gapY)||60)),n.forEach(e=>{const t=p.filter(t=>t.owner===e)[0],i=t?t.box:null;e.explicitHeight||(e.height=Math.round(Math.max(56+(i?i.maxY-i.minY:0),u))),e.explicitWidth||(e.width=Math.round(Math.max((i?i.maxX-i.minX:0)+c+56,f)))}),o.forEach(e=>{const t=lanesOf(e.id);if(t.length){const i=t.reduce((e,t)=>Math.max(e,t.width),f);return e.explicitWidth||(e.width=i),e.explicitWidth&&t.forEach(t=>{t.explicitWidth||(t.width=e.width)}),void(e.explicitHeight||(e.height=h+t.reduce((e,t)=>e+t.height,0)))}const i=p.filter(t=>t.owner===e)[0],o=i?i.box:null;e.explicitWidth||(e.width=Math.round(Math.max(56+(o?o.maxX-o.minX:0),f))),e.explicitHeight||(e.height=Math.round(Math.max((o?o.maxY-o.minY:0)+h+56,160)))});let d=60;o.forEach(e=>{e.explicitLeft||(e.left=60),e.explicitTop||(e.top=d),d=Math.max(d,e.top+e.height+60)}),o.forEach(e=>{const t=lanesOf(e.id);if(!t.length)return;const i=e.top+h,o=Math.max(e.height-h,1),n=t.reduce((e,t)=>e+(t.explicitHeight?t.height:0),0),r=t.filter(e=>!e.explicitHeight),s=r.length?Math.max(o-n,0)/r.length:0;let a=i;t.forEach(t=>{t.explicitLeft||(t.left=e.left),t.explicitTop||(t.top=a),!t.explicitHeight&&e.explicitHeight&&(t.height=Math.round(s||u)),a=t.top+t.height})});let m=60;n.forEach(e=>{l.get(e.id)||(e.explicitLeft||(e.left=60),e.explicitTop||(e.top=m,m=e.top+e.height+60))}),p.forEach(e=>{const t=e.box;if(!t||!e.didLayout)return;const i=e.owner;let o=80,n=80;i&&(o=i.left+28,n=i.top+28,"pool"===i.dslKind?n+=h:o+=c),e.nodes.forEach(e=>{e.left=Math.round(o+(e.left-t.minX)),e.top=Math.round(n+(e.top-t.minY))})});return{kind:"bpmn",nodes:o.concat(n).concat(r).map(e=>{const t={id:e.id,typeId:"FlowNode",kind:e.kind,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};return void 0!==e.eventKind&&(t.eventKind=e.eventKind),void 0!==e.trigger&&(t.trigger=e.trigger),void 0!==e.gatewayType&&(t.gatewayType=e.gatewayType),void 0!==e.taskType&&(t.taskType=e.taskType),void 0!==e.fillColor&&(t.fillColor=e.fillColor),void 0!==e.strokeColor&&(t.strokeColor=e.strokeColor),t}),edges:s,layout:a,options:t}}function renderBpmnDsl(t,i){const o=compileBpmnDsl(i),n=o.options||{},r=(new e.ICE).init(t),s=new e.BpmnDesigner(r);return o.nodes.forEach(e=>{const t={id:e.id,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};["eventKind","trigger","gatewayType","taskType","fillColor","strokeColor"].forEach(i=>{void 0!==e[i]&&(t[i]=e[i])}),s.createNode(e.kind,t)}),o.edges.forEach(e=>{s.createEdge(e)}),s.select(null),n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):!1!==n.fitViewport&&s.fitViewport(n.fitViewportPadding),s.resetHistory(),{kind:"bpmn",ice:r,designer:s}}function renderFlowDsl(t,i){const o=compileFlowDsl(i),n=o.options||{},r=(new e.ICE).init(t),s=new e.FlowDesigner(r);return o.nodes.forEach(e=>{s.createNode(e.kind,e)}),o.edges.forEach(e=>{s.createEdge(e)}),s.select(null),n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):!1!==n.fitViewport&&s.fitViewport(n.fitViewportPadding),s.resetHistory(),{kind:"flowchart",ice:r,designer:s}}exports.DSL_SCHEMA_VERSION=1,exports.compileBpmnDsl=compileBpmnDsl,exports.compileDsl=compileDsl,exports.compileFlowDsl=compileFlowDsl,exports.isBpmnDsl=isBpmnDsl,exports.isFlowDsl=isFlowDsl,exports.layeredLayout=layeredLayout,exports.renderBpmnDsl=renderBpmnDsl,exports.renderDsl=function renderDsl(t,i){const o=validateDsl(i);if(!o.valid)throw new Error(o.errors.join("\n"));return isBpmnDsl(i)?renderBpmnDsl(t,i):isFlowDsl(i)?renderFlowDsl(t,i):function renderErDsl(t,i){const o=compileDsl(i),n=o.options||{},r=(new e.ICE).init(t),s=new e.EntityDesigner(r);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),n=o.get(e.targetId);let r="R",s="L";if(t&&n){const e=n.center[0]-t.center[0],i=n.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(r=e>=0?"R":"L",s=e>=0?"L":"R"):(r=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:r},end:{id:e.targetId,position:s}}}})}(s,o,n.routeType).forEach(e=>{s.createRelation(e)}),("layered"===o.layout||"horizontal"===o.layout)&&new e.ICELayeredLayout({gapX:n.gapX||120,gapY:n.gapY||50}).layoutContainer(r);n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):n.fitViewport&&function fitViewport(e,t,i){const o=t.entities||[];let n=1/0,r=1/0,s=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();n=Math.min(n,t.minX),r=Math.min(r,t.minY),s=Math.max(s,t.maxX),a=Math.max(a,t.maxY)});const l=s-n,p=a-r,d=e.canvasWidth||0,h=e.canvasHeight||0;if(!d||!h||l<=0||p<=0)return;const c=Number.isFinite(i)&&i>=0?i:40,u=Math.max(1,d-2*c),f=Math.max(1,h-2*c),m=Math.min(u/l,f/p,1),g=(d-l*m)/2-n*m,y=(h-p*m)/2-r*m;e.setViewport(m,g,y)}(r,s,n.fitViewportPadding);return{kind:"entity",ice:r,designer:s}}(t,i)},exports.renderFlowDsl=renderFlowDsl,exports.validateBpmnDsl=validateBpmnDsl,exports.validateDsl=validateDsl,exports.validateFlowDsl=validateFlowDsl;
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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};
|
|
1
|
+
import{FLOW_NODE_KINDS as e,ICE as t,BpmnDesigner as i,FlowDesigner as o,EntityDesigner as n,ICELayeredLayout as r}from"ice-entity-designer";function isFlowDsl(e){return!!e&&"object"==typeof e&&"flowchart"===e.kind}function isBpmnDsl(e){return!!e&&"object"==typeof e&&"bpmn"===e.kind}const s=1,a=["terminator","process","decision","io"],l=["T","R","B","L","C"],d=["pool","lane","task","event","gateway","subprocess","dataObject","annotation"],p=["start","intermediate","end"],h=["none","message","timer","error","terminate"],c=["exclusive","parallel","inclusive","event"],u=["none","user","service","script","send","receive","manual"],f=["sequence","message","association"];function validateDsl(e){return isBpmnDsl(e)?validateBpmnDsl(e):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 n=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${n}.id is duplicated: ${e.id}`):i.add(e.id):t.push(n+".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(`${n}.fields[${i}].name must be a non-empty string`)}):t.push(n+".fields must be an array")):t.push(n+" 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 validateBpmnDsl(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,o=new Map;return Array.isArray(e.nodes)?(e.nodes.forEach((e,n)=>{const r=`nodes[${n}]`;if(!e||"object"!=typeof e)return void t.push(r+" must be an object");"string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):(i.add(e.id),o.set(e.id,e.kind||"task")):t.push(r+".id must be a non-empty string"),void 0!==e.kind&&-1===d.indexOf(e.kind)&&t.push(`${r}.kind must be one of ${d.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`)});[["eventKind",p],["trigger",h],["gatewayType",c],["taskType",u]].forEach(([i,o])=>{const n=e[i];void 0!==n&&-1===o.indexOf(n)&&t.push(`${r}.${i} must be one of ${o.join("/")}`)})}),e.nodes.forEach((e,n)=>{if(!e||"object"!=typeof e||void 0===e.parent)return;const r=`nodes[${n}]`;if("string"!=typeof e.parent||!e.parent.trim())return void t.push(r+".parent must be a non-empty string when present");if(!i.has(e.parent))return void t.push(r+".parent must reference an existing node id");if(e.parent===e.id)return void t.push(r+".parent must not reference itself");const s=o.get(e.parent);"pool"===e.kind?t.push(r+".parent is not allowed on a pool (池是最外层容器)"):"lane"===e.kind&&"pool"!==s?t.push(r+".parent must reference a pool"):"pool"!==s&&"lane"!==s&&t.push(r+".parent must reference a pool or a lane")})):t.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,o)=>{const n=`edges[${o}]`;if(!e||"object"!=typeof e)return void t.push(n+" must be an object");"string"==typeof e.source&&e.source.trim()&&i.has(e.source)||t.push(n+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&i.has(e.target)||t.push(n+".target must reference an existing node id");const r=void 0!==e.type?e.type:e.flowType;void 0!==r&&-1===f.indexOf(r)&&t.push(`${n}.type must be one of ${f.join("/")}`),void 0!==e.label&&"string"!=typeof e.label&&t.push(n+".label must be a string when present"),void 0!==e.condition&&"string"!=typeof e.condition&&t.push(n+".condition must be a string when present"),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&t.push(n+'.linkShape must be "visio" or "bezier" when present')}):t.push("edges must be an array when present"),{valid:0===t.length,errors:t}}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 n=`nodes[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${n}.id is duplicated: ${e.id}`):i.add(e.id):t.push(n+".id must be a non-empty string"),void 0!==e.kind&&-1===a.indexOf(e.kind)&&t.push(`${n}.kind must be one of ${a.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,o)=>{const n=`edges[${o}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&i.has(e.source)||t.push(n+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&i.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===l.indexOf(e.sourcePort)&&t.push(`${n}.sourcePort must be one of ${l.join("/")}`),void 0!==e.targetPort&&-1===l.indexOf(e.targetPort)&&t.push(`${n}.targetPort must be one of ${l.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}}function layeredLayout(e,t,i={}){const o=Number(i.gapX)||90,n=Number(i.gapY)||90,r=void 0===i.originX?80:i.originX,s=void 0===i.originY?80:i.originY,a=new Map;if(!e.length)return a;const l=new Map;e.forEach(e=>l.set(e.id,e));const d=new Map,p=new Map;e.forEach(e=>{d.set(e.id,0),p.set(e.id,[])}),t.forEach(e=>{l.has(e.sourceId)&&l.has(e.targetId)&&(d.set(e.targetId,(d.get(e.targetId)||0)+1),p.get(e.sourceId).push(e.targetId))});const h=new Map,c=[];e.forEach(e=>{0===(d.get(e.id)||0)&&(h.set(e.id,0),c.push(e.id))}),c.length||(h.set(e[0].id,0),c.push(e[0].id));let u=e.length*e.length+e.length;for(;c.length&&u-- >0;){const e=c.shift(),t=h.get(e)||0;(p.get(e)||[]).forEach(e=>{const i=t+1;(void 0===h.get(e)?-1:h.get(e))<i&&(h.set(e,i),c.push(e))})}e.forEach(e=>{h.has(e.id)||h.set(e.id,0)});const f=new Map;e.forEach(e=>{const t=h.get(e.id)||0;f.has(t)||f.set(t,[]),f.get(t).push(e)});const g=[...f.keys()].sort((e,t)=>e-t);if("horizontal"===i.direction){const e=g.map(e=>Math.max(...f.get(e).map(e=>e.width)));let t=0;g.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.height,0)+Math.max(s.length-1,0)*n)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(t+(e[r]-i.width)/2),top:Math.round(l)}),l+=i.height+n}),t+=e[r]+o})}else{const e=g.map(e=>Math.max(...f.get(e).map(e=>e.height)));let t=0;g.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.width,0)+Math.max(s.length-1,0)*o)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(l),top:Math.round(t+(e[r]-i.height)/2)}),l+=i.width+o}),t+=e[r]+n})}const m=Math.min(...e.map(e=>a.get(e.id).left)),y=Math.min(...e.map(e=>a.get(e.id).top));return a.forEach(e=>{e.left+=r-m,e.top+=s-y}),a}const g={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&&g[e.kind]?e.kind:"process"}(e),i=g[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 n=layeredLayout(e,t,{gapX:i,gapY:o});e.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)})}(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}}const m={pool:"bpmnPool",lane:"bpmnLane",task:"bpmnTask",event:"bpmnEvent",gateway:"bpmnGateway",subprocess:"bpmnSubprocess",dataObject:"bpmnDataObject",annotation:"bpmnAnnotation"},y=Number(e.bpmnPool.bandSize)||32,b=Number(e.bpmnLane.bandSize)||32,w=Number(e.bpmnLane.height)||130,v=Number(e.bpmnPool.width)||900;function toWorkingNode(t){const i=t.kind||"task",o=function presetOf(t){return e[t]||e.bpmnTask}(m[i]||"bpmnTask"),n={id:t.id,typeId:"FlowNode",kind:m[i]||"bpmnTask",title:t.title||t.name||t.id,left:"number"==typeof t.left?t.left:0,top:"number"==typeof t.top?t.top:0,width:"number"==typeof t.width?t.width:o.width,height:"number"==typeof t.height?t.height:o.height,fillColor:t.fillColor,strokeColor:t.strokeColor,dslKind:i,parent:t.parent,explicitLeft:"number"==typeof t.left,explicitTop:"number"==typeof t.top,explicitWidth:"number"==typeof t.width,explicitHeight:"number"==typeof t.height};return"event"===i&&(n.eventKind=t.eventKind||o.eventKind||"start",n.trigger=t.trigger||o.trigger||"none"),"gateway"===i&&(n.gatewayType=t.gatewayType||o.gatewayType||"exclusive"),"task"!==i&&"subprocess"!==i||(n.taskType=t.taskType||o.taskType||"none"),n}function buildGroups(e,t){const i=new Map;t.forEach(e=>i.set(e.id,e));const o=1===t.length?t[0]:null,n=[];return e.forEach(e=>{(e=>{let t=n.filter(t=>t.owner===e)[0];return t||(t={owner:e,nodes:[],box:null,didLayout:!1},n.push(t)),t})((e.parent?i.get(e.parent):void 0)||o).nodes.push(e)}),n}function layoutGroups(e,t,i,o){e.forEach(e=>{if(e.nodes.some(e=>!e.explicitLeft||!e.explicitTop)){const n=layeredLayout(e.nodes,t,{gapX:i,gapY:o,originX:0,originY:0,direction:"horizontal"});e.nodes.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)}),e.didLayout=!0}e.box=function unionBox(e){if(!e.length)return null;let t=1/0,i=1/0,o=-1/0,n=-1/0;return e.forEach(e=>{t=Math.min(t,e.left),i=Math.min(i,e.top),o=Math.max(o,e.left+e.width),n=Math.max(n,e.top+e.height)}),{minX:t,minY:i,maxX:o,maxY:n}}(e.nodes)})}function compileBpmnDsl(e){const t=e.options||{},i=(e.nodes||[]).map(toWorkingNode),o=i.filter(e=>"pool"===e.dslKind),n=i.filter(e=>"lane"===e.dslKind),r=i.filter(e=>!function isContainer(e){return"pool"===e.dslKind||"lane"===e.dslKind}(e)),s=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,flowType:e.type||e.flowType||"sequence",label:e.label||"",condition:e.condition||"",isDefault:!!e.isDefault,linkShape:e.linkShape||"visio"})),a=t.layout||"auto",l=function resolveLaneOwners(e,t){const i=new Map;return e.forEach(e=>{let o=e.parent;o||1!==t.length||(o=t[0].id),o&&i.set(e.id,o)}),i}(n,o),lanesOf=e=>n.filter(t=>l.get(t.id)===e);let d=[];"none"!==a&&(d=buildGroups(r,o.concat(n)),layoutGroups(d,s,Number(t.gapX)||90,Number(t.gapY)||60)),n.forEach(e=>{const t=d.filter(t=>t.owner===e)[0],i=t?t.box:null;e.explicitHeight||(e.height=Math.round(Math.max(56+(i?i.maxY-i.minY:0),w))),e.explicitWidth||(e.width=Math.round(Math.max((i?i.maxX-i.minX:0)+b+56,v)))}),o.forEach(e=>{const t=lanesOf(e.id);if(t.length){const i=t.reduce((e,t)=>Math.max(e,t.width),v);return e.explicitWidth||(e.width=i),e.explicitWidth&&t.forEach(t=>{t.explicitWidth||(t.width=e.width)}),void(e.explicitHeight||(e.height=y+t.reduce((e,t)=>e+t.height,0)))}const i=d.filter(t=>t.owner===e)[0],o=i?i.box:null;e.explicitWidth||(e.width=Math.round(Math.max(56+(o?o.maxX-o.minX:0),v))),e.explicitHeight||(e.height=Math.round(Math.max((o?o.maxY-o.minY:0)+y+56,160)))});let p=60;o.forEach(e=>{e.explicitLeft||(e.left=60),e.explicitTop||(e.top=p),p=Math.max(p,e.top+e.height+60)}),o.forEach(e=>{const t=lanesOf(e.id);if(!t.length)return;const i=e.top+y,o=Math.max(e.height-y,1),n=t.reduce((e,t)=>e+(t.explicitHeight?t.height:0),0),r=t.filter(e=>!e.explicitHeight),s=r.length?Math.max(o-n,0)/r.length:0;let a=i;t.forEach(t=>{t.explicitLeft||(t.left=e.left),t.explicitTop||(t.top=a),!t.explicitHeight&&e.explicitHeight&&(t.height=Math.round(s||w)),a=t.top+t.height})});let h=60;n.forEach(e=>{l.get(e.id)||(e.explicitLeft||(e.left=60),e.explicitTop||(e.top=h,h=e.top+e.height+60))}),d.forEach(e=>{const t=e.box;if(!t||!e.didLayout)return;const i=e.owner;let o=80,n=80;i&&(o=i.left+28,n=i.top+28,"pool"===i.dslKind?n+=y:o+=b),e.nodes.forEach(e=>{e.left=Math.round(o+(e.left-t.minX)),e.top=Math.round(n+(e.top-t.minY))})});return{kind:"bpmn",nodes:o.concat(n).concat(r).map(e=>{const t={id:e.id,typeId:"FlowNode",kind:e.kind,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};return void 0!==e.eventKind&&(t.eventKind=e.eventKind),void 0!==e.trigger&&(t.trigger=e.trigger),void 0!==e.gatewayType&&(t.gatewayType=e.gatewayType),void 0!==e.taskType&&(t.taskType=e.taskType),void 0!==e.fillColor&&(t.fillColor=e.fillColor),void 0!==e.strokeColor&&(t.strokeColor=e.strokeColor),t}),edges:s,layout:a,options:t}}function renderDsl(e,i){const o=validateDsl(i);if(!o.valid)throw new Error(o.errors.join("\n"));return isBpmnDsl(i)?renderBpmnDsl(e,i):isFlowDsl(i)?renderFlowDsl(e,i):function renderErDsl(e,i){const o=compileDsl(i),s=o.options||{},a=(new t).init(e),l=new n(a);o.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),n=o.get(e.targetId);let r="R",s="L";if(t&&n){const e=n.center[0]-t.center[0],i=n.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(r=e>=0?"R":"L",s=e>=0?"L":"R"):(r=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:r},end:{id:e.targetId,position:s}}}})}(l,o,s.routeType).forEach(e=>{l.createRelation(e)}),("layered"===o.layout||"horizontal"===o.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 n=1/0,r=1/0,s=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();n=Math.min(n,t.minX),r=Math.min(r,t.minY),s=Math.max(s,t.maxX),a=Math.max(a,t.maxY)});const l=s-n,d=a-r,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),g=Math.min(u/l,f/d,1),m=(p-l*g)/2-n*g,y=(h-d*g)/2-r*g;e.setViewport(g,m,y)}(a,l,s.fitViewportPadding);return{kind:"entity",ice:a,designer:l}}(e,i)}function renderBpmnDsl(e,o){const n=compileBpmnDsl(o),r=n.options||{},s=(new t).init(e),a=new i(s);return n.nodes.forEach(e=>{const t={id:e.id,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};["eventKind","trigger","gatewayType","taskType","fillColor","strokeColor"].forEach(i=>{void 0!==e[i]&&(t[i]=e[i])}),a.createNode(e.kind,t)}),n.edges.forEach(e=>{a.createEdge(e)}),a.select(null),r.viewport?s.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):!1!==r.fitViewport&&a.fitViewport(r.fitViewportPadding),a.resetHistory(),{kind:"bpmn",ice:s,designer:a}}function renderFlowDsl(e,i){const n=compileFlowDsl(i),r=n.options||{},s=(new t).init(e),a=new o(s);return n.nodes.forEach(e=>{a.createNode(e.kind,e)}),n.edges.forEach(e=>{a.createEdge(e)}),a.select(null),r.viewport?s.setViewport(r.viewport.scale,r.viewport.tx,r.viewport.ty):!1!==r.fitViewport&&a.fitViewport(r.fitViewportPadding),a.resetHistory(),{kind:"flowchart",ice:s,designer:a}}export{s as DSL_SCHEMA_VERSION,compileBpmnDsl,compileDsl,compileFlowDsl,isBpmnDsl,isFlowDsl,layeredLayout,renderBpmnDsl,renderDsl,renderFlowDsl,validateBpmnDsl,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 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
|
+
!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}function isBpmnDsl(e){return!!e&&"object"==typeof e&&"bpmn"===e.kind}const i=["terminator","process","decision","io"],o=["T","R","B","L","C"],n=["pool","lane","task","event","gateway","subprocess","dataObject","annotation"],r=["start","intermediate","end"],s=["none","message","timer","error","terminate"],a=["exclusive","parallel","inclusive","event"],l=["none","user","service","script","send","receive","manual"],d=["sequence","message","association"];function validateDsl(e){return isBpmnDsl(e)?validateBpmnDsl(e):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 n=`entities[${o}]`;e&&"object"==typeof e?("string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${n}.id is duplicated: ${e.id}`):i.add(e.id):t.push(n+".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(`${n}.fields[${i}].name must be a non-empty string`)}):t.push(n+".fields must be an array")):t.push(n+" 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 validateBpmnDsl(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,o=new Map;return Array.isArray(e.nodes)?(e.nodes.forEach((e,d)=>{const p=`nodes[${d}]`;if(!e||"object"!=typeof e)return void t.push(p+" must be an object");"string"==typeof e.id&&e.id.trim()?i.has(e.id)?t.push(`${p}.id is duplicated: ${e.id}`):(i.add(e.id),o.set(e.id,e.kind||"task")):t.push(p+".id must be a non-empty string"),void 0!==e.kind&&-1===n.indexOf(e.kind)&&t.push(`${p}.kind must be one of ${n.join("/")}`),["left","top","width","height"].forEach(i=>{const o=e[i];void 0!==o&&"number"!=typeof o&&t.push(`${p}.${i} must be a number when present`)});[["eventKind",r],["trigger",s],["gatewayType",a],["taskType",l]].forEach(([i,o])=>{const n=e[i];void 0!==n&&-1===o.indexOf(n)&&t.push(`${p}.${i} must be one of ${o.join("/")}`)})}),e.nodes.forEach((e,n)=>{if(!e||"object"!=typeof e||void 0===e.parent)return;const r=`nodes[${n}]`;if("string"!=typeof e.parent||!e.parent.trim())return void t.push(r+".parent must be a non-empty string when present");if(!i.has(e.parent))return void t.push(r+".parent must reference an existing node id");if(e.parent===e.id)return void t.push(r+".parent must not reference itself");const s=o.get(e.parent);"pool"===e.kind?t.push(r+".parent is not allowed on a pool (池是最外层容器)"):"lane"===e.kind&&"pool"!==s?t.push(r+".parent must reference a pool"):"pool"!==s&&"lane"!==s&&t.push(r+".parent must reference a pool or a lane")})):t.push("nodes must be an array"),void 0===e.edges||Array.isArray(e.edges)?(e.edges||[]).forEach((e,o)=>{const n=`edges[${o}]`;if(!e||"object"!=typeof e)return void t.push(n+" must be an object");"string"==typeof e.source&&e.source.trim()&&i.has(e.source)||t.push(n+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&i.has(e.target)||t.push(n+".target must reference an existing node id");const r=void 0!==e.type?e.type:e.flowType;void 0!==r&&-1===d.indexOf(r)&&t.push(`${n}.type must be one of ${d.join("/")}`),void 0!==e.label&&"string"!=typeof e.label&&t.push(n+".label must be a string when present"),void 0!==e.condition&&"string"!=typeof e.condition&&t.push(n+".condition must be a string when present"),void 0!==e.linkShape&&"visio"!==e.linkShape&&"bezier"!==e.linkShape&&t.push(n+'.linkShape must be "visio" or "bezier" when present')}):t.push("edges must be an array when present"),{valid:0===t.length,errors:t}}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 n=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()?n.has(e.id)?t.push(`${r}.id is duplicated: ${e.id}`):n.add(e.id):t.push(r+".id must be a non-empty string"),void 0!==e.kind&&-1===i.indexOf(e.kind)&&t.push(`${r}.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(`${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,i)=>{const r=`edges[${i}]`;e&&"object"==typeof e?("string"==typeof e.source&&e.source.trim()&&n.has(e.source)||t.push(r+".source must reference an existing node id"),"string"==typeof e.target&&e.target.trim()&&n.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===o.indexOf(e.sourcePort)&&t.push(`${r}.sourcePort must be one of ${o.join("/")}`),void 0!==e.targetPort&&-1===o.indexOf(e.targetPort)&&t.push(`${r}.targetPort must be one of ${o.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}}function layeredLayout(e,t,i={}){const o=Number(i.gapX)||90,n=Number(i.gapY)||90,r=void 0===i.originX?80:i.originX,s=void 0===i.originY?80:i.originY,a=new Map;if(!e.length)return a;const l=new Map;e.forEach(e=>l.set(e.id,e));const d=new Map,p=new Map;e.forEach(e=>{d.set(e.id,0),p.set(e.id,[])}),t.forEach(e=>{l.has(e.sourceId)&&l.has(e.targetId)&&(d.set(e.targetId,(d.get(e.targetId)||0)+1),p.get(e.sourceId).push(e.targetId))});const h=new Map,c=[];e.forEach(e=>{0===(d.get(e.id)||0)&&(h.set(e.id,0),c.push(e.id))}),c.length||(h.set(e[0].id,0),c.push(e[0].id));let u=e.length*e.length+e.length;for(;c.length&&u-- >0;){const e=c.shift(),t=h.get(e)||0;(p.get(e)||[]).forEach(e=>{const i=t+1;(void 0===h.get(e)?-1:h.get(e))<i&&(h.set(e,i),c.push(e))})}e.forEach(e=>{h.has(e.id)||h.set(e.id,0)});const f=new Map;e.forEach(e=>{const t=h.get(e.id)||0;f.has(t)||f.set(t,[]),f.get(t).push(e)});const m=[...f.keys()].sort((e,t)=>e-t);if("horizontal"===i.direction){const e=m.map(e=>Math.max(...f.get(e).map(e=>e.width)));let t=0;m.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.height,0)+Math.max(s.length-1,0)*n)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(t+(e[r]-i.width)/2),top:Math.round(l)}),l+=i.height+n}),t+=e[r]+o})}else{const e=m.map(e=>Math.max(...f.get(e).map(e=>e.height)));let t=0;m.forEach((i,r)=>{const s=f.get(i);let l=-(s.reduce((e,t)=>e+t.width,0)+Math.max(s.length-1,0)*o)/2;s.forEach(i=>{a.set(i.id,{left:Math.round(l),top:Math.round(t+(e[r]-i.height)/2)}),l+=i.width+o}),t+=e[r]+n})}const g=Math.min(...e.map(e=>a.get(e.id).left)),y=Math.min(...e.map(e=>a.get(e.id).top));return a.forEach(e=>{e.left+=r-g,e.top+=s-y}),a}const p={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&&p[e.kind]?e.kind:"process"}(e),i=p[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 n=layeredLayout(e,t,{gapX:i,gapY:o});e.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)})}(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}}const h={pool:"bpmnPool",lane:"bpmnLane",task:"bpmnTask",event:"bpmnEvent",gateway:"bpmnGateway",subprocess:"bpmnSubprocess",dataObject:"bpmnDataObject",annotation:"bpmnAnnotation"},c=Number(t.FLOW_NODE_KINDS.bpmnPool.bandSize)||32,u=Number(t.FLOW_NODE_KINDS.bpmnLane.bandSize)||32,f=Number(t.FLOW_NODE_KINDS.bpmnLane.height)||130,m=Number(t.FLOW_NODE_KINDS.bpmnPool.width)||900;function toWorkingNode(e){const i=e.kind||"task",o=function presetOf(e){return t.FLOW_NODE_KINDS[e]||t.FLOW_NODE_KINDS.bpmnTask}(h[i]||"bpmnTask"),n={id:e.id,typeId:"FlowNode",kind:h[i]||"bpmnTask",title:e.title||e.name||e.id,left:"number"==typeof e.left?e.left:0,top:"number"==typeof e.top?e.top:0,width:"number"==typeof e.width?e.width:o.width,height:"number"==typeof e.height?e.height:o.height,fillColor:e.fillColor,strokeColor:e.strokeColor,dslKind:i,parent:e.parent,explicitLeft:"number"==typeof e.left,explicitTop:"number"==typeof e.top,explicitWidth:"number"==typeof e.width,explicitHeight:"number"==typeof e.height};return"event"===i&&(n.eventKind=e.eventKind||o.eventKind||"start",n.trigger=e.trigger||o.trigger||"none"),"gateway"===i&&(n.gatewayType=e.gatewayType||o.gatewayType||"exclusive"),"task"!==i&&"subprocess"!==i||(n.taskType=e.taskType||o.taskType||"none"),n}function buildGroups(e,t){const i=new Map;t.forEach(e=>i.set(e.id,e));const o=1===t.length?t[0]:null,n=[];return e.forEach(e=>{(e=>{let t=n.filter(t=>t.owner===e)[0];return t||(t={owner:e,nodes:[],box:null,didLayout:!1},n.push(t)),t})((e.parent?i.get(e.parent):void 0)||o).nodes.push(e)}),n}function layoutGroups(e,t,i,o){e.forEach(e=>{if(e.nodes.some(e=>!e.explicitLeft||!e.explicitTop)){const n=layeredLayout(e.nodes,t,{gapX:i,gapY:o,originX:0,originY:0,direction:"horizontal"});e.nodes.forEach(e=>{const t=n.get(e.id);t&&(e.left=t.left,e.top=t.top)}),e.didLayout=!0}e.box=function unionBox(e){if(!e.length)return null;let t=1/0,i=1/0,o=-1/0,n=-1/0;return e.forEach(e=>{t=Math.min(t,e.left),i=Math.min(i,e.top),o=Math.max(o,e.left+e.width),n=Math.max(n,e.top+e.height)}),{minX:t,minY:i,maxX:o,maxY:n}}(e.nodes)})}function compileBpmnDsl(e){const t=e.options||{},i=(e.nodes||[]).map(toWorkingNode),o=i.filter(e=>"pool"===e.dslKind),n=i.filter(e=>"lane"===e.dslKind),r=i.filter(e=>!function isContainer(e){return"pool"===e.dslKind||"lane"===e.dslKind}(e)),s=(e.edges||[]).map((e,t)=>({id:e.id||"edge-"+t,sourceId:e.source,targetId:e.target,flowType:e.type||e.flowType||"sequence",label:e.label||"",condition:e.condition||"",isDefault:!!e.isDefault,linkShape:e.linkShape||"visio"})),a=t.layout||"auto",l=function resolveLaneOwners(e,t){const i=new Map;return e.forEach(e=>{let o=e.parent;o||1!==t.length||(o=t[0].id),o&&i.set(e.id,o)}),i}(n,o),lanesOf=e=>n.filter(t=>l.get(t.id)===e);let d=[];"none"!==a&&(d=buildGroups(r,o.concat(n)),layoutGroups(d,s,Number(t.gapX)||90,Number(t.gapY)||60)),n.forEach(e=>{const t=d.filter(t=>t.owner===e)[0],i=t?t.box:null;e.explicitHeight||(e.height=Math.round(Math.max(56+(i?i.maxY-i.minY:0),f))),e.explicitWidth||(e.width=Math.round(Math.max((i?i.maxX-i.minX:0)+u+56,m)))}),o.forEach(e=>{const t=lanesOf(e.id);if(t.length){const i=t.reduce((e,t)=>Math.max(e,t.width),m);return e.explicitWidth||(e.width=i),e.explicitWidth&&t.forEach(t=>{t.explicitWidth||(t.width=e.width)}),void(e.explicitHeight||(e.height=c+t.reduce((e,t)=>e+t.height,0)))}const i=d.filter(t=>t.owner===e)[0],o=i?i.box:null;e.explicitWidth||(e.width=Math.round(Math.max(56+(o?o.maxX-o.minX:0),m))),e.explicitHeight||(e.height=Math.round(Math.max((o?o.maxY-o.minY:0)+c+56,160)))});let p=60;o.forEach(e=>{e.explicitLeft||(e.left=60),e.explicitTop||(e.top=p),p=Math.max(p,e.top+e.height+60)}),o.forEach(e=>{const t=lanesOf(e.id);if(!t.length)return;const i=e.top+c,o=Math.max(e.height-c,1),n=t.reduce((e,t)=>e+(t.explicitHeight?t.height:0),0),r=t.filter(e=>!e.explicitHeight),s=r.length?Math.max(o-n,0)/r.length:0;let a=i;t.forEach(t=>{t.explicitLeft||(t.left=e.left),t.explicitTop||(t.top=a),!t.explicitHeight&&e.explicitHeight&&(t.height=Math.round(s||f)),a=t.top+t.height})});let h=60;n.forEach(e=>{l.get(e.id)||(e.explicitLeft||(e.left=60),e.explicitTop||(e.top=h,h=e.top+e.height+60))}),d.forEach(e=>{const t=e.box;if(!t||!e.didLayout)return;const i=e.owner;let o=80,n=80;i&&(o=i.left+28,n=i.top+28,"pool"===i.dslKind?n+=c:o+=u),e.nodes.forEach(e=>{e.left=Math.round(o+(e.left-t.minX)),e.top=Math.round(n+(e.top-t.minY))})});return{kind:"bpmn",nodes:o.concat(n).concat(r).map(e=>{const t={id:e.id,typeId:"FlowNode",kind:e.kind,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};return void 0!==e.eventKind&&(t.eventKind=e.eventKind),void 0!==e.trigger&&(t.trigger=e.trigger),void 0!==e.gatewayType&&(t.gatewayType=e.gatewayType),void 0!==e.taskType&&(t.taskType=e.taskType),void 0!==e.fillColor&&(t.fillColor=e.fillColor),void 0!==e.strokeColor&&(t.strokeColor=e.strokeColor),t}),edges:s,layout:a,options:t}}function renderBpmnDsl(e,i){const o=compileBpmnDsl(i),n=o.options||{},r=(new t.ICE).init(e),s=new t.BpmnDesigner(r);return o.nodes.forEach(e=>{const t={id:e.id,title:e.title,left:e.left,top:e.top,width:e.width,height:e.height};["eventKind","trigger","gatewayType","taskType","fillColor","strokeColor"].forEach(i=>{void 0!==e[i]&&(t[i]=e[i])}),s.createNode(e.kind,t)}),o.edges.forEach(e=>{s.createEdge(e)}),s.select(null),n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):!1!==n.fitViewport&&s.fitViewport(n.fitViewportPadding),s.resetHistory(),{kind:"bpmn",ice:r,designer:s}}function renderFlowDsl(e,i){const o=compileFlowDsl(i),n=o.options||{},r=(new t.ICE).init(e),s=new t.FlowDesigner(r);return o.nodes.forEach(e=>{s.createNode(e.kind,e)}),o.edges.forEach(e=>{s.createEdge(e)}),s.select(null),n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):!1!==n.fitViewport&&s.fitViewport(n.fitViewportPadding),s.resetHistory(),{kind:"flowchart",ice:r,designer:s}}e.DSL_SCHEMA_VERSION=1,e.compileBpmnDsl=compileBpmnDsl,e.compileDsl=compileDsl,e.compileFlowDsl=compileFlowDsl,e.isBpmnDsl=isBpmnDsl,e.isFlowDsl=isFlowDsl,e.layeredLayout=layeredLayout,e.renderBpmnDsl=renderBpmnDsl,e.renderDsl=function renderDsl(e,i){const o=validateDsl(i);if(!o.valid)throw new Error(o.errors.join("\n"));return isBpmnDsl(i)?renderBpmnDsl(e,i):isFlowDsl(i)?renderFlowDsl(e,i):function renderErDsl(e,i){const o=compileDsl(i),n=o.options||{},r=(new t.ICE).init(e),s=new t.EntityDesigner(r);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),n=o.get(e.targetId);let r="R",s="L";if(t&&n){const e=n.center[0]-t.center[0],i=n.center[1]-t.center[1];Math.abs(e)>Math.abs(i)?(r=e>=0?"R":"L",s=e>=0?"L":"R"):(r=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:r},end:{id:e.targetId,position:s}}}})}(s,o,n.routeType).forEach(e=>{s.createRelation(e)}),("layered"===o.layout||"horizontal"===o.layout)&&new t.ICELayeredLayout({gapX:n.gapX||120,gapY:n.gapY||50}).layoutContainer(r);n.viewport?r.setViewport(n.viewport.scale,n.viewport.tx,n.viewport.ty):n.fitViewport&&function fitViewport(e,t,i){const o=t.entities||[];let n=1/0,r=1/0,s=-1/0,a=-1/0;o.forEach(e=>{const t=e.getMinBoundingBox(!0).getMinAndMaxPoint();n=Math.min(n,t.minX),r=Math.min(r,t.minY),s=Math.max(s,t.maxX),a=Math.max(a,t.maxY)});const l=s-n,d=a-r,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-n*m,y=(h-d*m)/2-r*m;e.setViewport(m,g,y)}(r,s,n.fitViewportPadding);return{kind:"entity",ice:r,designer:s}}(e,i)},e.renderFlowDsl=renderFlowDsl,e.validateBpmnDsl=validateBpmnDsl,e.validateDsl=validateDsl,e.validateFlowDsl=validateFlowDsl,Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DslBpmnDocument } from '../types';
|
|
2
|
+
export declare type CompiledBpmnNode = {
|
|
3
|
+
id: string;
|
|
4
|
+
typeId: 'FlowNode';
|
|
5
|
+
/** ice-entity-designer 的 FlowNode kind(bpmn*) */
|
|
6
|
+
kind: string;
|
|
7
|
+
title: string;
|
|
8
|
+
left: number;
|
|
9
|
+
top: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
eventKind?: string;
|
|
13
|
+
trigger?: string;
|
|
14
|
+
gatewayType?: string;
|
|
15
|
+
taskType?: string;
|
|
16
|
+
fillColor?: string;
|
|
17
|
+
strokeColor?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare type CompiledBpmnEdge = {
|
|
20
|
+
id: string;
|
|
21
|
+
sourceId: string;
|
|
22
|
+
targetId: string;
|
|
23
|
+
flowType: string;
|
|
24
|
+
label: string;
|
|
25
|
+
condition: string;
|
|
26
|
+
isDefault: boolean;
|
|
27
|
+
linkShape: string;
|
|
28
|
+
};
|
|
29
|
+
export declare type CompiledBpmnScene = {
|
|
30
|
+
kind: 'bpmn';
|
|
31
|
+
nodes: CompiledBpmnNode[];
|
|
32
|
+
edges: CompiledBpmnEdge[];
|
|
33
|
+
layout: string;
|
|
34
|
+
options?: Record<string, any>;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* BPMN DSL → FlowNode / FlowEdge 构造参数。
|
|
38
|
+
*
|
|
39
|
+
* 与流程图同一套「节点 + 连线」语义,额外做两件事:
|
|
40
|
+
*
|
|
41
|
+
* 1. **容器内分层排布**:节点缺坐标时,按所属容器(`parent`)分组做分层布局(主干自左而右)。
|
|
42
|
+
* 2. **容器自适应内容**:没给几何的泳道按「内容包围盒 + 名称带 + 留白」定尺寸,没给几何的池
|
|
43
|
+
* 再按泳道们定尺寸,池之间纵向堆叠。**先排内容、再定尺寸、最后落位**,因此自动排出来的
|
|
44
|
+
* 图元一定落在所属容器的内容区里(否则会被 `BpmnDesigner` 按几何重新归属到别的容器)。
|
|
45
|
+
*
|
|
46
|
+
* 池名称带(顶部 32)与泳道名称带(左侧 32)都算在内容区之外,与 `BpmnDesigner` 的归属判定一致。
|
|
47
|
+
*
|
|
48
|
+
* 只要给了坐标(编辑器导出 / BPMN XML 导入的产物),编译过程就完全是恒等的,不做任何挪动。
|
|
49
|
+
*/
|
|
50
|
+
export declare function compileBpmnDsl(dsl: DslBpmnDocument): CompiledBpmnScene;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分层自动布局(流程图与 BPMN 共用)。
|
|
3
|
+
*
|
|
4
|
+
* 规则:无入边节点为第 0 层,其余节点取「前驱最大层 + 1」;同层按文档顺序横向排列,
|
|
5
|
+
* 层内垂直居中,层间距 gapY、同层间距 gapX。循环引用用小步数上限保护,
|
|
6
|
+
* 全环图以第一个节点为根 —— 保证任何输入都能给出**确定性**的坐标。
|
|
7
|
+
*
|
|
8
|
+
* 两个方向:`vertical`(默认,流程图)层自上而下、同层左右排开;
|
|
9
|
+
* `horizontal`(BPMN)层自左而右、同层上下排开。
|
|
10
|
+
*
|
|
11
|
+
* 返回的是 id → {left, top} 的映射,不改动入参;调用方决定写回哪里
|
|
12
|
+
* (流程图写到画布坐标,BPMN 写到所属容器的内容区)。
|
|
13
|
+
*/
|
|
14
|
+
export declare type LayoutItem = {
|
|
15
|
+
id: string;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
export declare type LayoutEdge = {
|
|
20
|
+
sourceId: string;
|
|
21
|
+
targetId: string;
|
|
22
|
+
};
|
|
23
|
+
export declare type LayoutOptions = {
|
|
24
|
+
gapX?: number;
|
|
25
|
+
gapY?: number;
|
|
26
|
+
/** 布局结果的左上角落点,默认 (80, 80) */
|
|
27
|
+
originX?: number;
|
|
28
|
+
originY?: number;
|
|
29
|
+
/**
|
|
30
|
+
* 主干方向:`vertical`(默认,流程图:层自上而下、同层左右排开)
|
|
31
|
+
* 或 `horizontal`(BPMN:层自左而右、同层上下排开)。
|
|
32
|
+
*/
|
|
33
|
+
direction?: 'vertical' | 'horizontal';
|
|
34
|
+
};
|
|
35
|
+
export declare function layeredLayout(items: LayoutItem[], edges: LayoutEdge[], options?: LayoutOptions): Map<string, {
|
|
36
|
+
left: number;
|
|
37
|
+
top: number;
|
|
38
|
+
}>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
export * from './types';
|
|
2
|
-
export { DSL_SCHEMA_VERSION, validateDsl, validateFlowDsl } from './validate';
|
|
2
|
+
export { DSL_SCHEMA_VERSION, validateDsl, validateFlowDsl, validateBpmnDsl } from './validate';
|
|
3
3
|
export { compileDsl } from './compiler/dslToScene';
|
|
4
4
|
export type { CompiledScene } from './compiler/dslToScene';
|
|
5
5
|
export { compileFlowDsl } from './compiler/flowToScene';
|
|
6
6
|
export type { CompiledFlowScene, CompiledFlowNode, CompiledFlowEdge } from './compiler/flowToScene';
|
|
7
|
-
export {
|
|
8
|
-
export type {
|
|
7
|
+
export { compileBpmnDsl } from './compiler/bpmnToScene';
|
|
8
|
+
export type { CompiledBpmnScene, CompiledBpmnNode, CompiledBpmnEdge } from './compiler/bpmnToScene';
|
|
9
|
+
export { layeredLayout } from './compiler/layout';
|
|
10
|
+
export type { LayoutItem, LayoutEdge, LayoutOptions } from './compiler/layout';
|
|
11
|
+
export { renderDsl, renderFlowDsl, renderBpmnDsl } from './runtime/renderDsl';
|
|
12
|
+
export type { RenderDslResult, RenderErDslResult, RenderFlowDslResult, RenderBpmnDslResult, } from './runtime/renderDsl';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DslDocument, DslFlowDocument } from '../types';
|
|
1
|
+
import type { DslBpmnDocument, DslDocument, DslFlowDocument } from '../types';
|
|
2
2
|
export declare type RenderErDslResult = {
|
|
3
3
|
kind: 'entity';
|
|
4
4
|
ice: any;
|
|
@@ -9,7 +9,12 @@ export declare type RenderFlowDslResult = {
|
|
|
9
9
|
ice: any;
|
|
10
10
|
designer: any;
|
|
11
11
|
};
|
|
12
|
-
export declare type
|
|
12
|
+
export declare type RenderBpmnDslResult = {
|
|
13
|
+
kind: 'bpmn';
|
|
14
|
+
ice: any;
|
|
15
|
+
designer: any;
|
|
16
|
+
};
|
|
17
|
+
export declare type RenderDslResult = RenderErDslResult | RenderFlowDslResult | RenderBpmnDslResult;
|
|
13
18
|
/**
|
|
14
19
|
* 渲染一份 DSL 文档:ER 文档(entities/relations)或流程图文档(kind: 'flowchart')。
|
|
15
20
|
*
|
|
@@ -17,5 +22,13 @@ export declare type RenderDslResult = RenderErDslResult | RenderFlowDslResult;
|
|
|
17
22
|
* `designer` 分别是 `EntityDesigner` / `FlowDesigner` 实例。
|
|
18
23
|
*/
|
|
19
24
|
export declare function renderDsl(canvasOrId: any, dsl: DslDocument): RenderDslResult;
|
|
25
|
+
/**
|
|
26
|
+
* 渲染 BPMN 文档:池/泳道也是节点(`parent` 声明归属),由 `BpmnDesigner` 按几何真嵌套,
|
|
27
|
+
* 因此拖动池/泳道时内部图元与挂在它们上面的连线会一起走(引擎的容器 + 递归 AFTER_MOVE)。
|
|
28
|
+
*
|
|
29
|
+
* 语义校验沿用编辑器那一套:`designer.validateBpmn()`;BPMN XML 互操作用
|
|
30
|
+
* `ice-entity-designer` 的 `toBpmnXml(designer)` / `fromBpmnXml(...)`。
|
|
31
|
+
*/
|
|
32
|
+
export declare function renderBpmnDsl(canvasOrId: any, dsl: DslBpmnDocument): RenderBpmnDslResult;
|
|
20
33
|
/** 渲染流程图文档:节点缺坐标时已由 compileFlowDsl 做过分层自动布局 */
|
|
21
34
|
export declare function renderFlowDsl(canvasOrId: any, dsl: DslFlowDocument): RenderFlowDslResult;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -117,11 +117,85 @@ export declare type DslFlowDocument = {
|
|
|
117
117
|
edges?: DslFlowEdge[];
|
|
118
118
|
options?: DslFlowDocumentOptions;
|
|
119
119
|
};
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
export declare type DslBpmnNodeKind = 'pool' | 'lane' | 'task' | 'event' | 'gateway' | 'subprocess' | 'dataObject' | 'annotation';
|
|
121
|
+
/** 事件种类 / 触发 / 网关 / 任务类型(取值与编辑器属性面板一致) */
|
|
122
|
+
export declare type DslBpmnEventKind = 'start' | 'intermediate' | 'end';
|
|
123
|
+
export declare type DslBpmnTrigger = 'none' | 'message' | 'timer' | 'error' | 'terminate';
|
|
124
|
+
export declare type DslBpmnGatewayType = 'exclusive' | 'parallel' | 'inclusive' | 'event';
|
|
125
|
+
export declare type DslBpmnTaskType = 'none' | 'user' | 'service' | 'script' | 'send' | 'receive' | 'manual';
|
|
126
|
+
/** 连线类型:sequence 顺序流 / message 消息流(跨池)/ association 关联(数据对象、注释) */
|
|
127
|
+
export declare type DslBpmnFlowType = 'sequence' | 'message' | 'association';
|
|
128
|
+
export declare type DslBpmnNode = {
|
|
129
|
+
id: string;
|
|
130
|
+
/** 节点类型,默认 task */
|
|
131
|
+
kind?: DslBpmnNodeKind;
|
|
132
|
+
/** 节点文字(title / name 二者取一,name 兼容 ER 文档写法) */
|
|
133
|
+
title?: string;
|
|
134
|
+
name?: string;
|
|
135
|
+
/**
|
|
136
|
+
* 归属容器:泳道写所属池的 id,流程节点写所属泳道(或池)的 id。
|
|
137
|
+
* 缺省时不报错 —— 有坐标的按坐标自动嵌套,没坐标的按「唯一的池」兜底并自动排布。
|
|
138
|
+
*/
|
|
139
|
+
parent?: string;
|
|
140
|
+
left?: number;
|
|
141
|
+
top?: number;
|
|
142
|
+
width?: number;
|
|
143
|
+
height?: number;
|
|
144
|
+
/** event 用 */
|
|
145
|
+
eventKind?: DslBpmnEventKind;
|
|
146
|
+
trigger?: DslBpmnTrigger;
|
|
147
|
+
/** gateway 用 */
|
|
148
|
+
gatewayType?: DslBpmnGatewayType;
|
|
149
|
+
/** task / subprocess 用 */
|
|
150
|
+
taskType?: DslBpmnTaskType;
|
|
151
|
+
fillColor?: string;
|
|
152
|
+
strokeColor?: string;
|
|
153
|
+
};
|
|
154
|
+
export declare type DslBpmnEdge = {
|
|
155
|
+
id?: string;
|
|
156
|
+
source: string;
|
|
157
|
+
target: string;
|
|
158
|
+
/** 连线类型,默认 sequence;message / association 才能跨池 */
|
|
159
|
+
type?: DslBpmnFlowType;
|
|
160
|
+
/** 兼容别名:与 type 等价(type 优先) */
|
|
161
|
+
flowType?: DslBpmnFlowType;
|
|
162
|
+
label?: string;
|
|
163
|
+
/** 顺序流的条件表达式(画在线上) */
|
|
164
|
+
condition?: string;
|
|
165
|
+
/** 默认流(画斜杠标记) */
|
|
166
|
+
isDefault?: boolean;
|
|
167
|
+
linkShape?: 'visio' | 'bezier';
|
|
168
|
+
};
|
|
169
|
+
export declare type DslBpmnDocumentOptions = {
|
|
170
|
+
/** 是否自动适应视图,默认 true */
|
|
171
|
+
fitViewport?: boolean;
|
|
172
|
+
fitViewportPadding?: number;
|
|
173
|
+
viewport?: {
|
|
174
|
+
scale: number;
|
|
175
|
+
tx: number;
|
|
176
|
+
ty: number;
|
|
177
|
+
};
|
|
178
|
+
/** 缺坐标时是否自动排布(分层 + 容器内落位),默认 auto */
|
|
179
|
+
layout?: 'auto' | 'none';
|
|
180
|
+
/** 自动排布的同层间距 */
|
|
181
|
+
gapX?: number;
|
|
182
|
+
/** 自动排布的层间距 */
|
|
183
|
+
gapY?: number;
|
|
184
|
+
};
|
|
185
|
+
export declare type DslBpmnDocument = {
|
|
186
|
+
schemaVersion?: number;
|
|
187
|
+
kind: 'bpmn';
|
|
188
|
+
nodes: DslBpmnNode[];
|
|
189
|
+
edges?: DslBpmnEdge[];
|
|
190
|
+
options?: DslBpmnDocumentOptions;
|
|
191
|
+
};
|
|
192
|
+
/** 一份 DSL 文档:ER(默认)、流程图(kind: 'flowchart')或 BPMN(kind: 'bpmn') */
|
|
193
|
+
export declare type DslDocument = DslErDocument | DslFlowDocument | DslBpmnDocument;
|
|
122
194
|
export declare type DslValidationResult = {
|
|
123
195
|
valid: boolean;
|
|
124
196
|
errors: string[];
|
|
125
197
|
};
|
|
126
198
|
/** 运行时判别:带 kind: 'flowchart' 的按流程图文档处理 */
|
|
127
199
|
export declare function isFlowDsl(dsl: any): dsl is DslFlowDocument;
|
|
200
|
+
/** 运行时判别:带 kind: 'bpmn' 的按 BPMN 文档处理 */
|
|
201
|
+
export declare function isBpmnDsl(dsl: any): dsl is DslBpmnDocument;
|
package/dist/types/validate.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import type { DslDocument, DslFlowDocument, DslValidationResult } from './types';
|
|
1
|
+
import type { DslBpmnDocument, DslDocument, DslFlowDocument, DslValidationResult } from './types';
|
|
2
2
|
export declare const DSL_SCHEMA_VERSION = 1;
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* 校验一份 DSL 文档:ER(entities/relations)、流程图(kind: 'flowchart')
|
|
5
|
+
* 或 BPMN(kind: 'bpmn',nodes/edges + 池/泳道容器)。
|
|
6
|
+
*/
|
|
4
7
|
export declare function validateDsl(dsl: DslDocument): DslValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* BPMN 文档校验:结构 + 取值词汇表 + 端点必须存在。
|
|
10
|
+
*
|
|
11
|
+
* 这里只做**结构**校验(离线可判定、错误信息稳定)。语义检查(每个池至少一个开始事件、
|
|
12
|
+
* 顺序流不得跨池、可达性等)交给 `BpmnDesigner.validateBpmn()` —— 那是同一套规则,
|
|
13
|
+
* 不要在 DSL 里再实现一遍。
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateBpmnDsl(dsl: DslBpmnDocument): DslValidationResult;
|
|
5
16
|
/** 流程图文档校验:结构 + 端点必须指向已存在的节点(与 ER 的关系校验同一口径) */
|
|
6
17
|
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.7",
|
|
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.22"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@babel/core": "7.17.8",
|