@bpmn-ld/bpmn-ld 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +125 -2
- package/contexts/combined.jsonld +3 -0
- package/contexts/core.jsonld +170 -0
- package/contexts/di.jsonld +37 -0
- package/dist/analyze/analyze.d.ts +3 -0
- package/dist/analyze/analyze.js +11 -0
- package/dist/analyze/findings.d.ts +8 -0
- package/dist/analyze/findings.js +1 -0
- package/dist/analyze/report.d.ts +3 -0
- package/dist/analyze/report.js +9 -0
- package/dist/analyze/rules/ad-hoc-completion-condition.d.ts +2 -0
- package/dist/analyze/rules/ad-hoc-completion-condition.js +7 -0
- package/dist/analyze/rules/cannot-reach-end.d.ts +2 -0
- package/dist/analyze/rules/cannot-reach-end.js +28 -0
- package/dist/analyze/rules/compensation-association.d.ts +2 -0
- package/dist/analyze/rules/compensation-association.js +13 -0
- package/dist/analyze/rules/dead-end.d.ts +2 -0
- package/dist/analyze/rules/dead-end.js +13 -0
- package/dist/analyze/rules/end-event.d.ts +2 -0
- package/dist/analyze/rules/end-event.js +8 -0
- package/dist/analyze/rules/error-catch.d.ts +2 -0
- package/dist/analyze/rules/error-catch.js +14 -0
- package/dist/analyze/rules/escalation-catch.d.ts +2 -0
- package/dist/analyze/rules/escalation-catch.js +14 -0
- package/dist/analyze/rules/gateway-cardinality.d.ts +3 -0
- package/dist/analyze/rules/gateway-cardinality.js +17 -0
- package/dist/analyze/rules/index.d.ts +4 -0
- package/dist/analyze/rules/index.js +21 -0
- package/dist/analyze/rules/instantiating-gateway.d.ts +2 -0
- package/dist/analyze/rules/instantiating-gateway.js +14 -0
- package/dist/analyze/rules/non-interrupting-start.d.ts +2 -0
- package/dist/analyze/rules/non-interrupting-start.js +14 -0
- package/dist/analyze/rules/reachability.d.ts +2 -0
- package/dist/analyze/rules/reachability.js +25 -0
- package/dist/analyze/rules/rule.d.ts +7 -0
- package/dist/analyze/rules/rule.js +1 -0
- package/dist/analyze/rules/signal-catch.d.ts +2 -0
- package/dist/analyze/rules/signal-catch.js +12 -0
- package/dist/analyze/rules/split-join-pairing.d.ts +3 -0
- package/dist/analyze/rules/split-join-pairing.js +50 -0
- package/dist/analyze/rules/start-event.d.ts +2 -0
- package/dist/analyze/rules/start-event.js +8 -0
- package/dist/analyze/rules/task-message-flow.d.ts +2 -0
- package/dist/analyze/rules/task-message-flow.js +19 -0
- package/dist/analyze/scope-graph.d.ts +56 -0
- package/dist/analyze/scope-graph.js +89 -0
- package/dist/analyze-cli.d.ts +1 -0
- package/dist/analyze-cli.js +5 -0
- package/dist/analyze-run.d.ts +12 -0
- package/dist/analyze-run.js +85 -0
- package/dist/bpmn-ld-cli.d.ts +1 -0
- package/dist/bpmn-ld-cli.js +90 -0
- package/dist/build-cli.d.ts +1 -0
- package/dist/build-cli.js +2 -0
- package/dist/build.d.ts +3 -0
- package/dist/build.js +38 -0
- package/dist/check-xml/check.d.ts +3 -0
- package/dist/check-xml/check.js +11 -0
- package/dist/check-xml/lint.d.ts +2 -0
- package/dist/check-xml/lint.js +47 -0
- package/dist/check-xml/moddle.d.ts +6 -0
- package/dist/check-xml/moddle.js +23 -0
- package/dist/check-xml/types.d.ts +20 -0
- package/dist/check-xml/types.js +1 -0
- package/dist/check-xml/xsd.d.ts +2 -0
- package/dist/check-xml/xsd.js +25 -0
- package/dist/check-xml-cli.d.ts +1 -0
- package/dist/check-xml-cli.js +5 -0
- package/dist/check-xml-run.d.ts +10 -0
- package/dist/check-xml-run.js +77 -0
- package/dist/convert/analyze-output.d.ts +3 -0
- package/dist/convert/analyze-output.js +8 -0
- package/dist/convert/convert.d.ts +19 -0
- package/dist/convert/convert.js +96 -0
- package/dist/convert/errors.d.ts +5 -0
- package/dist/convert/errors.js +8 -0
- package/dist/convert/extensions.d.ts +23 -0
- package/dist/convert/extensions.js +103 -0
- package/dist/convert/mapping-check.d.ts +15 -0
- package/dist/convert/mapping-check.js +66 -0
- package/dist/convert/mapping.d.ts +52 -0
- package/dist/convert/mapping.js +273 -0
- package/dist/convert/namespaces.d.ts +2 -0
- package/dist/convert/namespaces.js +19 -0
- package/dist/convert/validate-output.d.ts +2 -0
- package/dist/convert/validate-output.js +28 -0
- package/dist/convert/warnings.d.ts +9 -0
- package/dist/convert/warnings.js +67 -0
- package/dist/convert/xml-reader.d.ts +11 -0
- package/dist/convert/xml-reader.js +84 -0
- package/dist/convert-cli.d.ts +1 -0
- package/dist/convert-cli.js +5 -0
- package/dist/convert-run.d.ts +10 -0
- package/dist/convert-run.js +125 -0
- package/dist/coverage-cli.d.ts +1 -0
- package/dist/coverage-cli.js +8 -0
- package/dist/coverage-mappings.d.ts +3 -0
- package/dist/coverage-mappings.js +34 -0
- package/dist/coverage-scope.d.ts +11 -0
- package/dist/coverage-scope.js +187 -0
- package/dist/coverage-xsd.d.ts +15 -0
- package/dist/coverage-xsd.js +55 -0
- package/dist/coverage.d.ts +35 -0
- package/dist/coverage.js +152 -0
- package/dist/docs-cli.d.ts +1 -0
- package/dist/docs-cli.js +18 -0
- package/dist/docs.d.ts +8 -0
- package/dist/docs.js +136 -0
- package/dist/eval/checks.d.ts +19 -0
- package/dist/eval/checks.js +252 -0
- package/dist/eval/regenerate.d.ts +10 -0
- package/dist/eval/regenerate.js +48 -0
- package/dist/eval-regenerate-cli.d.ts +1 -0
- package/dist/eval-regenerate-cli.js +16 -0
- package/dist/export/data.d.ts +10 -0
- package/dist/export/data.js +127 -0
- package/dist/export/diagram.d.ts +8 -0
- package/dist/export/diagram.js +112 -0
- package/dist/export/element.d.ts +27 -0
- package/dist/export/element.js +175 -0
- package/dist/export/export.d.ts +22 -0
- package/dist/export/export.js +124 -0
- package/dist/export/extensions.d.ts +18 -0
- package/dist/export/extensions.js +122 -0
- package/dist/export/layout-export.d.ts +4 -0
- package/dist/export/layout-export.js +25 -0
- package/dist/export/mapping-check.d.ts +39 -0
- package/dist/export/mapping-check.js +175 -0
- package/dist/export/normalize.d.ts +3 -0
- package/dist/export/normalize.js +67 -0
- package/dist/export-cli.d.ts +1 -0
- package/dist/export-cli.js +5 -0
- package/dist/export-run.d.ts +10 -0
- package/dist/export-run.js +157 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/install-skill-run.d.ts +8 -0
- package/dist/install-skill-run.js +30 -0
- package/dist/install-skill.d.ts +23 -0
- package/dist/install-skill.js +76 -0
- package/dist/layout/collaboration.d.ts +36 -0
- package/dist/layout/collaboration.js +152 -0
- package/dist/layout/di.d.ts +15 -0
- package/dist/layout/di.js +52 -0
- package/dist/layout/extract.d.ts +2 -0
- package/dist/layout/extract.js +99 -0
- package/dist/layout/lanes.d.ts +30 -0
- package/dist/layout/lanes.js +112 -0
- package/dist/layout/layering.d.ts +7 -0
- package/dist/layout/layering.js +53 -0
- package/dist/layout/layout.d.ts +12 -0
- package/dist/layout/layout.js +299 -0
- package/dist/layout/model.d.ts +52 -0
- package/dist/layout/model.js +10 -0
- package/dist/layout/placement.d.ts +25 -0
- package/dist/layout/placement.js +256 -0
- package/dist/layout/standalone.d.ts +8 -0
- package/dist/layout/standalone.js +50 -0
- package/dist/layout-cli.d.ts +1 -0
- package/dist/layout-cli.js +5 -0
- package/dist/layout-run.d.ts +9 -0
- package/dist/layout-run.js +105 -0
- package/dist/loader.d.ts +5 -0
- package/dist/loader.js +7 -0
- package/dist/namespace.d.ts +5 -0
- package/dist/namespace.js +5 -0
- package/dist/ontology.d.ts +19 -0
- package/dist/ontology.js +94 -0
- package/dist/paths.d.ts +1 -0
- package/dist/paths.js +2 -0
- package/dist/render/geometry.d.ts +40 -0
- package/dist/render/geometry.js +81 -0
- package/dist/render/renderer.d.ts +31 -0
- package/dist/render/renderer.js +369 -0
- package/dist/render/symbols.d.ts +10 -0
- package/dist/render/symbols.js +26 -0
- package/dist/render/text.d.ts +20 -0
- package/dist/render/text.js +28 -0
- package/dist/render-cli.d.ts +1 -0
- package/dist/render-cli.js +7 -0
- package/dist/render-run.d.ts +9 -0
- package/dist/render-run.js +161 -0
- package/dist/render.d.ts +4 -0
- package/dist/render.js +4 -0
- package/dist/schema-overrides.d.ts +14 -0
- package/dist/schema-overrides.js +36 -0
- package/dist/schema-validate.d.ts +5 -0
- package/dist/schema-validate.js +8 -0
- package/dist/schema.d.ts +6 -0
- package/dist/schema.js +114 -0
- package/dist/shacl.d.ts +15 -0
- package/dist/shacl.js +37 -0
- package/dist/validate-cli.d.ts +1 -0
- package/dist/validate-cli.js +5 -0
- package/dist/validate-run.d.ts +8 -0
- package/dist/validate-run.js +58 -0
- package/dist/validate.d.ts +11 -0
- package/dist/validate.js +94 -0
- package/dist/versioning-cli.d.ts +1 -0
- package/dist/versioning-cli.js +18 -0
- package/dist/versioning.d.ts +17 -0
- package/dist/versioning.js +45 -0
- package/ontology/core.ttl +993 -0
- package/ontology/di.ttl +167 -0
- package/package.json +76 -4
- package/schema/bpmn-ld.schema.json +15230 -0
- package/shapes/core.shapes.ttl +398 -0
- package/skills/bpmn-ld/SKILL.md +154 -0
- package/skills/bpmn-ld/evals/models/order-approval-di.jsonld +296 -0
- package/skills/bpmn-ld/evals/models/refund-di.bpmn +82 -0
- package/skills/bpmn-ld/evals/models/refund.bpmn +18 -0
- package/skills/bpmn-ld/evals/outputs/explain-collaboration.md +22 -0
- package/skills/bpmn-ld/evals/outputs/explain-order-approval.md +24 -0
- package/skills/bpmn-ld/evals/outputs/explain-refund.md +17 -0
- package/skills/bpmn-ld/evals/outputs/generate-activity-compensation.jsonld +39 -0
- package/skills/bpmn-ld/evals/outputs/generate-ad-hoc-sub-process.jsonld +52 -0
- package/skills/bpmn-ld/evals/outputs/generate-boundary-event.jsonld +27 -0
- package/skills/bpmn-ld/evals/outputs/generate-collaboration.jsonld +49 -0
- package/skills/bpmn-ld/evals/outputs/generate-conditions.jsonld +93 -0
- package/skills/bpmn-ld/evals/outputs/generate-diagram-properties.jsonld +340 -0
- package/skills/bpmn-ld/evals/outputs/generate-error.jsonld +217 -0
- package/skills/bpmn-ld/evals/outputs/generate-escalation.jsonld +231 -0
- package/skills/bpmn-ld/evals/outputs/generate-event-definition-ref.jsonld +67 -0
- package/skills/bpmn-ld/evals/outputs/generate-event-sub-process.jsonld +54 -0
- package/skills/bpmn-ld/evals/outputs/generate-exclusive-choice.jsonld +32 -0
- package/skills/bpmn-ld/evals/outputs/generate-instantiating-gateway.jsonld +24 -0
- package/skills/bpmn-ld/evals/outputs/generate-lane-partition.jsonld +46 -0
- package/skills/bpmn-ld/evals/outputs/generate-link-event.expect.json +11 -0
- package/skills/bpmn-ld/evals/outputs/generate-link-event.jsonld +57 -0
- package/skills/bpmn-ld/evals/outputs/generate-loop.jsonld +30 -0
- package/skills/bpmn-ld/evals/outputs/generate-message.jsonld +61 -0
- package/skills/bpmn-ld/evals/outputs/generate-parallel-branches.jsonld +25 -0
- package/skills/bpmn-ld/evals/outputs/generate-process-attributes.jsonld +49 -0
- package/skills/bpmn-ld/evals/outputs/generate-script-task.jsonld +18 -0
- package/skills/bpmn-ld/evals/outputs/generate-signal.jsonld +178 -0
- package/skills/bpmn-ld/evals/outputs/generate-sub-process.jsonld +31 -0
- package/skills/bpmn-ld/evals/outputs/generate-targeted-compensation.jsonld +40 -0
- package/skills/bpmn-ld/evals/outputs/generate-task-implementation.jsonld +18 -0
- package/skills/bpmn-ld/evals/outputs/generate-task-message-references.jsonld +49 -0
- package/skills/bpmn-ld/evals/outputs/generate-transaction.jsonld +48 -0
- package/skills/bpmn-ld/evals/outputs/modify-order-approval.jsonld +376 -0
- package/skills/bpmn-ld/evals/outputs/modify-refund.jsonld +373 -0
- package/skills/bpmn-ld/evals/outputs/order-approval.jsonld +29 -0
- package/skills/bpmn-ld/evals/outputs/refine-order-approval.jsonld +377 -0
- package/skills/bpmn-ld/evals/prompts/explain-collaboration.md +3 -0
- package/skills/bpmn-ld/evals/prompts/explain-order-approval.md +3 -0
- package/skills/bpmn-ld/evals/prompts/explain-refund.md +3 -0
- package/skills/bpmn-ld/evals/prompts/generate-activity-compensation.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-ad-hoc-sub-process.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-boundary-event.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-collaboration.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-conditions.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-diagram-properties.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-error.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-escalation.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-event-definition-ref.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-event-sub-process.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-exclusive-choice.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-instantiating-gateway.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-lane-partition.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-link-event.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-loop.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-message.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-parallel-branches.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-process-attributes.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-script-task.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-signal.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-sub-process.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-targeted-compensation.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-task-implementation.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-task-message-references.md +1 -0
- package/skills/bpmn-ld/evals/prompts/generate-transaction.md +1 -0
- package/skills/bpmn-ld/evals/prompts/modify-order-approval.md +4 -0
- package/skills/bpmn-ld/evals/prompts/modify-refund.md +4 -0
- package/skills/bpmn-ld/evals/prompts/order-approval.md +1 -0
- package/skills/bpmn-ld/evals/prompts/refine-order-approval.md +8 -0
- package/skills/bpmn-ld/examples/positive/activity-compensation.jsonld +39 -0
- package/skills/bpmn-ld/examples/positive/ad-hoc-sub-process.jsonld +52 -0
- package/skills/bpmn-ld/examples/positive/boundary-event.jsonld +27 -0
- package/skills/bpmn-ld/examples/positive/collaboration.jsonld +49 -0
- package/skills/bpmn-ld/examples/positive/conditions.jsonld +93 -0
- package/skills/bpmn-ld/examples/positive/diagram-properties.jsonld +340 -0
- package/skills/bpmn-ld/examples/positive/error.jsonld +208 -0
- package/skills/bpmn-ld/examples/positive/escalation.jsonld +231 -0
- package/skills/bpmn-ld/examples/positive/event-definition-ref.jsonld +142 -0
- package/skills/bpmn-ld/examples/positive/event-sub-process.jsonld +54 -0
- package/skills/bpmn-ld/examples/positive/exclusive-choice.jsonld +32 -0
- package/skills/bpmn-ld/examples/positive/instantiating-gateway.jsonld +24 -0
- package/skills/bpmn-ld/examples/positive/lane-partition.jsonld +46 -0
- package/skills/bpmn-ld/examples/positive/link-event.expect.json +10 -0
- package/skills/bpmn-ld/examples/positive/link-event.jsonld +138 -0
- package/skills/bpmn-ld/examples/positive/loop.jsonld +30 -0
- package/skills/bpmn-ld/examples/positive/message.jsonld +60 -0
- package/skills/bpmn-ld/examples/positive/order-approval.jsonld +29 -0
- package/skills/bpmn-ld/examples/positive/parallel-branches.jsonld +25 -0
- package/skills/bpmn-ld/examples/positive/process-attributes.jsonld +49 -0
- package/skills/bpmn-ld/examples/positive/script-task.jsonld +18 -0
- package/skills/bpmn-ld/examples/positive/signal.jsonld +150 -0
- package/skills/bpmn-ld/examples/positive/sub-process.jsonld +31 -0
- package/skills/bpmn-ld/examples/positive/targeted-compensation.jsonld +40 -0
- package/skills/bpmn-ld/examples/positive/task-implementation.jsonld +18 -0
- package/skills/bpmn-ld/examples/positive/task-message-references.jsonld +151 -0
- package/skills/bpmn-ld/examples/positive/transaction.jsonld +48 -0
- package/skills/bpmn-ld/references/clarification-and-refinement.md +60 -0
- package/skills/bpmn-ld/references/common-mistakes.md +110 -0
- package/skills/bpmn-ld/references/explain-and-document.md +36 -0
- package/skills/bpmn-ld/references/modify-existing-model.md +49 -0
- package/skills/bpmn-ld/references/patterns.md +292 -0
- package/skills/bpmn-ld/references/render-output.md +1 -0
- package/skills/bpmn-ld/references/rule-catalogue.md +183 -0
- package/skills/bpmn-ld/references/vocabulary-summary.md +65 -0
- package/skills/bpmn-ld/template.jsonld +14 -0
- package/templates/combined.jsonld +3 -0
- package/templates/core.jsonld +170 -0
- package/templates/core.shapes.ttl +398 -0
- package/templates/core.ttl +993 -0
- package/templates/di.jsonld +37 -0
- package/templates/di.ttl +167 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isObject } from "./element.js";
|
|
2
|
+
const RESERVED_PREFIXES = ["xml", "xmlns", "xsi", "dc", "di", "bpmndi"];
|
|
3
|
+
const ABSOLUTE = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
4
|
+
const ABSOLUTE_KEY = /^(?:[A-Za-z][A-Za-z0-9+.-]*:\/\/|urn:)/i;
|
|
5
|
+
const splitIri = (iri) => {
|
|
6
|
+
const cut = Math.max(iri.lastIndexOf("#"), iri.lastIndexOf("/"), iri.lastIndexOf(":")) + 1;
|
|
7
|
+
return { namespace: iri.slice(0, cut), local: iri.slice(cut) };
|
|
8
|
+
};
|
|
9
|
+
const isScalar = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
10
|
+
export class Extensions {
|
|
11
|
+
namespaces = new Map();
|
|
12
|
+
terms = new Map();
|
|
13
|
+
references = new Set();
|
|
14
|
+
base;
|
|
15
|
+
byNamespace = new Map();
|
|
16
|
+
generated = 0;
|
|
17
|
+
constructor(context, base) {
|
|
18
|
+
this.base = base;
|
|
19
|
+
const entries = Array.isArray(context) ? context : [context];
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
if (!isObject(entry))
|
|
22
|
+
continue;
|
|
23
|
+
for (const [term, definition] of Object.entries(entry)) {
|
|
24
|
+
if (term.startsWith("@"))
|
|
25
|
+
continue;
|
|
26
|
+
if (typeof definition === "string")
|
|
27
|
+
this.terms.set(term, definition);
|
|
28
|
+
else if (isObject(definition) && typeof definition["@id"] === "string") {
|
|
29
|
+
this.terms.set(term, definition["@id"]);
|
|
30
|
+
if (definition["@type"] === "@id")
|
|
31
|
+
this.references.add(term);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
expand(key, viaTerm = true) {
|
|
37
|
+
const colon = key.indexOf(":");
|
|
38
|
+
if (colon > 0) {
|
|
39
|
+
const prefix = key.slice(0, colon);
|
|
40
|
+
const namespace = this.terms.get(prefix);
|
|
41
|
+
if (namespace !== undefined && ABSOLUTE.test(namespace) && !key.startsWith(`${prefix}://`)) {
|
|
42
|
+
return { namespace, local: key.slice(colon + 1), preferred: prefix };
|
|
43
|
+
}
|
|
44
|
+
return ABSOLUTE_KEY.test(key) ? splitIri(key) : undefined;
|
|
45
|
+
}
|
|
46
|
+
const target = this.terms.get(key);
|
|
47
|
+
if (viaTerm && target !== undefined && target !== key)
|
|
48
|
+
return this.expand(target, false);
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
prefixFor(resolved) {
|
|
52
|
+
const known = this.byNamespace.get(resolved.namespace);
|
|
53
|
+
if (known !== undefined)
|
|
54
|
+
return known;
|
|
55
|
+
let prefix = resolved.preferred;
|
|
56
|
+
if (prefix === undefined || RESERVED_PREFIXES.includes(prefix) || this.namespaces.has(prefix)) {
|
|
57
|
+
do
|
|
58
|
+
prefix = `ns${++this.generated}`;
|
|
59
|
+
while (this.namespaces.has(prefix) || this.terms.has(prefix));
|
|
60
|
+
}
|
|
61
|
+
this.namespaces.set(prefix, resolved.namespace);
|
|
62
|
+
this.byNamespace.set(resolved.namespace, prefix);
|
|
63
|
+
return prefix;
|
|
64
|
+
}
|
|
65
|
+
qualify(key) {
|
|
66
|
+
const resolved = this.expand(key);
|
|
67
|
+
if (resolved === undefined || resolved.local === "")
|
|
68
|
+
return undefined;
|
|
69
|
+
return `${this.prefixFor(resolved)}:${resolved.local}`;
|
|
70
|
+
}
|
|
71
|
+
content(value) {
|
|
72
|
+
if (isScalar(value))
|
|
73
|
+
return String(value);
|
|
74
|
+
if (!isObject(value))
|
|
75
|
+
return undefined;
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [key, member] of Object.entries(value).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
78
|
+
const name = this.qualify(key);
|
|
79
|
+
if (name === undefined)
|
|
80
|
+
continue;
|
|
81
|
+
const items = (Array.isArray(member) ? member : [member]).map((item) => this.content(item)).filter((item) => item !== undefined);
|
|
82
|
+
if (items.length > 0)
|
|
83
|
+
result[name] = items;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
resolve(reference) {
|
|
88
|
+
try {
|
|
89
|
+
return new URL(reference, this.base).href;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return reference;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
scalar(key, value) {
|
|
96
|
+
const reference = isObject(value) && Object.keys(value).length === 1 && typeof value.id === "string" ? value.id : value;
|
|
97
|
+
if (!isScalar(reference))
|
|
98
|
+
return undefined;
|
|
99
|
+
return typeof reference === "string" && this.references.has(key) ? this.resolve(reference) : String(reference);
|
|
100
|
+
}
|
|
101
|
+
attribute(key, value, element) {
|
|
102
|
+
const name = this.qualify(key);
|
|
103
|
+
const text = this.scalar(key, value);
|
|
104
|
+
if (name === undefined || text === undefined)
|
|
105
|
+
return false;
|
|
106
|
+
element[`@_${name}`] = text;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
apply(key, value, element) {
|
|
110
|
+
const name = this.qualify(key);
|
|
111
|
+
if (name === undefined)
|
|
112
|
+
return false;
|
|
113
|
+
if (this.attribute(key, value, element))
|
|
114
|
+
return true;
|
|
115
|
+
const items = (Array.isArray(value) ? value : [value]).map((item) => this.content(item)).filter((item) => item !== undefined);
|
|
116
|
+
if (items.length === 0)
|
|
117
|
+
return true;
|
|
118
|
+
const container = (element.extensionElements ??= {});
|
|
119
|
+
container[name] = [...(container[name] ?? []), ...items];
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type LayoutOptions } from "../layout/layout.ts";
|
|
2
|
+
import { type ExportOptions, type ExportResult } from "./export.ts";
|
|
3
|
+
export type LayoutAndExportOptions = ExportOptions & LayoutOptions;
|
|
4
|
+
export declare const layoutAndExport: (input: unknown, options?: LayoutAndExportOptions) => Promise<ExportResult>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { layoutDocument, LayoutInputError } from "../layout/layout.js";
|
|
2
|
+
import { exportDocument, ExportInputError, schemaFinding } from "./export.js";
|
|
3
|
+
import { isObject } from "./element.js";
|
|
4
|
+
import { normalize } from "./normalize.js";
|
|
5
|
+
export const layoutAndExport = async (input, options = {}) => {
|
|
6
|
+
if (!isObject(input))
|
|
7
|
+
return exportDocument(input, options);
|
|
8
|
+
let document;
|
|
9
|
+
try {
|
|
10
|
+
document = await normalize(input, options.documentUrl);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
throw new ExportInputError([{ code: "invalid-context", location: "/@context", message: error.message }]);
|
|
14
|
+
}
|
|
15
|
+
let laidOut;
|
|
16
|
+
try {
|
|
17
|
+
laidOut = layoutDocument(document, { force: options.force }).document;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error instanceof LayoutInputError)
|
|
21
|
+
throw new ExportInputError(error.errors.map(schemaFinding));
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
return exportDocument(laidOut, { documentUrl: options.documentUrl });
|
|
25
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Store } from "n3";
|
|
2
|
+
import { type ElementMapping } from "../convert/mapping.ts";
|
|
3
|
+
export interface ConverterTables {
|
|
4
|
+
elements: Record<string, ElementMapping>;
|
|
5
|
+
containment: Record<string, Record<string, string>>;
|
|
6
|
+
roots: string[];
|
|
7
|
+
diagramElements: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface ExporterTables {
|
|
10
|
+
elements: Record<string, ElementMapping>;
|
|
11
|
+
containment: Record<string, Record<string, string>>;
|
|
12
|
+
supported: Record<string, string[]>;
|
|
13
|
+
diagram: Record<string, {
|
|
14
|
+
attributes: string[];
|
|
15
|
+
children: string[];
|
|
16
|
+
}>;
|
|
17
|
+
roots: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface AllowedDifference {
|
|
20
|
+
where: string;
|
|
21
|
+
reason: string;
|
|
22
|
+
}
|
|
23
|
+
export type ExportMappingReason = "not-in-context" | "not-in-ontology" | "not-exported" | "export-only" | "term-mismatch" | "type-mismatch" | "not-supported" | "stale-allowance";
|
|
24
|
+
export interface ExportMappingProblem {
|
|
25
|
+
where: string;
|
|
26
|
+
reason: ExportMappingReason;
|
|
27
|
+
detail: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ExportMappingInput {
|
|
30
|
+
exporter: ExporterTables;
|
|
31
|
+
converter: ConverterTables;
|
|
32
|
+
store: Store;
|
|
33
|
+
context: Record<string, string>;
|
|
34
|
+
allowed?: AllowedDifference[];
|
|
35
|
+
}
|
|
36
|
+
export declare const converterTables: () => ConverterTables;
|
|
37
|
+
export declare const exporterTables: () => ExporterTables;
|
|
38
|
+
export declare const ALLOWED_DIFFERENCES: AllowedDifference[];
|
|
39
|
+
export declare const checkExportMapping: ({ exporter, converter, store, context, allowed }: ExportMappingInput) => ExportMappingProblem[];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { declaredClasses, declaredProperties } from "../ontology.js";
|
|
2
|
+
import { CONTAINMENT, ELEMENT_MAPPINGS, ELEMENT_NAMESPACES, ROOT_ELEMENTS as CONVERTER_ROOTS } from "../convert/mapping.js";
|
|
3
|
+
import { DIAGRAM_EXPORT } from "./diagram.js";
|
|
4
|
+
import { SUPPORTED_ELEMENTS } from "./element.js";
|
|
5
|
+
import { CONTAINS, MAPPINGS } from "./data.js";
|
|
6
|
+
import { ROOT_ELEMENTS as EXPORT_ROOT_TYPES } from "./export.js";
|
|
7
|
+
export const converterTables = () => ({
|
|
8
|
+
elements: ELEMENT_MAPPINGS,
|
|
9
|
+
containment: CONTAINMENT,
|
|
10
|
+
roots: CONVERTER_ROOTS,
|
|
11
|
+
diagramElements: Object.keys(ELEMENT_NAMESPACES),
|
|
12
|
+
});
|
|
13
|
+
export const exporterTables = () => ({
|
|
14
|
+
elements: MAPPINGS,
|
|
15
|
+
containment: CONTAINS,
|
|
16
|
+
supported: SUPPORTED_ELEMENTS,
|
|
17
|
+
diagram: DIAGRAM_EXPORT,
|
|
18
|
+
roots: [...Object.values(EXPORT_ROOT_TYPES), "BPMNDiagram"],
|
|
19
|
+
});
|
|
20
|
+
const DATA_ELEMENTS = [
|
|
21
|
+
"dataObject",
|
|
22
|
+
"dataObjectReference",
|
|
23
|
+
"dataStore",
|
|
24
|
+
"dataStoreReference",
|
|
25
|
+
"dataInput",
|
|
26
|
+
"dataOutput",
|
|
27
|
+
"inputSet",
|
|
28
|
+
"outputSet",
|
|
29
|
+
"ioSpecification",
|
|
30
|
+
"dataInputAssociation",
|
|
31
|
+
"dataOutputAssociation",
|
|
32
|
+
"assignment",
|
|
33
|
+
"transformation",
|
|
34
|
+
"from",
|
|
35
|
+
"to",
|
|
36
|
+
];
|
|
37
|
+
const dataReason = "data constructs are exported but the converter does not read them yet";
|
|
38
|
+
export const ALLOWED_DIFFERENCES = [
|
|
39
|
+
...DATA_ELEMENTS.map((name) => ({ where: name, reason: dataReason })),
|
|
40
|
+
{ where: "roots.dataStore", reason: dataReason },
|
|
41
|
+
{ where: "*.singles.ioSpecification", reason: "activities carry an ioSpecification only on export" },
|
|
42
|
+
{ where: "containment.*.data*", reason: "data containment is export-only" },
|
|
43
|
+
{ where: "containment.*.inputSet", reason: "data containment is export-only" },
|
|
44
|
+
{ where: "containment.*.outputSet", reason: "data containment is export-only" },
|
|
45
|
+
{ where: "containment.*.assignment", reason: "data containment is export-only" },
|
|
46
|
+
];
|
|
47
|
+
const flatten = (mapping) => {
|
|
48
|
+
const paths = new Map();
|
|
49
|
+
paths.set("type", mapping.type);
|
|
50
|
+
for (const [attribute, term] of Object.entries(mapping.attributes))
|
|
51
|
+
paths.set(`attributes.${attribute}`, term);
|
|
52
|
+
for (const field of ["singles", "textChildren", "textLists"]) {
|
|
53
|
+
for (const [child, term] of Object.entries(mapping[field] ?? {}))
|
|
54
|
+
paths.set(`${field}.${child}`, term);
|
|
55
|
+
}
|
|
56
|
+
for (const lookup of mapping.lookups ?? [])
|
|
57
|
+
paths.set(`lookups.${lookup.attribute}`, lookup.term);
|
|
58
|
+
for (const term of mapping.booleans ?? [])
|
|
59
|
+
paths.set(`booleans.${term}`, term);
|
|
60
|
+
for (const term of mapping.numbers ?? [])
|
|
61
|
+
paths.set(`numbers.${term}`, term);
|
|
62
|
+
if (mapping.bodyTerm !== undefined)
|
|
63
|
+
paths.set("bodyTerm", mapping.bodyTerm);
|
|
64
|
+
return paths;
|
|
65
|
+
};
|
|
66
|
+
const containmentPaths = (containment) => {
|
|
67
|
+
const paths = new Map();
|
|
68
|
+
for (const [parent, children] of Object.entries(containment)) {
|
|
69
|
+
for (const [child, term] of Object.entries(children))
|
|
70
|
+
paths.set(`containment.${parent}.${child}`, term);
|
|
71
|
+
}
|
|
72
|
+
return paths;
|
|
73
|
+
};
|
|
74
|
+
const diagramPaths = (names, terms) => {
|
|
75
|
+
const paths = new Map();
|
|
76
|
+
for (const name of names)
|
|
77
|
+
for (const term of terms(name))
|
|
78
|
+
paths.set(`diagram.${name}.${term}`, term);
|
|
79
|
+
return paths;
|
|
80
|
+
};
|
|
81
|
+
const converterDiagram = (converter) => diagramPaths(converter.diagramElements, (name) => {
|
|
82
|
+
const mapping = converter.elements[name];
|
|
83
|
+
const flat = [...flatten(mapping)].filter(([path]) => path !== "type").map(([, term]) => term);
|
|
84
|
+
const contained = Object.values(converter.containment[name] ?? {});
|
|
85
|
+
return [...flat, ...contained];
|
|
86
|
+
});
|
|
87
|
+
const exporterDiagram = (exporter) => diagramPaths(Object.keys(exporter.diagram), (name) => [...exporter.diagram[name].attributes, ...exporter.diagram[name].children]);
|
|
88
|
+
const compare = (where, converterPaths, exporterPaths, problems) => {
|
|
89
|
+
for (const [path, term] of converterPaths) {
|
|
90
|
+
const prefix = where === "" ? "" : `${where}.`;
|
|
91
|
+
const exported = exporterPaths.get(path);
|
|
92
|
+
if (exported === undefined)
|
|
93
|
+
problems.push({ where: `${prefix}${path}`, reason: "not-exported", detail: `converter maps ${path} to ${term}` });
|
|
94
|
+
else if (exported !== term)
|
|
95
|
+
problems.push({ where: `${prefix}${path}`, reason: "term-mismatch", detail: `converter ${term}, exporter ${exported}` });
|
|
96
|
+
}
|
|
97
|
+
for (const [path, term] of exporterPaths) {
|
|
98
|
+
if (!converterPaths.has(path))
|
|
99
|
+
problems.push({ where: `${where === "" ? "" : `${where}.`}${path}`, reason: "export-only", detail: `exporter maps ${path} to ${term}` });
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const ontologyProblems = (exporter, store, context) => {
|
|
103
|
+
const classes = declaredClasses(store);
|
|
104
|
+
const properties = declaredProperties(store);
|
|
105
|
+
const problems = [];
|
|
106
|
+
const check = (term, kind, where) => {
|
|
107
|
+
const iri = context[term];
|
|
108
|
+
if (iri === undefined)
|
|
109
|
+
problems.push({ where, reason: "not-in-context", detail: term });
|
|
110
|
+
else if (!(kind === "class" ? classes : properties).has(iri))
|
|
111
|
+
problems.push({ where, reason: "not-in-ontology", detail: term });
|
|
112
|
+
};
|
|
113
|
+
for (const [element, mapping] of Object.entries(exporter.elements)) {
|
|
114
|
+
for (const [path, term] of flatten(mapping)) {
|
|
115
|
+
if (path === "attributes.id")
|
|
116
|
+
continue;
|
|
117
|
+
check(term, path === "type" ? "class" : "property", `${element}.${path}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const [path, term] of containmentPaths(exporter.containment))
|
|
121
|
+
check(term, "property", path);
|
|
122
|
+
for (const [path, term] of exporterDiagram(exporter))
|
|
123
|
+
if (!path.endsWith(".id"))
|
|
124
|
+
check(term, "property", path);
|
|
125
|
+
return problems;
|
|
126
|
+
};
|
|
127
|
+
const matches = (pattern, where) => new RegExp(`^${pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`).test(where);
|
|
128
|
+
export const checkExportMapping = ({ exporter, converter, store, context, allowed = ALLOWED_DIFFERENCES }) => {
|
|
129
|
+
const problems = ontologyProblems(exporter, store, context);
|
|
130
|
+
for (const [element, mapping] of Object.entries(converter.elements)) {
|
|
131
|
+
const exported = exporter.elements[element];
|
|
132
|
+
if (exported === undefined) {
|
|
133
|
+
problems.push({ where: element, reason: "not-exported", detail: `converter element ${element} has no exporter mapping` });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
compare(element, flatten(mapping), flatten(exported), problems);
|
|
137
|
+
}
|
|
138
|
+
for (const element of Object.keys(exporter.elements)) {
|
|
139
|
+
if (!(element in converter.elements))
|
|
140
|
+
problems.push({ where: element, reason: "export-only", detail: `exporter element ${element} is not read by the converter` });
|
|
141
|
+
}
|
|
142
|
+
compare("", containmentPaths(converter.containment), containmentPaths(exporter.containment), problems);
|
|
143
|
+
compare("", converterDiagram(converter), exporterDiagram(exporter), problems);
|
|
144
|
+
for (const [parent, children] of Object.entries(converter.containment)) {
|
|
145
|
+
if (converter.diagramElements.includes(parent))
|
|
146
|
+
continue;
|
|
147
|
+
for (const child of Object.keys(children)) {
|
|
148
|
+
if (!(exporter.supported[parent] ?? []).includes(child)) {
|
|
149
|
+
problems.push({ where: `supported.${parent}.${child}`, reason: "not-supported", detail: `exporter does not export ${child} inside ${parent}` });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const root of converter.roots) {
|
|
154
|
+
if (!exporter.roots.includes(root))
|
|
155
|
+
problems.push({ where: `roots.${root}`, reason: "not-exported", detail: `converter root ${root} is not exported` });
|
|
156
|
+
}
|
|
157
|
+
for (const root of exporter.roots) {
|
|
158
|
+
if (!converter.roots.includes(root))
|
|
159
|
+
problems.push({ where: `roots.${root}`, reason: "export-only", detail: `exporter root ${root} is not read by the converter` });
|
|
160
|
+
}
|
|
161
|
+
const used = new Set();
|
|
162
|
+
const remaining = problems.filter((problem) => {
|
|
163
|
+
if (problem.reason !== "export-only")
|
|
164
|
+
return true;
|
|
165
|
+
const allowance = allowed.find((entry) => matches(entry.where, problem.where));
|
|
166
|
+
if (allowance !== undefined)
|
|
167
|
+
used.add(allowance);
|
|
168
|
+
return allowance === undefined;
|
|
169
|
+
});
|
|
170
|
+
for (const entry of allowed) {
|
|
171
|
+
if (!used.has(entry))
|
|
172
|
+
remaining.push({ where: entry.where, reason: "stale-allowance", detail: entry.reason });
|
|
173
|
+
}
|
|
174
|
+
return remaining;
|
|
175
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import jsonld from "jsonld";
|
|
4
|
+
import { COMBINED_CONTEXT_IRI, defaultBase } from "../convert/convert.js";
|
|
5
|
+
import { fileDocumentLoader } from "../loader.js";
|
|
6
|
+
import { ROOT } from "../paths.js";
|
|
7
|
+
import { isObject } from "./element.js";
|
|
8
|
+
const loader = async (url) => fileDocumentLoader(url === COMBINED_CONTEXT_IRI ? pathToFileURL(join(ROOT, "contexts/combined.jsonld")).href : url);
|
|
9
|
+
const isReference = (value) => isObject(value) && Object.keys(value).length === 1 && typeof value.id === "string";
|
|
10
|
+
const topLevelNodes = (document) => (Array.isArray(document["@graph"]) ? document["@graph"] : [document]).filter(isObject);
|
|
11
|
+
const contextBase = (document) => {
|
|
12
|
+
const context = Array.isArray(document["@context"]) ? document["@context"] : [document["@context"]];
|
|
13
|
+
const entry = context.find((item) => isObject(item) && typeof item["@base"] === "string");
|
|
14
|
+
return entry?.["@base"] ?? defaultBase();
|
|
15
|
+
};
|
|
16
|
+
const containsReference = (value, ids) => {
|
|
17
|
+
if (Array.isArray(value))
|
|
18
|
+
return value.some((item) => containsReference(item, ids));
|
|
19
|
+
if (!isObject(value))
|
|
20
|
+
return false;
|
|
21
|
+
if (isReference(value))
|
|
22
|
+
return ids.has(value.id);
|
|
23
|
+
return Object.entries(value).some(([key, member]) => !key.startsWith("@") && containsReference(member, ids));
|
|
24
|
+
};
|
|
25
|
+
export const isFlat = (document) => {
|
|
26
|
+
const nodes = topLevelNodes(document);
|
|
27
|
+
const ids = new Set(nodes.filter((node) => node.type !== undefined && typeof node.id === "string").map((node) => node.id));
|
|
28
|
+
return nodes.some((node) => Object.entries(node).some(([key, member]) => !key.startsWith("@") && containsReference(member, ids)));
|
|
29
|
+
};
|
|
30
|
+
const nest = (value, index, nested, path) => {
|
|
31
|
+
if (Array.isArray(value))
|
|
32
|
+
return value.map((item) => nest(item, index, nested, path));
|
|
33
|
+
if (!isObject(value))
|
|
34
|
+
return value;
|
|
35
|
+
if (isReference(value)) {
|
|
36
|
+
const target = index.get(value.id);
|
|
37
|
+
if (target === undefined || path.has(value.id))
|
|
38
|
+
return value;
|
|
39
|
+
nested.add(value.id);
|
|
40
|
+
return nest(target, index, nested, path);
|
|
41
|
+
}
|
|
42
|
+
const id = typeof value.id === "string" ? value.id : undefined;
|
|
43
|
+
if (id !== undefined)
|
|
44
|
+
path.add(id);
|
|
45
|
+
const result = {};
|
|
46
|
+
for (const [key, member] of Object.entries(value)) {
|
|
47
|
+
if (key === "id" && typeof member === "string" && member.startsWith("_:"))
|
|
48
|
+
continue;
|
|
49
|
+
result[key] = key.startsWith("@") ? member : nest(member, index, nested, path);
|
|
50
|
+
}
|
|
51
|
+
if (id !== undefined)
|
|
52
|
+
path.delete(id);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
export const normalize = async (document, documentUrl) => {
|
|
56
|
+
if (!isFlat(document))
|
|
57
|
+
return document;
|
|
58
|
+
const options = { base: documentUrl ?? contextBase(document), documentLoader: loader };
|
|
59
|
+
const flat = await jsonld.flatten(document, undefined, options);
|
|
60
|
+
const compacted = await jsonld.compact(flat, document["@context"], options);
|
|
61
|
+
const nodes = topLevelNodes(compacted);
|
|
62
|
+
const index = new Map(nodes.filter((node) => typeof node.id === "string").map((node) => [node.id, node]));
|
|
63
|
+
const nested = new Set();
|
|
64
|
+
const nodesNested = nodes.map((node) => nest(node, index, nested, new Set()));
|
|
65
|
+
const roots = nodesNested.filter((_, position) => !(typeof nodes[position].id === "string" && nested.has(nodes[position].id)));
|
|
66
|
+
return { "@context": compacted["@context"], "@graph": roots };
|
|
67
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const EXIT_OK = 0;
|
|
2
|
+
export declare const EXIT_EXPORT_PROBLEM = 1;
|
|
3
|
+
export declare const EXIT_BAD_INPUT = 2;
|
|
4
|
+
export interface CliResult {
|
|
5
|
+
exitCode: number;
|
|
6
|
+
stdout: string;
|
|
7
|
+
stderr: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const USAGE = "Usage: export <input.jsonld> [options]\n\nExports a BPMN-LD document (nested or flat canonical form) to BPMN 2.0 XML.\n\nOptions:\n -o, --output <file> Write XML to <file> instead of standard output\n --layout Add BPMN DI first: shapes and edges are laid out for flow nodes\n and sequence flows that lack them, existing DI is kept\n --force With --layout, replace existing diagrams by a fresh full layout\n --strict Exit with code 1 if the export produced any warning\n --json Print one JSON document { xml?, warnings, errors } on standard\n output instead of the XML and the text diagnostics. xml is\n left out when --output is given or the export failed\n -h, --help Show this help\n\nWithout --json, warnings and errors are written to standard error.\n\nExit codes:\n 0 Exported successfully\n 1 Strict mode found warnings\n 2 Usage error or unusable input (missing file, invalid JSON, invalid BPMN-LD)\n";
|
|
10
|
+
export declare const runExport: (argv: string[]) => Promise<CliResult>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { layoutAndExport } from "./export/layout-export.js";
|
|
5
|
+
import { exportDocument, ExportInputError } from "./export/export.js";
|
|
6
|
+
export const EXIT_OK = 0;
|
|
7
|
+
export const EXIT_EXPORT_PROBLEM = 1;
|
|
8
|
+
export const EXIT_BAD_INPUT = 2;
|
|
9
|
+
const MAX_REPORTED_ERRORS = 10;
|
|
10
|
+
export const USAGE = `Usage: export <input.jsonld> [options]
|
|
11
|
+
|
|
12
|
+
Exports a BPMN-LD document (nested or flat canonical form) to BPMN 2.0 XML.
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-o, --output <file> Write XML to <file> instead of standard output
|
|
16
|
+
--layout Add BPMN DI first: shapes and edges are laid out for flow nodes
|
|
17
|
+
and sequence flows that lack them, existing DI is kept
|
|
18
|
+
--force With --layout, replace existing diagrams by a fresh full layout
|
|
19
|
+
--strict Exit with code 1 if the export produced any warning
|
|
20
|
+
--json Print one JSON document { xml?, warnings, errors } on standard
|
|
21
|
+
output instead of the XML and the text diagnostics. xml is
|
|
22
|
+
left out when --output is given or the export failed
|
|
23
|
+
-h, --help Show this help
|
|
24
|
+
|
|
25
|
+
Without --json, warnings and errors are written to standard error.
|
|
26
|
+
|
|
27
|
+
Exit codes:
|
|
28
|
+
0 Exported successfully
|
|
29
|
+
1 Strict mode found warnings
|
|
30
|
+
2 Usage error or unusable input (missing file, invalid JSON, invalid BPMN-LD)
|
|
31
|
+
`;
|
|
32
|
+
class UsageError extends Error {
|
|
33
|
+
}
|
|
34
|
+
const parseArgs = (argv) => {
|
|
35
|
+
const options = { input: "", strict: false, layout: false, force: false, json: false };
|
|
36
|
+
let input;
|
|
37
|
+
for (let i = 0; i < argv.length; i++) {
|
|
38
|
+
const arg = argv[i];
|
|
39
|
+
if (arg === "-h" || arg === "--help")
|
|
40
|
+
return "help";
|
|
41
|
+
else if (arg === "-o" || arg === "--output") {
|
|
42
|
+
const value = argv[++i];
|
|
43
|
+
if (value === undefined || value.startsWith("-"))
|
|
44
|
+
throw new UsageError(`${arg} requires a value`);
|
|
45
|
+
options.output = value;
|
|
46
|
+
}
|
|
47
|
+
else if (arg === "--strict")
|
|
48
|
+
options.strict = true;
|
|
49
|
+
else if (arg === "--layout")
|
|
50
|
+
options.layout = true;
|
|
51
|
+
else if (arg === "--force")
|
|
52
|
+
options.force = true;
|
|
53
|
+
else if (arg === "--json")
|
|
54
|
+
options.json = true;
|
|
55
|
+
else if (arg.startsWith("-"))
|
|
56
|
+
throw new UsageError(`unknown option ${arg}`);
|
|
57
|
+
else if (input !== undefined)
|
|
58
|
+
throw new UsageError(`unexpected extra argument ${arg}`);
|
|
59
|
+
else
|
|
60
|
+
input = arg;
|
|
61
|
+
}
|
|
62
|
+
if (input === undefined)
|
|
63
|
+
throw new UsageError("missing input file");
|
|
64
|
+
if (options.force && !options.layout)
|
|
65
|
+
throw new UsageError("--force requires --layout");
|
|
66
|
+
options.input = input;
|
|
67
|
+
return options;
|
|
68
|
+
};
|
|
69
|
+
const failure = (exitCode, stderr) => ({ exitCode, stdout: "", stderr });
|
|
70
|
+
const readJson = (path) => {
|
|
71
|
+
let text;
|
|
72
|
+
try {
|
|
73
|
+
text = readFileSync(path, "utf8");
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
const reason = error.code === "ENOENT" ? "no such file" : (error.message ?? "cannot read");
|
|
77
|
+
throw new UsageError(`cannot read ${path}: ${reason}`);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(text);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new UsageError(`${path} is not valid JSON: ${error.message}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const failureError = (code, message) => ({ code, location: "/", message });
|
|
87
|
+
const jsonResult = (exitCode, report) => ({
|
|
88
|
+
exitCode,
|
|
89
|
+
stdout: `${JSON.stringify(report, null, 2)}\n`,
|
|
90
|
+
stderr: "",
|
|
91
|
+
});
|
|
92
|
+
const formatWarning = (w) => `warning: ${w.kind} ${w.construct} at ${w.location} [${w.code}]${w.node ? ` node ${w.node}` : ""}${w.message ? `: ${w.message}` : ""}`;
|
|
93
|
+
export const runExport = async (argv) => {
|
|
94
|
+
let options;
|
|
95
|
+
try {
|
|
96
|
+
options = parseArgs(argv);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (error instanceof UsageError)
|
|
100
|
+
return failure(EXIT_BAD_INPUT, `error: ${error.message}\n\n${USAGE}`);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
if (options === "help")
|
|
104
|
+
return { exitCode: EXIT_OK, stdout: USAGE, stderr: "" };
|
|
105
|
+
let document;
|
|
106
|
+
try {
|
|
107
|
+
document = readJson(options.input);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (!(error instanceof UsageError))
|
|
111
|
+
throw error;
|
|
112
|
+
if (!options.json)
|
|
113
|
+
return failure(EXIT_BAD_INPUT, `error: ${error.message}\n`);
|
|
114
|
+
const code = error.message.includes("not valid JSON") ? "invalid-json" : "unreadable-input";
|
|
115
|
+
return jsonResult(EXIT_BAD_INPUT, { warnings: [], errors: [failureError(code, error.message)] });
|
|
116
|
+
}
|
|
117
|
+
let result;
|
|
118
|
+
try {
|
|
119
|
+
const documentUrl = pathToFileURL(resolve(options.input)).href;
|
|
120
|
+
result = options.layout
|
|
121
|
+
? await layoutAndExport(document, { documentUrl, force: options.force })
|
|
122
|
+
: await exportDocument(document, { documentUrl });
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (!(error instanceof ExportInputError))
|
|
126
|
+
throw error;
|
|
127
|
+
if (options.json)
|
|
128
|
+
return jsonResult(EXIT_BAD_INPUT, { warnings: [], errors: error.findings });
|
|
129
|
+
const shown = error.errors.slice(0, MAX_REPORTED_ERRORS).map((e) => `error: ${options.input}: invalid BPMN-LD: ${e}`);
|
|
130
|
+
const more = error.errors.length - shown.length;
|
|
131
|
+
if (more > 0)
|
|
132
|
+
shown.push(`error: ... and ${more} more`);
|
|
133
|
+
return failure(EXIT_BAD_INPUT, `${shown.join("\n")}\n`);
|
|
134
|
+
}
|
|
135
|
+
const errors = [];
|
|
136
|
+
let exitCode = EXIT_OK;
|
|
137
|
+
if (options.strict && result.warnings.length > 0) {
|
|
138
|
+
errors.push(failureError("strict-mode", `strict mode: ${result.warnings.length} warning(s)`));
|
|
139
|
+
exitCode = EXIT_EXPORT_PROBLEM;
|
|
140
|
+
}
|
|
141
|
+
if (options.output !== undefined) {
|
|
142
|
+
try {
|
|
143
|
+
writeFileSync(options.output, result.xml);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
const message = `cannot write ${options.output}: ${error.message}`;
|
|
147
|
+
if (options.json)
|
|
148
|
+
return jsonResult(EXIT_BAD_INPUT, { warnings: result.warnings, errors: [...errors, failureError("cannot-write", message)] });
|
|
149
|
+
return failure(EXIT_BAD_INPUT, [...result.warnings.map(formatWarning), ...errors.map((e) => `error: ${e.message}`), `error: ${message}`].join("\n") + "\n");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (options.json) {
|
|
153
|
+
return jsonResult(exitCode, { ...(options.output === undefined ? { xml: result.xml } : {}), warnings: result.warnings, errors });
|
|
154
|
+
}
|
|
155
|
+
const lines = [...result.warnings.map(formatWarning), ...errors.map((e) => `error: ${e.message}`)];
|
|
156
|
+
return { exitCode, stdout: options.output === undefined ? result.xml : "", stderr: lines.length ? `${lines.join("\n")}\n` : "" };
|
|
157
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ROOT } from "./paths.ts";
|
|
2
|
+
export { runAnalyze } from "./analyze-run.ts";
|
|
3
|
+
export { runCheckXml } from "./check-xml-run.ts";
|
|
4
|
+
export { runConvert } from "./convert-run.ts";
|
|
5
|
+
export { runExport } from "./export-run.ts";
|
|
6
|
+
export { installSkill, SUPPORTED_SKILL_DIRECTORIES } from "./install-skill.ts";
|
|
7
|
+
export { runInstallSkill } from "./install-skill-run.ts";
|
|
8
|
+
export { runLayout } from "./layout-run.ts";
|
|
9
|
+
export { runRender } from "./render-run.ts";
|
|
10
|
+
export { runValidate } from "./validate-run.ts";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ROOT } from "./paths.js";
|
|
2
|
+
export { runAnalyze } from "./analyze-run.js";
|
|
3
|
+
export { runCheckXml } from "./check-xml-run.js";
|
|
4
|
+
export { runConvert } from "./convert-run.js";
|
|
5
|
+
export { runExport } from "./export-run.js";
|
|
6
|
+
export { installSkill, SUPPORTED_SKILL_DIRECTORIES } from "./install-skill.js";
|
|
7
|
+
export { runInstallSkill } from "./install-skill-run.js";
|
|
8
|
+
export { runLayout } from "./layout-run.js";
|
|
9
|
+
export { runRender } from "./render-run.js";
|
|
10
|
+
export { runValidate } from "./validate-run.js";
|