@istar-ts/core 0.14.2 → 0.15.0-beta.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/README.md +22 -0
- package/dist/index.cjs +230 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +216 -133
- package/dist/index.d.ts +216 -133
- package/dist/index.js +227 -47
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -762,14 +762,64 @@ function defaultHubPosition(model, source, target, size) {
|
|
|
762
762
|
y: (a.y + b.y) / 2 - size.height / 2
|
|
763
763
|
};
|
|
764
764
|
}
|
|
765
|
+
/** Space kept between inner elements and an actor's boundary (piStar's `updateBoundary` adds 10px). */
|
|
766
|
+
const ACTOR_PADDING = 10;
|
|
767
|
+
/** A kind's default size, absent any per-host override (see `actorBounds`' `defaultSizeOf`). */
|
|
768
|
+
function metamodelSizeOf(metamodel, kind) {
|
|
769
|
+
return metamodel.elements.get(kind)?.size ?? {
|
|
770
|
+
width: 0,
|
|
771
|
+
height: 0
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* An actor's boundary: the kind's default-size rectangle at the actor's position, grown to
|
|
776
|
+
* include every inner element (each padded by `ACTOR_PADDING`), like piStar's `updateBoundary`
|
|
777
|
+
* (which floors on the kind's default size, not the actor's last expanded `display` size; an
|
|
778
|
+
* inner element's own `display` size does override, same as its rendered size elsewhere).
|
|
779
|
+
* Shared by `@istar-ts/react`'s node layout and `@istar-ts/glsp`'s GModel, so an actor draws the
|
|
780
|
+
* same box in both: children are looked up by category (`metamodelOf`), not `istar.*` names.
|
|
781
|
+
*
|
|
782
|
+
* `defaultSizeOf` resolves a kind's default size; it defaults to the metamodel's, but a host
|
|
783
|
+
* whose registry overrides a kind's size independently of the metamodel (`@istar-ts/react`'s
|
|
784
|
+
* `IstarRegistry`) must pass one that reads its own sizes, or its boundary would stop matching
|
|
785
|
+
* what it actually draws.
|
|
786
|
+
*/
|
|
787
|
+
function actorBounds(model, actorId, metamodel = metamodelOf(model), defaultSizeOf = (kind) => metamodelSizeOf(metamodel, kind)) {
|
|
788
|
+
const actor = model.elements.get(actorId);
|
|
789
|
+
if (!actor) throw new Error(`no element "${actorId}" in the model`);
|
|
790
|
+
const meta = metamodel;
|
|
791
|
+
const ownSize = defaultSizeOf(actor.kind);
|
|
792
|
+
let minX = actor.x;
|
|
793
|
+
let minY = actor.y;
|
|
794
|
+
let maxX = actor.x + ownSize.width;
|
|
795
|
+
let maxY = actor.y + ownSize.height;
|
|
796
|
+
for (const child of model.elements.values()) {
|
|
797
|
+
if (child.parent !== actorId) continue;
|
|
798
|
+
if (meta.elements.get(child.kind)?.category === "actor") continue;
|
|
799
|
+
const base = defaultSizeOf(child.kind);
|
|
800
|
+
const width = child.display?.width ?? base.width;
|
|
801
|
+
const height = child.display?.height ?? base.height;
|
|
802
|
+
minX = Math.min(minX, child.x - 10);
|
|
803
|
+
minY = Math.min(minY, child.y - 10);
|
|
804
|
+
maxX = Math.max(maxX, child.x + width + 10);
|
|
805
|
+
maxY = Math.max(maxY, child.y + height + 10);
|
|
806
|
+
}
|
|
807
|
+
return {
|
|
808
|
+
x: minX,
|
|
809
|
+
y: minY,
|
|
810
|
+
width: maxX - minX,
|
|
811
|
+
height: maxY - minY
|
|
812
|
+
};
|
|
813
|
+
}
|
|
765
814
|
//#endregion
|
|
766
815
|
//#region src/constraints.ts
|
|
767
816
|
const OK = { ok: true };
|
|
768
|
-
function fail$1(code, reason) {
|
|
817
|
+
function fail$1(code, reason, end) {
|
|
769
818
|
return {
|
|
770
819
|
ok: false,
|
|
771
820
|
code,
|
|
772
|
-
reason
|
|
821
|
+
reason,
|
|
822
|
+
end
|
|
773
823
|
};
|
|
774
824
|
}
|
|
775
825
|
/**
|
|
@@ -799,8 +849,8 @@ function canLink(model, source, target, kind, options = {}) {
|
|
|
799
849
|
const metamodel = options.metamodel ?? metamodelOf(model);
|
|
800
850
|
const s = resolve(any, source);
|
|
801
851
|
const t = resolve(any, target) ?? any.links.get(refId(target));
|
|
802
|
-
if (!s) return fail$1("unknown-element", `unknown source element "${refId(source)}"
|
|
803
|
-
if (!t) return fail$1("unknown-element", `unknown target element "${refId(target)}"
|
|
852
|
+
if (!s) return fail$1("unknown-element", `unknown source element "${refId(source)}"`, "source");
|
|
853
|
+
if (!t) return fail$1("unknown-element", `unknown target element "${refId(target)}"`, "target");
|
|
804
854
|
let definition = metamodel.links.get(kind);
|
|
805
855
|
if (!definition) return fail$1("unknown-link-kind", `unknown link kind "${String(kind)}"`);
|
|
806
856
|
if (definition.parts && !isLinkRef(t) && metamodel.elements.get(t.kind)?.of === definition.kind) definition = metamodel.links.get(definition.parts.leg) ?? definition;
|
|
@@ -851,7 +901,7 @@ function hubCheck(graph, definition, source, target) {
|
|
|
851
901
|
}
|
|
852
902
|
/** The built-in (iStar 2.0) rules only know element targets. */
|
|
853
903
|
function elementTargetOnly(definition) {
|
|
854
|
-
return fail$1("invalid-target", `the target of ${/^[aeiou]/i.test(definition.label) ? "an" : "a"} ${definition.label} link must be an element, not a link
|
|
904
|
+
return fail$1("invalid-target", `the target of ${/^[aeiou]/i.test(definition.label) ? "an" : "a"} ${definition.label} link must be an element, not a link`, "target");
|
|
855
905
|
}
|
|
856
906
|
function refId(ref) {
|
|
857
907
|
return typeof ref === "string" ? ref : ref.id;
|
|
@@ -927,16 +977,16 @@ const is = (graph, element, ...shortNames) => {
|
|
|
927
977
|
};
|
|
928
978
|
const isDependum = (element) => element.isDependum === true;
|
|
929
979
|
const isALink = (graph, source, target) => {
|
|
930
|
-
if (!is(graph, source, "Actor", "Role")) return fail$1("invalid-source", "the source of Is-A links must be a Role or a general Actor (iStar 2.0 Guide, Page 6).");
|
|
980
|
+
if (!is(graph, source, "Actor", "Role")) return fail$1("invalid-source", "the source of Is-A links must be a Role or a general Actor (iStar 2.0 Guide, Page 6).", "source");
|
|
931
981
|
if (source.kind !== target.kind) return fail$1("actor-types-differ", "the source and target of Is-A links must be of the same type - Actor and Actor, or Role and Role (iStar 2.0 Guide, Page 6).");
|
|
932
|
-
if (!is(graph, target, "Actor", "Role")) return fail$1("invalid-target", "the target of Is-A links must be a Role or a general Actor (iStar 2.0 Guide, Page 6).");
|
|
982
|
+
if (!is(graph, target, "Actor", "Role")) return fail$1("invalid-target", "the target of Is-A links must be a Role or a general Actor (iStar 2.0 Guide, Page 6).", "target");
|
|
933
983
|
if (source.id === target.id) return fail$1("self-link", "you cannot make Is-A links from an actor onto itself.");
|
|
934
984
|
if (graph.isThereLinkBetween(source, target)) return fail$1("duplicate-link", "there can only be one Actor link between the same two actors (iStar 2.0 Guide, Page 14).");
|
|
935
985
|
return OK;
|
|
936
986
|
};
|
|
937
987
|
const participatesInLink = (graph, source, target) => {
|
|
938
|
-
if (!graph.isActor(source)) return fail$1("invalid-source", "the source of a Participates-In link must be some kind of actor (iStar 2.0 Guide, Page 6)");
|
|
939
|
-
if (!graph.isActor(target)) return fail$1("invalid-target", "the target of a Participates-In link must be some kind of actor (iStar 2.0 Guide, Page 6)");
|
|
988
|
+
if (!graph.isActor(source)) return fail$1("invalid-source", "the source of a Participates-In link must be some kind of actor (iStar 2.0 Guide, Page 6)", "source");
|
|
989
|
+
if (!graph.isActor(target)) return fail$1("invalid-target", "the target of a Participates-In link must be some kind of actor (iStar 2.0 Guide, Page 6)", "target");
|
|
940
990
|
if (source.id === target.id) return fail$1("self-link", "you cannot make a Participates-In link from an actor onto itself.");
|
|
941
991
|
if (graph.isThereLinkBetween(source, target)) return fail$1("duplicate-link", "there can only be one Actor link between the same two actors (iStar 2.0 Guide, Page 14).");
|
|
942
992
|
return OK;
|
|
@@ -947,30 +997,30 @@ function owningActorId(graph, element) {
|
|
|
947
997
|
}
|
|
948
998
|
const dependencyLink = (graph, source, target) => {
|
|
949
999
|
if (source.id === target.id) return fail$1("self-link", "a Dependency link cannot link an element onto itself");
|
|
950
|
-
if (isDependum(source)) return fail$1("dependum-endpoint", "a Dependency link cannot start from a dependum");
|
|
951
|
-
if (isDependum(target)) return fail$1("dependum-endpoint", "a Dependency link cannot end in a dependum");
|
|
1000
|
+
if (isDependum(source)) return fail$1("dependum-endpoint", "a Dependency link cannot start from a dependum", "source");
|
|
1001
|
+
if (isDependum(target)) return fail$1("dependum-endpoint", "a Dependency link cannot end in a dependum", "target");
|
|
952
1002
|
if (owningActorId(graph, source) === owningActorId(graph, target)) return fail$1("same-actor", "a Dependency link must involve two different actors (iStar 2.0 Guide, Page 14)");
|
|
953
|
-
if (graph.isTargetOfType(source, "istar.OrRefinementLink") || graph.isTargetOfType(source, "istar.AndRefinementLink")) return fail$1("refined-depender", "a refined element cannot be the Depender Element in a Dependency link (iStar 2.0 Guide, Page 14). Instead, you can try to add the Dependency originating from a child.");
|
|
954
|
-
if (graph.isTargetOfType(source, "istar.ContributionLink")) return fail$1("contributed-depender", "a contributed element cannot be the Depender Element in a Dependency link (iStar 2.0 Guide, Page 14). Instead, you can try to add the Dependency originating from a child.");
|
|
1003
|
+
if (graph.isTargetOfType(source, "istar.OrRefinementLink") || graph.isTargetOfType(source, "istar.AndRefinementLink")) return fail$1("refined-depender", "a refined element cannot be the Depender Element in a Dependency link (iStar 2.0 Guide, Page 14). Instead, you can try to add the Dependency originating from a child.", "source");
|
|
1004
|
+
if (graph.isTargetOfType(source, "istar.ContributionLink")) return fail$1("contributed-depender", "a contributed element cannot be the Depender Element in a Dependency link (iStar 2.0 Guide, Page 14). Instead, you can try to add the Dependency originating from a child.", "source");
|
|
955
1005
|
return OK;
|
|
956
1006
|
};
|
|
957
1007
|
function refinementLink(label) {
|
|
958
1008
|
const other = label === "AND" ? "istar.OrRefinementLink" : "istar.AndRefinementLink";
|
|
959
1009
|
return (graph, source, target) => {
|
|
960
|
-
if (!is(graph, source, "Task", "Goal")) return fail$1("invalid-source", `the source of an ${label}-refinement link must be a Goal or a Task (iStar 2.0 Guide, Table 1)
|
|
961
|
-
if (!is(graph, target, "Task", "Goal")) return fail$1("invalid-target", `the target of an ${label}-refinement link must be a Goal or a Task (iStar 2.0 Guide, Table 1)
|
|
1010
|
+
if (!is(graph, source, "Task", "Goal")) return fail$1("invalid-source", `the source of an ${label}-refinement link must be a Goal or a Task (iStar 2.0 Guide, Table 1)`, "source");
|
|
1011
|
+
if (!is(graph, target, "Task", "Goal")) return fail$1("invalid-target", `the target of an ${label}-refinement link must be a Goal or a Task (iStar 2.0 Guide, Table 1)`, "target");
|
|
962
1012
|
if (source.id === target.id) return fail$1("self-link", `you cannot make an ${label}-refinement link from an element onto itself`);
|
|
963
1013
|
if (isDependum(source) || isDependum(target)) return fail$1("dependum-endpoint", `you cannot make an ${label}-refinement link with a dependum (iStar 2.0 Guide, Page 14)`);
|
|
964
1014
|
if (source.parent !== target.parent) return fail$1("different-actors", `the source and target of an ${label}-refinement link must pertain to the same actor (iStar 2.0 Guide, Page 14)`);
|
|
965
1015
|
if (graph.isThereLinkBetween(source, target)) return fail$1("duplicate-link", "there can only be one refinement link between the same two elements");
|
|
966
|
-
if (graph.isSourceOfType(target, "istar.DependencyLink")) return fail$1("depender-target", "you cannot refine a Depender Element; that is, an element that is the source of a Dependency (iStar 2.0 Guide, Page 14). Instead, you can try to move the dependency to the sub-element.");
|
|
967
|
-
if (graph.isTargetOfType(target, other)) return fail$1("mixed-refinement", label === "AND" ? "you cannot mix AND-refinements with OR-refinements targeting the same element (iStar 2.0 Guide, Page 10)." : "you cannot mix OR-refinements with AND-refinements targeting the same element (iStar 2.0 Guide, Page 10).");
|
|
1016
|
+
if (graph.isSourceOfType(target, "istar.DependencyLink")) return fail$1("depender-target", "you cannot refine a Depender Element; that is, an element that is the source of a Dependency (iStar 2.0 Guide, Page 14). Instead, you can try to move the dependency to the sub-element.", "target");
|
|
1017
|
+
if (graph.isTargetOfType(target, other)) return fail$1("mixed-refinement", label === "AND" ? "you cannot mix AND-refinements with OR-refinements targeting the same element (iStar 2.0 Guide, Page 10)." : "you cannot mix OR-refinements with AND-refinements targeting the same element (iStar 2.0 Guide, Page 10).", "target");
|
|
968
1018
|
return OK;
|
|
969
1019
|
};
|
|
970
1020
|
}
|
|
971
1021
|
const neededByLink = (graph, source, target) => {
|
|
972
|
-
if (!is(graph, source, "Resource")) return fail$1("invalid-source", "the source of a Needed-By link must be a Resource (iStar 2.0 Guide, Table 1)");
|
|
973
|
-
if (!is(graph, target, "Task")) return fail$1("invalid-target", "the target of a Needed-By link must be a Task (iStar 2.0 Guide, Table 1)");
|
|
1022
|
+
if (!is(graph, source, "Resource")) return fail$1("invalid-source", "the source of a Needed-By link must be a Resource (iStar 2.0 Guide, Table 1)", "source");
|
|
1023
|
+
if (!is(graph, target, "Task")) return fail$1("invalid-target", "the target of a Needed-By link must be a Task (iStar 2.0 Guide, Table 1)", "target");
|
|
974
1024
|
if (source.id === target.id) return fail$1("self-link", "you cannot make a Needed-By link from an element onto itself");
|
|
975
1025
|
if (isDependum(source) || isDependum(target)) return fail$1("dependum-endpoint", "you cannot make a Needed-By link with a dependum (iStar 2.0 Guide, Page 14)");
|
|
976
1026
|
if (source.parent !== target.parent) return fail$1("different-actors", "the source and target of a Needed-By link must pertain to the same actor (iStar 2.0 Guide, Page 14)");
|
|
@@ -978,19 +1028,19 @@ const neededByLink = (graph, source, target) => {
|
|
|
978
1028
|
return OK;
|
|
979
1029
|
};
|
|
980
1030
|
const contributionLink = (graph, source, target) => {
|
|
981
|
-
if (!is(graph, source, "Goal", "Quality", "Task", "Resource")) return fail$1("invalid-source", "the source of a Contribution link must be a Goal, a Quality, a Task or a Resource (iStar 2.0 Guide, Table 1)");
|
|
982
|
-
if (!is(graph, target, "Quality")) return fail$1("invalid-target", "the target of a Contribution link must be a Quality (iStar 2.0 Guide, Table 1)");
|
|
1031
|
+
if (!is(graph, source, "Goal", "Quality", "Task", "Resource")) return fail$1("invalid-source", "the source of a Contribution link must be a Goal, a Quality, a Task or a Resource (iStar 2.0 Guide, Table 1)", "source");
|
|
1032
|
+
if (!is(graph, target, "Quality")) return fail$1("invalid-target", "the target of a Contribution link must be a Quality (iStar 2.0 Guide, Table 1)", "target");
|
|
983
1033
|
if (source.id === target.id) return fail$1("self-link", "you cannot make a Contribution link from an element onto itself (iStar 2.0 Guide, Page 15)");
|
|
984
1034
|
if (isDependum(source) || isDependum(target)) return fail$1("dependum-endpoint", "you cannot make a Contribution link with a dependum (iStar 2.0 Guide, Page 14)");
|
|
985
1035
|
if (source.parent !== target.parent) return fail$1("different-actors", "the source and target of a Contribution link must pertain to the same actor (iStar 2.0 Guide, Page 14)");
|
|
986
1036
|
if (graph.isThereLinkBetween(source, target, "istar.ContributionLink")) return fail$1("duplicate-link", "there can only be one Contribution link between the same two elements");
|
|
987
1037
|
if (graph.isThereLinkBetween(source, target, "istar.QualificationLink")) return fail$1("contribution-and-qualification", "you cannot have Contribution and Qualification links between the same two elements (iStar 2.0 Guide, Page 15)");
|
|
988
|
-
if (graph.isSourceOfType(target, "istar.DependencyLink")) return fail$1("depender-target", "you cannot contribute to a Depender Element; that is, an element that is the source of a Dependency (iStar 2.0 Guide, Page 14). Instead, you can try to move the dependency to the sub-quality.");
|
|
1038
|
+
if (graph.isSourceOfType(target, "istar.DependencyLink")) return fail$1("depender-target", "you cannot contribute to a Depender Element; that is, an element that is the source of a Dependency (iStar 2.0 Guide, Page 14). Instead, you can try to move the dependency to the sub-quality.", "target");
|
|
989
1039
|
return OK;
|
|
990
1040
|
};
|
|
991
1041
|
const qualificationLink = (graph, source, target) => {
|
|
992
|
-
if (!is(graph, source, "Quality")) return fail$1("invalid-source", "the source of a Qualification link must be a Quality (iStar 2.0 Guide, Table 1)");
|
|
993
|
-
if (!is(graph, target, "Goal", "Task", "Resource")) return fail$1("invalid-target", "the target of a Qualification link must be a Goal, a Task or a Resource (iStar 2.0 Guide, Table 1)");
|
|
1042
|
+
if (!is(graph, source, "Quality")) return fail$1("invalid-source", "the source of a Qualification link must be a Quality (iStar 2.0 Guide, Table 1)", "source");
|
|
1043
|
+
if (!is(graph, target, "Goal", "Task", "Resource")) return fail$1("invalid-target", "the target of a Qualification link must be a Goal, a Task or a Resource (iStar 2.0 Guide, Table 1)", "target");
|
|
994
1044
|
if (source.id === target.id) return fail$1("self-link", "you cannot make a Qualification link from an element onto itself");
|
|
995
1045
|
if (isDependum(source) || isDependum(target)) return fail$1("dependum-endpoint", "you cannot make a Qualification link with a dependum (iStar 2.0 Guide, Page 14)");
|
|
996
1046
|
if (source.parent !== target.parent) return fail$1("different-actors", "the source and target of a Qualification link must pertain to the same actor (iStar 2.0 Guide, Page 14)");
|
|
@@ -1030,12 +1080,12 @@ function matchesSelector(graph, element, selector) {
|
|
|
1030
1080
|
function declarativeCheck(graph, definition, rules, rulesKind, source, target) {
|
|
1031
1081
|
const name = definition.label;
|
|
1032
1082
|
const article = /^[aeiou]/i.test(name) ? "an" : "a";
|
|
1033
|
-
if (!rules.sources.some((selector) => matchesSelector(graph, source, selector))) return fail$1("invalid-source", `the source of ${article} ${name} link must be ${describe(graph, rules.sources)}
|
|
1083
|
+
if (!rules.sources.some((selector) => matchesSelector(graph, source, selector))) return fail$1("invalid-source", `the source of ${article} ${name} link must be ${describe(graph, rules.sources)}`, "source");
|
|
1034
1084
|
if (!rules.targets.some((selector) => matchesSelector(graph, target, selector))) {
|
|
1035
1085
|
const targetKind = isLinkRef(target) ? void 0 : graph.metamodel.elements.get(target.kind);
|
|
1036
1086
|
const hubOf = targetKind?.role === "hub" && targetKind.of !== void 0 ? graph.metamodel.links.get(targetKind.of) : void 0;
|
|
1037
|
-
if (hubOf) return fail$1("hub-target", `you cannot make ${article} ${name} link towards the hub of ${/^[aeiou]/i.test(hubOf.label) ? "an" : "a"} ${hubOf.label} link
|
|
1038
|
-
return fail$1("invalid-target", `the target of ${article} ${name} link must be ${describe(graph, rules.targets)}
|
|
1087
|
+
if (hubOf) return fail$1("hub-target", `you cannot make ${article} ${name} link towards the hub of ${/^[aeiou]/i.test(hubOf.label) ? "an" : "a"} ${hubOf.label} link`, "target");
|
|
1088
|
+
return fail$1("invalid-target", `the target of ${article} ${name} link must be ${describe(graph, rules.targets)}`, "target");
|
|
1039
1089
|
}
|
|
1040
1090
|
if (!rules.allowSelf && source.id === target.id) return fail$1("self-link", `you cannot make ${article} ${name} link from an element onto itself`);
|
|
1041
1091
|
if (definition.category === "node" && !isLinkRef(target)) {
|
|
@@ -1790,6 +1840,20 @@ function withFileMetamodel(model, block) {
|
|
|
1790
1840
|
//#region src/operations.ts
|
|
1791
1841
|
var ModelOperationError = class extends Error {
|
|
1792
1842
|
name = "ModelOperationError";
|
|
1843
|
+
/** The element or link the error is about, when the operation named one. */
|
|
1844
|
+
elementId;
|
|
1845
|
+
constructor(message, elementId) {
|
|
1846
|
+
super(message);
|
|
1847
|
+
this.elementId = elementId;
|
|
1848
|
+
}
|
|
1849
|
+
/** As a `GoalDiagnostic`, anchored on `elementId` (empty string if the error names none). */
|
|
1850
|
+
toDiagnostic() {
|
|
1851
|
+
return {
|
|
1852
|
+
elementId: this.elementId ?? "",
|
|
1853
|
+
severity: "error",
|
|
1854
|
+
message: this.message
|
|
1855
|
+
};
|
|
1856
|
+
}
|
|
1793
1857
|
};
|
|
1794
1858
|
const defaultIdGenerator = () => {
|
|
1795
1859
|
const c = globalThis.crypto;
|
|
@@ -1819,12 +1883,12 @@ function derive(from, changes) {
|
|
|
1819
1883
|
}
|
|
1820
1884
|
function requireElement(model, id) {
|
|
1821
1885
|
const element = model.elements.get(id);
|
|
1822
|
-
if (!element) throw new ModelOperationError(`unknown element "${id}"
|
|
1886
|
+
if (!element) throw new ModelOperationError(`unknown element "${id}"`, id);
|
|
1823
1887
|
return element;
|
|
1824
1888
|
}
|
|
1825
1889
|
function requireLink(model, id) {
|
|
1826
1890
|
const link = model.links.get(id);
|
|
1827
|
-
if (!link) throw new ModelOperationError(`unknown link "${id}"
|
|
1891
|
+
if (!link) throw new ModelOperationError(`unknown link "${id}"`, id);
|
|
1828
1892
|
return link;
|
|
1829
1893
|
}
|
|
1830
1894
|
function withoutUndefined(value) {
|
|
@@ -1838,10 +1902,10 @@ function addElement(model, input, ctx = {}) {
|
|
|
1838
1902
|
const definition = metamodel.elements.get(input.kind);
|
|
1839
1903
|
if (!definition) throw new ModelOperationError(`unknown element kind "${input.kind}" in ${metamodel.name}`);
|
|
1840
1904
|
const id = input.id ?? (ctx.createId ?? defaultIdGenerator)();
|
|
1841
|
-
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use
|
|
1905
|
+
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use`, id);
|
|
1842
1906
|
if (input.parent !== void 0) {
|
|
1843
1907
|
if (definition.category === "actor") throw new ModelOperationError("actors cannot be nested");
|
|
1844
|
-
if (!isActorIn$1(m, requireElement(m, input.parent).kind)) throw new ModelOperationError(`parent "${input.parent}" is not an actor
|
|
1908
|
+
if (!isActorIn$1(m, requireElement(m, input.parent).kind)) throw new ModelOperationError(`parent "${input.parent}" is not an actor`, input.parent);
|
|
1845
1909
|
}
|
|
1846
1910
|
const element = withoutUndefined({
|
|
1847
1911
|
id,
|
|
@@ -1910,10 +1974,10 @@ function moveElement(model, id, x, y) {
|
|
|
1910
1974
|
function nestElement(model, id, parent) {
|
|
1911
1975
|
const m = any(model);
|
|
1912
1976
|
const current = requireElement(m, id);
|
|
1913
|
-
if (isActorIn$1(m, current.kind)) throw new ModelOperationError("actors cannot be nested");
|
|
1914
|
-
if (current.isDependum) throw new ModelOperationError("a dependum cannot be nested");
|
|
1977
|
+
if (isActorIn$1(m, current.kind)) throw new ModelOperationError("actors cannot be nested", id);
|
|
1978
|
+
if (current.isDependum) throw new ModelOperationError("a dependum cannot be nested", id);
|
|
1915
1979
|
if ((current.parent ?? null) === parent) return model;
|
|
1916
|
-
if (parent !== null && !isActorIn$1(m, requireElement(m, parent).kind)) throw new ModelOperationError(`parent "${parent}" is not an actor
|
|
1980
|
+
if (parent !== null && !isActorIn$1(m, requireElement(m, parent).kind)) throw new ModelOperationError(`parent "${parent}" is not an actor`, parent);
|
|
1917
1981
|
const elements = new Map(m.elements);
|
|
1918
1982
|
elements.delete(id);
|
|
1919
1983
|
const { parent: _old, ...rest } = current;
|
|
@@ -1991,12 +2055,27 @@ function removeCascade(model, elementIds, linkIds) {
|
|
|
1991
2055
|
});
|
|
1992
2056
|
}
|
|
1993
2057
|
/**
|
|
2058
|
+
* Maps a failing `connect` result to a `GoalDiagnostic`, anchored on the end named by the
|
|
2059
|
+
* `LinkCheck`'s `end` field (`target` when a check doesn't single out one end, such as
|
|
2060
|
+
* `self-link` or `actor-types-differ`). `undefined` for a successful result.
|
|
2061
|
+
*/
|
|
2062
|
+
function connectResultToDiagnostic(result, endpoints) {
|
|
2063
|
+
if (result.ok) return void 0;
|
|
2064
|
+
return {
|
|
2065
|
+
elementId: (result.end ?? "target") === "source" ? endpoints.source : endpoints.target,
|
|
2066
|
+
severity: "error",
|
|
2067
|
+
message: result.reason,
|
|
2068
|
+
code: result.code
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
/**
|
|
1994
2072
|
* Adds a link between two elements if the iStar constraints allow it.
|
|
1995
2073
|
*
|
|
1996
2074
|
* With an n-ary kind (`arity: 'n'`), a `target` that is one of the kind's hubs gets a new leg
|
|
1997
|
-
* from `source` (see `addLeg`).
|
|
1998
|
-
* target
|
|
1999
|
-
*
|
|
2075
|
+
* from `source` (see `addLeg`), taking `input.id` or `input.legId` (default a fresh id) as the
|
|
2076
|
+
* leg's id. Any other target gets a new hub, centred between source and target, with a leg from
|
|
2077
|
+
* `source` and an end to `target`. `input.id` and `customProperties` then go to the hub, `label`
|
|
2078
|
+
* and `name` to the end, and `legId`/`endId` (default fresh ids) to the leg and end.
|
|
2000
2079
|
*/
|
|
2001
2080
|
function connect(model, input, options = {}) {
|
|
2002
2081
|
const m = any(model);
|
|
@@ -2025,7 +2104,7 @@ function connect(model, input, options = {}) {
|
|
|
2025
2104
|
if (!m.links.has(target)) requireElement(m, target);
|
|
2026
2105
|
}
|
|
2027
2106
|
const id = input.id ?? (options.createId ?? defaultIdGenerator)();
|
|
2028
|
-
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use
|
|
2107
|
+
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use`, id);
|
|
2029
2108
|
const link = withoutUndefined({
|
|
2030
2109
|
id,
|
|
2031
2110
|
kind,
|
|
@@ -2046,7 +2125,13 @@ function connectHub(m, definition, input, options) {
|
|
|
2046
2125
|
const metamodel = metaOf(m);
|
|
2047
2126
|
const parts = definition.parts;
|
|
2048
2127
|
const { source, target } = input;
|
|
2049
|
-
if (m.elements.get(target)?.kind === parts.hub)
|
|
2128
|
+
if (m.elements.get(target)?.kind === parts.hub) {
|
|
2129
|
+
const legId = input.id ?? input.legId;
|
|
2130
|
+
return addLeg(typed(m), target, source, {
|
|
2131
|
+
...options,
|
|
2132
|
+
...legId === void 0 ? {} : { id: legId }
|
|
2133
|
+
});
|
|
2134
|
+
}
|
|
2050
2135
|
if (!options.force) {
|
|
2051
2136
|
const check = canLink(m, source, target, definition.kind);
|
|
2052
2137
|
if (!check.ok) return check;
|
|
@@ -2055,8 +2140,8 @@ function connectHub(m, definition, input, options) {
|
|
|
2055
2140
|
const to = requireElement(m, target);
|
|
2056
2141
|
const createId = options.createId ?? defaultIdGenerator;
|
|
2057
2142
|
const hubId = input.id ?? createId();
|
|
2058
|
-
const legId = createId();
|
|
2059
|
-
const endId = createId();
|
|
2143
|
+
const legId = input.legId ?? createId();
|
|
2144
|
+
const endId = input.endId ?? createId();
|
|
2060
2145
|
for (const [i, id] of [
|
|
2061
2146
|
hubId,
|
|
2062
2147
|
legId,
|
|
@@ -2065,7 +2150,7 @@ function connectHub(m, definition, input, options) {
|
|
|
2065
2150
|
hubId,
|
|
2066
2151
|
legId,
|
|
2067
2152
|
endId
|
|
2068
|
-
].indexOf(id) !== i) throw new ModelOperationError(`id "${id}" is already in use
|
|
2153
|
+
].indexOf(id) !== i) throw new ModelOperationError(`id "${id}" is already in use`, id);
|
|
2069
2154
|
const position = defaultHubPosition(m, from, to, metamodel.elements.get(parts.hub)?.size ?? {
|
|
2070
2155
|
width: 20,
|
|
2071
2156
|
height: 20
|
|
@@ -2116,14 +2201,14 @@ function addLeg(model, hubId, source, options = {}) {
|
|
|
2116
2201
|
const metamodel = metaOf(m);
|
|
2117
2202
|
const hub = requireElement(m, hubId);
|
|
2118
2203
|
const base = metamodel.links.get(metamodel.elements.get(hub.kind)?.of ?? "");
|
|
2119
|
-
if (metamodel.elements.get(hub.kind)?.role !== "hub" || !base?.parts) throw new ModelOperationError(`"${hubId}" is not the hub of an n-ary link
|
|
2204
|
+
if (metamodel.elements.get(hub.kind)?.role !== "hub" || !base?.parts) throw new ModelOperationError(`"${hubId}" is not the hub of an n-ary link`, hubId);
|
|
2120
2205
|
const kind = base.parts.leg;
|
|
2121
2206
|
if (!options.force) {
|
|
2122
2207
|
const check = canLink(m, source, hubId, kind);
|
|
2123
2208
|
if (!check.ok) return check;
|
|
2124
2209
|
} else requireElement(m, source);
|
|
2125
2210
|
const id = options.id ?? (options.createId ?? defaultIdGenerator)();
|
|
2126
|
-
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use
|
|
2211
|
+
if (m.elements.has(id) || m.links.has(id)) throw new ModelOperationError(`id "${id}" is already in use`, id);
|
|
2127
2212
|
const leg = {
|
|
2128
2213
|
id,
|
|
2129
2214
|
kind,
|
|
@@ -2146,7 +2231,7 @@ function addLeg(model, hubId, source, options = {}) {
|
|
|
2146
2231
|
function removeLeg(model, legId) {
|
|
2147
2232
|
const m = any(model);
|
|
2148
2233
|
const leg = requireLink(m, legId);
|
|
2149
|
-
if (metaOf(m).links.get(leg.kind)?.role !== "leg") throw new ModelOperationError(`"${legId}" is not a leg of an n-ary link
|
|
2234
|
+
if (metaOf(m).links.get(leg.kind)?.role !== "leg") throw new ModelOperationError(`"${legId}" is not a leg of an n-ary link`, legId);
|
|
2150
2235
|
return disconnect(model, legId);
|
|
2151
2236
|
}
|
|
2152
2237
|
/** Adds depender → dependum → dependee. */
|
|
@@ -2190,7 +2275,7 @@ function addDependency(model, input, options = {}) {
|
|
|
2190
2275
|
source: dependum.id,
|
|
2191
2276
|
target: dependee.id
|
|
2192
2277
|
};
|
|
2193
|
-
for (const id of [id1, id2]) if (added.model.elements.has(id) || added.model.links.has(id) || id1 === id2) throw new ModelOperationError(`id "${id}" is already in use
|
|
2278
|
+
for (const id of [id1, id2]) if (added.model.elements.has(id) || added.model.links.has(id) || id1 === id2) throw new ModelOperationError(`id "${id}" is already in use`, id);
|
|
2194
2279
|
return {
|
|
2195
2280
|
ok: true,
|
|
2196
2281
|
model: typed(derive(m, {
|
|
@@ -2972,6 +3057,101 @@ function fromNodeIdDiagnostics(diagnostics) {
|
|
|
2972
3057
|
return result;
|
|
2973
3058
|
}
|
|
2974
3059
|
//#endregion
|
|
2975
|
-
|
|
3060
|
+
//#region src/palette.ts
|
|
3061
|
+
/**
|
|
3062
|
+
* The data part of each kind's palette entry: label, grouping, ordering, and the presets a
|
|
3063
|
+
* toolbar entry creates with (a link's `value`, a dependency's `dependum`, an element's
|
|
3064
|
+
* `properties`). React-free so a host can answer "what can I add here" (GLSP's
|
|
3065
|
+
* `RequestContextActions`) without the react package. Icons, titles and components are
|
|
3066
|
+
* presentation and stay in `packages/react/src/registry`, which derives its default entries
|
|
3067
|
+
* from `DEFAULT_PALETTE`.
|
|
3068
|
+
*/
|
|
3069
|
+
function defaultElementEntry(kind, index) {
|
|
3070
|
+
const actor = isActorKind(kind);
|
|
3071
|
+
return {
|
|
3072
|
+
label: shortKindName(kind),
|
|
3073
|
+
order: actor ? index : 30 + index,
|
|
3074
|
+
section: actor ? "actors" : "elements",
|
|
3075
|
+
...actor ? { group: "actors" } : {}
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
const CONTRIBUTION_ENTRY_LABELS = {
|
|
3079
|
+
make: "Make (++)",
|
|
3080
|
+
help: "Help (+)",
|
|
3081
|
+
hurt: "Hurt (-)",
|
|
3082
|
+
break: "Break (--)"
|
|
3083
|
+
};
|
|
3084
|
+
const LINK_ENTRIES = {
|
|
3085
|
+
"istar.IsALink": [{
|
|
3086
|
+
label: "Is A",
|
|
3087
|
+
order: 10,
|
|
3088
|
+
group: "actor-links",
|
|
3089
|
+
section: "actors"
|
|
3090
|
+
}],
|
|
3091
|
+
"istar.ParticipatesInLink": [{
|
|
3092
|
+
label: "Participates-In",
|
|
3093
|
+
order: 11,
|
|
3094
|
+
group: "actor-links",
|
|
3095
|
+
section: "actors"
|
|
3096
|
+
}],
|
|
3097
|
+
"istar.DependencyLink": NODE_KINDS.map((dependum, i) => ({
|
|
3098
|
+
label: `${shortKindName(dependum)} dependency`,
|
|
3099
|
+
dependum,
|
|
3100
|
+
order: 20 + i,
|
|
3101
|
+
group: "dependencies",
|
|
3102
|
+
section: "actors"
|
|
3103
|
+
})),
|
|
3104
|
+
"istar.AndRefinementLink": [{
|
|
3105
|
+
label: "And",
|
|
3106
|
+
order: 40,
|
|
3107
|
+
section: "elements"
|
|
3108
|
+
}],
|
|
3109
|
+
"istar.OrRefinementLink": [{
|
|
3110
|
+
label: "Or",
|
|
3111
|
+
order: 41,
|
|
3112
|
+
section: "elements"
|
|
3113
|
+
}],
|
|
3114
|
+
"istar.NeededByLink": [{
|
|
3115
|
+
label: "Needed-By",
|
|
3116
|
+
order: 42,
|
|
3117
|
+
section: "elements"
|
|
3118
|
+
}],
|
|
3119
|
+
"istar.QualificationLink": [{
|
|
3120
|
+
label: "Qualification",
|
|
3121
|
+
order: 43,
|
|
3122
|
+
section: "elements"
|
|
3123
|
+
}],
|
|
3124
|
+
"istar.ContributionLink": CONTRIBUTION_LABELS.map((value, i) => ({
|
|
3125
|
+
label: CONTRIBUTION_ENTRY_LABELS[value],
|
|
3126
|
+
value,
|
|
3127
|
+
order: 50 + i,
|
|
3128
|
+
group: "contributions",
|
|
3129
|
+
section: "elements"
|
|
3130
|
+
}))
|
|
3131
|
+
};
|
|
3132
|
+
/** piStar's dropdown buttons. */
|
|
3133
|
+
const DEFAULT_PALETTE_GROUPS = {
|
|
3134
|
+
actors: { label: "Actor" },
|
|
3135
|
+
"actor-links": { label: "Actor links" },
|
|
3136
|
+
dependencies: { label: "Dependency" },
|
|
3137
|
+
contributions: { label: "Contribution" }
|
|
3138
|
+
};
|
|
3139
|
+
function buildDefaultPalette() {
|
|
3140
|
+
const elements = {};
|
|
3141
|
+
ELEMENT_KINDS.forEach((kind, i) => {
|
|
3142
|
+
elements[kind] = defaultElementEntry(kind, i);
|
|
3143
|
+
});
|
|
3144
|
+
const links = {};
|
|
3145
|
+
for (const kind of LINK_KINDS) links[kind] = LINK_ENTRIES[kind];
|
|
3146
|
+
return {
|
|
3147
|
+
elements,
|
|
3148
|
+
links,
|
|
3149
|
+
groups: DEFAULT_PALETTE_GROUPS
|
|
3150
|
+
};
|
|
3151
|
+
}
|
|
3152
|
+
/** The palette data of iStar 2.0, as piStar's toolbar presents it. */
|
|
3153
|
+
const DEFAULT_PALETTE = buildDefaultPalette();
|
|
3154
|
+
//#endregion
|
|
3155
|
+
export { ACTOR_KINDS, ACTOR_LINK_KINDS, ACTOR_PADDING, CONTRIBUTION_LABELS, DEFAULT_DIAGRAM, DEFAULT_ELEMENT_SIZE, DEFAULT_PALETTE, DEPENDENCY_LINK_KINDS, DIAGNOSTIC_SEVERITIES, DIAGRAM_LAYOUT_KEY, DSM3_FILE_KEYS, DSM3_TOOL, ELEMENT_KINDS, FILE_METAMODEL_KEY, HUB_ENTRY_KEY, ISTAR_2_0, ISTAR_2_0_DECLARATION, ISTAR_PREFIX, ISTAR_VERSION, LINK_KINDS, LINK_KIND_INFO, LINK_SELECTOR, METAMODEL_VERSION, MetamodelError, ModelOperationError, NODE_KINDS, NODE_KIND_INFO, NODE_LINK_KINDS, PISTAR_TOOL, PistarParseError, PistarWriteError, actorBounds, addDependency, addElement, addLeg, boolean, canLink, childrenOf, compareSeverity, connect, connectResultToDiagnostic, createDiagnosticsStore, createEmptyModel, createModelStore, defaultHubPosition, defaultIdGenerator, defineMetamodel, defineMetamodelExtension, defineProperties, dependencyEnds, dependencyLinksOf, detectFramework, detectPrefix, disconnect, effectiveElementKind, effectiveLinkKind, elementBehavesLike, elementCenter, elementKindDefinition, enumOf, extendMetamodel, fileMetamodelExtension, fileMetamodelOf, fromLspDiagnostic, fromLspDiagnostics, fromNodeIdDiagnostic, fromNodeIdDiagnostics, getSourceLayout, groupDiagnostics, hostMetamodelOf, hubEntryLayoutKey, hubLinkOf, hubOfLink, inheritMetamodel, inheritSourceLayout, isActor, isActorIn, isActorKind, isActorKindIn, isActorLinkKind, isContributionLabel, isDependencyLinkKind, isElementKind, isHubElement, isLinkKind, isLinkRef, isNode, isNodeIn, isNodeKind, isNodeKindIn, isNodeLinkKind, linkBehavesLike, linkKindDefinition, linkTargetOf, linksOf, mergeDiagnostics, metamodelOf, moveElement, nestElement, number, parsePistar, prop, reference, removeElement, removeElements, removeLeg, setHostMetamodel, shortKindName, string, targetsLinks, toPistar, toPistarObject, updateDiagram, updateElement, updateLink, validateFileMetamodel, validateModel, validateModelProperties, withFileMetamodel, withMetamodel, worstDiagnosticSeverity };
|
|
2976
3156
|
|
|
2977
3157
|
//# sourceMappingURL=index.js.map
|