sysml-validate 0.16.0 → 0.18.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/out/main.js +1520 -768
- package/out/main.js.map +4 -4
- package/package.json +1 -1
- package/resources/sysml.dimension-table.json +1 -1
- package/resources/sysml.library.index.json +1 -1
package/out/main.js
CHANGED
|
@@ -57816,229 +57816,640 @@ function asDiagnosticLevel(value, fallback = "off") {
|
|
|
57816
57816
|
return value === "off" || value === "warning" || value === "error" ? value : fallback;
|
|
57817
57817
|
}
|
|
57818
57818
|
|
|
57819
|
-
// ../language-server/out/src/services/
|
|
57820
|
-
var
|
|
57821
|
-
|
|
57822
|
-
|
|
57823
|
-
|
|
57819
|
+
// ../language-server/out/src/services/requirement-eval.js
|
|
57820
|
+
var UNRESOLVED = { kind: "unresolved" };
|
|
57821
|
+
var INCONCLUSIVE = { kind: "inconclusive" };
|
|
57822
|
+
var NULL_VALUE = { kind: "null" };
|
|
57823
|
+
var REDEFINE_KINDS = /* @__PURE__ */ new Set([":>>", ":>", "redefines", "subsets"]);
|
|
57824
|
+
function declaresFeature(node, name) {
|
|
57825
|
+
if (node.name === name)
|
|
57826
|
+
return true;
|
|
57827
|
+
for (const rel of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
|
|
57828
|
+
if (rel.kind && REDEFINE_KINDS.has(rel.kind) && (rel.targets ?? []).includes(name))
|
|
57829
|
+
return true;
|
|
57824
57830
|
}
|
|
57825
|
-
|
|
57826
|
-
|
|
57827
|
-
|
|
57828
|
-
|
|
57829
|
-
|
|
57830
|
-
|
|
57831
|
-
|
|
57832
|
-
|
|
57833
|
-
|
|
57834
|
-
|
|
57835
|
-
|
|
57836
|
-
|
|
57837
|
-
|
|
57838
|
-
|
|
57839
|
-
|
|
57840
|
-
|
|
57841
|
-
|
|
57842
|
-
|
|
57831
|
+
return false;
|
|
57832
|
+
}
|
|
57833
|
+
function evaluateExpr(node, scope, ext) {
|
|
57834
|
+
if (!node)
|
|
57835
|
+
return INCONCLUSIVE;
|
|
57836
|
+
const extended = ext?.(node, (child) => evaluateExpr(child, scope, ext));
|
|
57837
|
+
if (extended)
|
|
57838
|
+
return extended;
|
|
57839
|
+
const n = node;
|
|
57840
|
+
switch (n.$type) {
|
|
57841
|
+
case "NumericPrimary":
|
|
57842
|
+
return typeof n.numVal === "number" ? { kind: "number", value: n.numVal } : INCONCLUSIVE;
|
|
57843
|
+
case "LiteralBool":
|
|
57844
|
+
return { kind: "boolean", value: n.value === "true" };
|
|
57845
|
+
case "LiteralStr":
|
|
57846
|
+
return { kind: "string", value: decodeStringLiteral(String(n.value ?? "")) };
|
|
57847
|
+
case "LiteralNull":
|
|
57848
|
+
return INCONCLUSIVE;
|
|
57849
|
+
case "ParenExpr": {
|
|
57850
|
+
const items = n.items ?? [];
|
|
57851
|
+
return items.length === 1 ? evaluateExpr(items[0], scope, ext) : INCONCLUSIVE;
|
|
57843
57852
|
}
|
|
57853
|
+
case "UnaryMinusExpr": {
|
|
57854
|
+
const v = evaluateExpr(n.operand, scope, ext);
|
|
57855
|
+
return v.kind === "number" ? { kind: "number", value: -v.value } : passThrough(v);
|
|
57856
|
+
}
|
|
57857
|
+
case "UnaryPlusExpr":
|
|
57858
|
+
return evaluateExpr(n.operand, scope, ext);
|
|
57859
|
+
case "NotExpr": {
|
|
57860
|
+
if (!n.operand)
|
|
57861
|
+
return INCONCLUSIVE;
|
|
57862
|
+
const v = evaluateExpr(n.operand, scope, ext);
|
|
57863
|
+
return v.kind === "boolean" ? { kind: "boolean", value: !v.value } : passThrough(v);
|
|
57864
|
+
}
|
|
57865
|
+
case "PathExpr":
|
|
57866
|
+
return scope(String(n.path).split("."));
|
|
57867
|
+
case "IfExpr": {
|
|
57868
|
+
const cond = evaluateExpr(n.cond, scope, ext);
|
|
57869
|
+
if (cond.kind !== "boolean")
|
|
57870
|
+
return passThrough(cond);
|
|
57871
|
+
return cond.value ? evaluateExpr(n.thenExpr, scope, ext) : evaluateExpr(n.elseExpr, scope, ext);
|
|
57872
|
+
}
|
|
57873
|
+
case "PostfixOp": {
|
|
57874
|
+
if (n.unit && n.unitValue)
|
|
57875
|
+
return evaluateExpr(n.unitValue, scope, ext);
|
|
57876
|
+
if (n.operand)
|
|
57877
|
+
return evaluateExpr(n.operand, scope, ext);
|
|
57878
|
+
return INCONCLUSIVE;
|
|
57879
|
+
}
|
|
57880
|
+
case "BinExpr":
|
|
57881
|
+
return evaluateBin(n, scope, ext);
|
|
57882
|
+
default:
|
|
57883
|
+
return INCONCLUSIVE;
|
|
57844
57884
|
}
|
|
57845
|
-
named(name) {
|
|
57846
|
-
return this.byName.get(name) ?? EMPTY_DESCRIPTIONS;
|
|
57847
|
-
}
|
|
57848
|
-
firstNamed(name) {
|
|
57849
|
-
return this.byName.get(name)?.[0];
|
|
57850
|
-
}
|
|
57851
|
-
membersOf(path10, wildcard) {
|
|
57852
|
-
const map3 = wildcard === "shallow" ? this.directMembers : this.nestedMembers;
|
|
57853
|
-
return map3.get(path10) ?? EMPTY_DESCRIPTIONS;
|
|
57854
|
-
}
|
|
57855
|
-
};
|
|
57856
|
-
var EMPTY_DESCRIPTIONS = [];
|
|
57857
|
-
function push(map3, key, desc) {
|
|
57858
|
-
const list = map3.get(key);
|
|
57859
|
-
if (list)
|
|
57860
|
-
list.push(desc);
|
|
57861
|
-
else
|
|
57862
|
-
map3.set(key, [desc]);
|
|
57863
57885
|
}
|
|
57864
|
-
function
|
|
57865
|
-
|
|
57866
|
-
expandImportInto(imp, GlobalDescriptionIndex.from(globalDescriptions), out, options, /* @__PURE__ */ new Set());
|
|
57867
|
-
return dedupeEntries(out);
|
|
57886
|
+
function passThrough(v) {
|
|
57887
|
+
return v.kind === "unresolved" ? UNRESOLVED : INCONCLUSIVE;
|
|
57868
57888
|
}
|
|
57869
|
-
function
|
|
57870
|
-
|
|
57871
|
-
|
|
57872
|
-
|
|
57873
|
-
segments.push(seg.name);
|
|
57889
|
+
function decodeStringLiteral(raw) {
|
|
57890
|
+
let body = raw;
|
|
57891
|
+
if (body.length >= 2 && body.startsWith('"') && body.endsWith('"')) {
|
|
57892
|
+
body = body.slice(1, -1);
|
|
57874
57893
|
}
|
|
57875
|
-
return
|
|
57894
|
+
return body.replace(/\\(.)/gu, (_m, ch) => {
|
|
57895
|
+
switch (ch) {
|
|
57896
|
+
case "n":
|
|
57897
|
+
return "\n";
|
|
57898
|
+
case "t":
|
|
57899
|
+
return " ";
|
|
57900
|
+
case "b":
|
|
57901
|
+
return "\b";
|
|
57902
|
+
case "f":
|
|
57903
|
+
return "\f";
|
|
57904
|
+
default:
|
|
57905
|
+
return ch;
|
|
57906
|
+
}
|
|
57907
|
+
});
|
|
57876
57908
|
}
|
|
57877
|
-
function
|
|
57878
|
-
|
|
57879
|
-
|
|
57880
|
-
|
|
57881
|
-
|
|
57882
|
-
|
|
57883
|
-
|
|
57909
|
+
function evaluateBin(node, scope, ext) {
|
|
57910
|
+
const op = String(node.op);
|
|
57911
|
+
const left = evaluateExpr(node.left, scope, ext);
|
|
57912
|
+
if (op === "and" || op === "&") {
|
|
57913
|
+
if (left.kind === "boolean" && !left.value)
|
|
57914
|
+
return { kind: "boolean", value: false };
|
|
57915
|
+
} else if (op === "or" || op === "|") {
|
|
57916
|
+
if (left.kind === "boolean" && left.value)
|
|
57917
|
+
return { kind: "boolean", value: true };
|
|
57918
|
+
} else if (op === "implies") {
|
|
57919
|
+
if (left.kind === "boolean" && !left.value)
|
|
57920
|
+
return { kind: "boolean", value: true };
|
|
57884
57921
|
}
|
|
57885
|
-
|
|
57886
|
-
|
|
57887
|
-
|
|
57888
|
-
|
|
57889
|
-
|
|
57890
|
-
|
|
57891
|
-
|
|
57892
|
-
|
|
57893
|
-
|
|
57894
|
-
|
|
57895
|
-
|
|
57896
|
-
|
|
57897
|
-
|
|
57898
|
-
|
|
57899
|
-
|
|
57900
|
-
|
|
57901
|
-
|
|
57902
|
-
|
|
57903
|
-
|
|
57904
|
-
|
|
57905
|
-
|
|
57906
|
-
|
|
57907
|
-
|
|
57908
|
-
|
|
57909
|
-
|
|
57910
|
-
|
|
57911
|
-
|
|
57912
|
-
|
|
57913
|
-
|
|
57914
|
-
|
|
57915
|
-
|
|
57916
|
-
|
|
57917
|
-
|
|
57918
|
-
out.push({ name: alias, targetName: targetDesc.name, description: targetDesc });
|
|
57922
|
+
const right = evaluateExpr(node.right, scope, ext);
|
|
57923
|
+
if (left.kind === "unresolved" || right.kind === "unresolved")
|
|
57924
|
+
return UNRESOLVED;
|
|
57925
|
+
if (left.kind === "inconclusive" || right.kind === "inconclusive")
|
|
57926
|
+
return INCONCLUSIVE;
|
|
57927
|
+
switch (op) {
|
|
57928
|
+
case "+":
|
|
57929
|
+
case "-":
|
|
57930
|
+
case "*":
|
|
57931
|
+
case "/":
|
|
57932
|
+
case "%":
|
|
57933
|
+
case "**":
|
|
57934
|
+
case "^":
|
|
57935
|
+
if (left.kind === "number" && right.kind === "number") {
|
|
57936
|
+
return { kind: "number", value: arith(op, left.value, right.value) };
|
|
57937
|
+
}
|
|
57938
|
+
return INCONCLUSIVE;
|
|
57939
|
+
case "<":
|
|
57940
|
+
case ">":
|
|
57941
|
+
case "<=":
|
|
57942
|
+
case ">=":
|
|
57943
|
+
if (left.kind === "number" && right.kind === "number") {
|
|
57944
|
+
return { kind: "boolean", value: compare(op, left.value, right.value) };
|
|
57945
|
+
}
|
|
57946
|
+
return INCONCLUSIVE;
|
|
57947
|
+
case "==":
|
|
57948
|
+
case "!=":
|
|
57949
|
+
case "===":
|
|
57950
|
+
case "!==": {
|
|
57951
|
+
const eq3 = valuesEqual(left, right);
|
|
57952
|
+
if (eq3 === void 0)
|
|
57953
|
+
return INCONCLUSIVE;
|
|
57954
|
+
return { kind: "boolean", value: op.startsWith("!") ? !eq3 : eq3 };
|
|
57919
57955
|
}
|
|
57920
|
-
|
|
57921
|
-
|
|
57922
|
-
|
|
57956
|
+
case "and":
|
|
57957
|
+
case "&":
|
|
57958
|
+
return bothBool(left, right, (a2, b) => a2 && b);
|
|
57959
|
+
case "or":
|
|
57960
|
+
case "|":
|
|
57961
|
+
return bothBool(left, right, (a2, b) => a2 || b);
|
|
57962
|
+
case "xor":
|
|
57963
|
+
return bothBool(left, right, (a2, b) => a2 !== b);
|
|
57964
|
+
case "implies":
|
|
57965
|
+
return bothBool(left, right, (a2, b) => !a2 || b);
|
|
57966
|
+
default:
|
|
57967
|
+
return INCONCLUSIVE;
|
|
57923
57968
|
}
|
|
57924
|
-
applyImportFilters(imp, out, start, options);
|
|
57925
57969
|
}
|
|
57926
|
-
function
|
|
57927
|
-
|
|
57928
|
-
|
|
57929
|
-
|
|
57930
|
-
|
|
57931
|
-
|
|
57932
|
-
|
|
57933
|
-
|
|
57934
|
-
|
|
57935
|
-
|
|
57936
|
-
|
|
57970
|
+
function arith(op, a2, b) {
|
|
57971
|
+
switch (op) {
|
|
57972
|
+
case "+":
|
|
57973
|
+
return a2 + b;
|
|
57974
|
+
case "-":
|
|
57975
|
+
return a2 - b;
|
|
57976
|
+
case "*":
|
|
57977
|
+
return a2 * b;
|
|
57978
|
+
case "/":
|
|
57979
|
+
return a2 / b;
|
|
57980
|
+
case "%":
|
|
57981
|
+
return a2 % b;
|
|
57982
|
+
case "**":
|
|
57983
|
+
case "^":
|
|
57984
|
+
return a2 ** b;
|
|
57985
|
+
default:
|
|
57986
|
+
return NaN;
|
|
57937
57987
|
}
|
|
57938
|
-
out.length = start;
|
|
57939
|
-
out.push(...kept);
|
|
57940
57988
|
}
|
|
57941
|
-
function
|
|
57942
|
-
|
|
57943
|
-
|
|
57944
|
-
|
|
57945
|
-
|
|
57989
|
+
function compare(op, a2, b) {
|
|
57990
|
+
switch (op) {
|
|
57991
|
+
case "<":
|
|
57992
|
+
return a2 < b;
|
|
57993
|
+
case ">":
|
|
57994
|
+
return a2 > b;
|
|
57995
|
+
case "<=":
|
|
57996
|
+
return a2 <= b;
|
|
57997
|
+
case ">=":
|
|
57998
|
+
return a2 >= b;
|
|
57999
|
+
default:
|
|
57946
58000
|
return false;
|
|
57947
58001
|
}
|
|
57948
|
-
return true;
|
|
57949
58002
|
}
|
|
57950
|
-
function
|
|
57951
|
-
if (
|
|
57952
|
-
|
|
57953
|
-
|
|
57954
|
-
return
|
|
57955
|
-
|
|
57956
|
-
|
|
57957
|
-
|
|
57958
|
-
return
|
|
57959
|
-
|
|
57960
|
-
|
|
57961
|
-
|
|
57962
|
-
|
|
57963
|
-
|
|
57964
|
-
|
|
57965
|
-
|
|
57966
|
-
|
|
57967
|
-
|
|
57968
|
-
|
|
57969
|
-
|
|
57970
|
-
|
|
57971
|
-
if (
|
|
57972
|
-
|
|
57973
|
-
|
|
57974
|
-
|
|
57975
|
-
|
|
57976
|
-
return
|
|
58003
|
+
function valuesEqual(a2, b) {
|
|
58004
|
+
if (a2.kind === "null" || b.kind === "null")
|
|
58005
|
+
return a2.kind === b.kind;
|
|
58006
|
+
if (a2.kind === "number" && b.kind === "number")
|
|
58007
|
+
return a2.value === b.value;
|
|
58008
|
+
if (a2.kind === "boolean" && b.kind === "boolean")
|
|
58009
|
+
return a2.value === b.value;
|
|
58010
|
+
if (a2.kind === "string" && b.kind === "string")
|
|
58011
|
+
return a2.value === b.value;
|
|
58012
|
+
return void 0;
|
|
58013
|
+
}
|
|
58014
|
+
function bothBool(a2, b, f) {
|
|
58015
|
+
if (a2.kind === "boolean" && b.kind === "boolean")
|
|
58016
|
+
return { kind: "boolean", value: f(a2.value, b.value) };
|
|
58017
|
+
return INCONCLUSIVE;
|
|
58018
|
+
}
|
|
58019
|
+
function memberNamed(node, name, seen = /* @__PURE__ */ new Set()) {
|
|
58020
|
+
if (!node || seen.has(node))
|
|
58021
|
+
return void 0;
|
|
58022
|
+
seen.add(node);
|
|
58023
|
+
for (const member of node.members ?? []) {
|
|
58024
|
+
if (member.value !== void 0 && declaresFeature(member, name))
|
|
58025
|
+
return member;
|
|
58026
|
+
}
|
|
58027
|
+
for (const member of node.members ?? []) {
|
|
58028
|
+
if (declaresFeature(member, name))
|
|
58029
|
+
return member;
|
|
58030
|
+
}
|
|
58031
|
+
const typeRef = node.typing?.type?.ref;
|
|
58032
|
+
return typeRef ? memberNamed(typeRef, name, seen) : void 0;
|
|
58033
|
+
}
|
|
58034
|
+
function resolveFeatureValue(root3, segments) {
|
|
58035
|
+
let cur = root3;
|
|
58036
|
+
for (const seg of segments) {
|
|
58037
|
+
cur = memberNamed(cur, seg);
|
|
58038
|
+
if (!cur)
|
|
58039
|
+
return UNRESOLVED;
|
|
58040
|
+
}
|
|
58041
|
+
if (cur.value)
|
|
58042
|
+
return evaluateExpr(cur.value, () => INCONCLUSIVE);
|
|
58043
|
+
return INCONCLUSIVE;
|
|
58044
|
+
}
|
|
58045
|
+
function subjectScope(subjectName, subjectBinding) {
|
|
58046
|
+
const binding = subjectBinding;
|
|
58047
|
+
return (segments) => {
|
|
58048
|
+
if (!binding)
|
|
58049
|
+
return INCONCLUSIVE;
|
|
58050
|
+
if (subjectName && segments[0] === subjectName) {
|
|
58051
|
+
const rest = segments.slice(1);
|
|
58052
|
+
if (rest.length === 0)
|
|
58053
|
+
return INCONCLUSIVE;
|
|
58054
|
+
return resolveFeatureValue(binding, rest);
|
|
58055
|
+
}
|
|
58056
|
+
return resolveFeatureValue(binding, segments);
|
|
58057
|
+
};
|
|
58058
|
+
}
|
|
58059
|
+
function subjectNameOf(req) {
|
|
58060
|
+
const subject = (req.members ?? []).find((m) => m.$type === "SubjectDecl");
|
|
58061
|
+
return subject?.name;
|
|
58062
|
+
}
|
|
58063
|
+
function gatherConstraints(req) {
|
|
58064
|
+
const out = [];
|
|
58065
|
+
for (const member of req.members ?? []) {
|
|
58066
|
+
if (member.$type === "RequireConstraintStmt" && member.body) {
|
|
58067
|
+
out.push({ kind: "require", body: member.body, text: exprText(member.body) });
|
|
58068
|
+
} else if (member.$type === "AssumeConstraintStmt" && member.body) {
|
|
58069
|
+
out.push({ kind: "assume", body: member.body, text: exprText(member.body) });
|
|
57977
58070
|
}
|
|
58071
|
+
}
|
|
58072
|
+
return out;
|
|
58073
|
+
}
|
|
58074
|
+
function exprText(node) {
|
|
58075
|
+
return node.$cstNode?.text?.trim() ?? "";
|
|
58076
|
+
}
|
|
58077
|
+
function evaluateRequirement(req, subjectBinding) {
|
|
58078
|
+
const requirement = req;
|
|
58079
|
+
const subjectName = subjectNameOf(requirement);
|
|
58080
|
+
const scope = subjectScope(subjectName, subjectBinding);
|
|
58081
|
+
const constraints = gatherConstraints(requirement);
|
|
58082
|
+
const details = [];
|
|
58083
|
+
let sawInconclusive = false;
|
|
58084
|
+
let sawUnresolved = false;
|
|
58085
|
+
let failed = false;
|
|
58086
|
+
for (const c of constraints) {
|
|
58087
|
+
const v = evaluateExpr(c.body, scope);
|
|
58088
|
+
let status2;
|
|
58089
|
+
if (v.kind === "unresolved") {
|
|
58090
|
+
status2 = "unresolved";
|
|
58091
|
+
sawUnresolved = true;
|
|
58092
|
+
} else if (v.kind !== "boolean") {
|
|
58093
|
+
status2 = "inconclusive";
|
|
58094
|
+
sawInconclusive = true;
|
|
58095
|
+
} else if (v.value) {
|
|
58096
|
+
status2 = "pass";
|
|
58097
|
+
} else if (c.kind === "require") {
|
|
58098
|
+
status2 = "fail";
|
|
58099
|
+
failed = true;
|
|
58100
|
+
} else {
|
|
58101
|
+
status2 = "inconclusive";
|
|
58102
|
+
sawInconclusive = true;
|
|
58103
|
+
}
|
|
58104
|
+
details.push({ kind: c.kind, status: status2, text: c.text });
|
|
58105
|
+
}
|
|
58106
|
+
let status;
|
|
58107
|
+
if (constraints.length === 0)
|
|
58108
|
+
status = "inconclusive";
|
|
58109
|
+
else if (failed)
|
|
58110
|
+
status = "fail";
|
|
58111
|
+
else if (sawUnresolved)
|
|
58112
|
+
status = "unresolved";
|
|
58113
|
+
else if (sawInconclusive)
|
|
58114
|
+
status = "inconclusive";
|
|
58115
|
+
else
|
|
58116
|
+
status = "pass";
|
|
58117
|
+
return { status, details };
|
|
58118
|
+
}
|
|
58119
|
+
function bindingName(by) {
|
|
58120
|
+
const n = by;
|
|
58121
|
+
if (n?.$type !== "PathExpr")
|
|
57978
58122
|
return void 0;
|
|
58123
|
+
return n.path?.split(/::|\./).pop();
|
|
58124
|
+
}
|
|
58125
|
+
function evaluateVerificationCase(caseNode, resolveRequirement, resolvePart) {
|
|
58126
|
+
const node = caseNode;
|
|
58127
|
+
const subject = (node.members ?? []).find((m) => m.$type === "SubjectDecl");
|
|
58128
|
+
const subjectBoundName = bindingName(subject?.value);
|
|
58129
|
+
const subjectBinding = (subjectBoundName ? resolvePart(subjectBoundName) : void 0) ?? subject;
|
|
58130
|
+
const verifies = [];
|
|
58131
|
+
for (const member of node.members ?? []) {
|
|
58132
|
+
if (member.$type !== "VerifyStmt")
|
|
58133
|
+
continue;
|
|
58134
|
+
const targetName = String(member.target ?? "").split(/::|\./).pop();
|
|
58135
|
+
if (!targetName)
|
|
58136
|
+
continue;
|
|
58137
|
+
const req = resolveRequirement(targetName);
|
|
58138
|
+
if (!req) {
|
|
58139
|
+
verifies.push({ requirement: targetName, status: "unresolved" });
|
|
58140
|
+
continue;
|
|
58141
|
+
}
|
|
58142
|
+
const boundName = bindingName(member.by);
|
|
58143
|
+
const binding = (boundName ? resolvePart(boundName) : void 0) ?? subjectBinding;
|
|
58144
|
+
verifies.push({ requirement: targetName, status: evaluateRequirement(req, binding).status });
|
|
57979
58145
|
}
|
|
57980
|
-
|
|
58146
|
+
let status = "inconclusive";
|
|
58147
|
+
if (verifies.length === 0)
|
|
58148
|
+
status = "inconclusive";
|
|
58149
|
+
else if (verifies.some((v) => v.status === "fail"))
|
|
58150
|
+
status = "fail";
|
|
58151
|
+
else if (verifies.some((v) => v.status === "unresolved"))
|
|
58152
|
+
status = "error";
|
|
58153
|
+
else if (verifies.some((v) => v.status === "inconclusive"))
|
|
58154
|
+
status = "inconclusive";
|
|
58155
|
+
else
|
|
58156
|
+
status = "pass";
|
|
58157
|
+
return { status, verifies };
|
|
57981
58158
|
}
|
|
57982
|
-
|
|
57983
|
-
|
|
57984
|
-
|
|
58159
|
+
|
|
58160
|
+
// ../language-server/out/src/services/metadata-filter.js
|
|
58161
|
+
var INCONCLUSIVE2 = { kind: "inconclusive" };
|
|
58162
|
+
var SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([":>", "specializes", ":>>", "redefines", "subsets"]);
|
|
58163
|
+
var MAX_SPECIALIZATION_DEPTH = 32;
|
|
58164
|
+
var MAX_VALUE_DEPTH = 16;
|
|
58165
|
+
function evaluateFilterCondition(condition, element, options) {
|
|
57985
58166
|
if (!condition)
|
|
57986
58167
|
return void 0;
|
|
57987
|
-
|
|
57988
|
-
|
|
58168
|
+
const ctx = {
|
|
58169
|
+
element,
|
|
58170
|
+
options,
|
|
58171
|
+
metadata: attachedMetadata(element)
|
|
58172
|
+
};
|
|
58173
|
+
const value = evaluateExpr(condition, nameScope(ctx), extensionFor(ctx));
|
|
58174
|
+
return value.kind === "boolean" ? value.value : void 0;
|
|
58175
|
+
}
|
|
58176
|
+
function extensionFor(ctx) {
|
|
58177
|
+
const ext = (node, evaluate2) => {
|
|
58178
|
+
switch (node.$type) {
|
|
58179
|
+
case "SelfClassifyExpr":
|
|
58180
|
+
return classify(node, ctx);
|
|
58181
|
+
case "LiteralNull":
|
|
58182
|
+
return NULL_VALUE;
|
|
58183
|
+
case "PostfixOp":
|
|
58184
|
+
return featureAccess(node, ctx, ext);
|
|
58185
|
+
default:
|
|
58186
|
+
return void 0;
|
|
58187
|
+
}
|
|
58188
|
+
};
|
|
58189
|
+
return ext;
|
|
58190
|
+
}
|
|
58191
|
+
function classify(node, ctx) {
|
|
58192
|
+
const op = node.op;
|
|
58193
|
+
if (op === "@" || op === "@@" || op === "as" || op === "meta") {
|
|
58194
|
+
const found = findMetadata(node.type, ctx);
|
|
58195
|
+
return found === "unknown" ? INCONCLUSIVE2 : { kind: "boolean", value: found !== void 0 };
|
|
57989
58196
|
}
|
|
57990
|
-
if (
|
|
57991
|
-
return
|
|
58197
|
+
if (op === "istype" || op === "hastype")
|
|
58198
|
+
return classifyByType(op, node.type, ctx);
|
|
58199
|
+
return INCONCLUSIVE2;
|
|
58200
|
+
}
|
|
58201
|
+
function featureAccess(node, ctx, ext) {
|
|
58202
|
+
const segments = [];
|
|
58203
|
+
let cur = node;
|
|
58204
|
+
while (cur?.$type === "PostfixOp") {
|
|
58205
|
+
const postfix = cur;
|
|
58206
|
+
if (!(postfix.dot || postfix.select) || !postfix.field)
|
|
58207
|
+
return void 0;
|
|
58208
|
+
segments.unshift(postfix.field);
|
|
58209
|
+
cur = postfix.target;
|
|
57992
58210
|
}
|
|
57993
|
-
|
|
58211
|
+
const root3 = unwrapParen(cur);
|
|
58212
|
+
const rootOp = root3?.op;
|
|
58213
|
+
if (root3?.$type !== "SelfClassifyExpr" || !rootOp)
|
|
57994
58214
|
return void 0;
|
|
57995
|
-
if (
|
|
57996
|
-
return
|
|
58215
|
+
if (rootOp !== "as" && rootOp !== "meta" && rootOp !== "@" && rootOp !== "@@")
|
|
58216
|
+
return void 0;
|
|
58217
|
+
const found = findMetadata(root3.type, ctx);
|
|
58218
|
+
if (found === "unknown")
|
|
58219
|
+
return INCONCLUSIVE2;
|
|
58220
|
+
if (found === void 0)
|
|
58221
|
+
return NULL_VALUE;
|
|
58222
|
+
if (!found.annotation)
|
|
58223
|
+
return INCONCLUSIVE2;
|
|
58224
|
+
return metadataFeatureValue(found.annotation, segments, ctx, ext);
|
|
58225
|
+
}
|
|
58226
|
+
function metadataFeatureValue(annotation, segments, ctx, ext, depth = 0) {
|
|
58227
|
+
if (segments.length === 0 || depth > MAX_VALUE_DEPTH)
|
|
58228
|
+
return INCONCLUSIVE2;
|
|
58229
|
+
const [head2, ...rest] = segments;
|
|
58230
|
+
const definition = typeNodeOf(annotation, ctx);
|
|
58231
|
+
const member = memberNamed2(annotation, head2, ctx) ?? memberNamed2(definition, head2, ctx);
|
|
58232
|
+
if (!member)
|
|
58233
|
+
return INCONCLUSIVE2;
|
|
58234
|
+
if (rest.length > 0)
|
|
58235
|
+
return metadataFeatureValue(member, rest, ctx, ext, depth + 1);
|
|
58236
|
+
if (member.value)
|
|
58237
|
+
return evaluateExpr(member.value, nameScope(ctx), ext);
|
|
58238
|
+
return NULL_VALUE;
|
|
58239
|
+
}
|
|
58240
|
+
function memberNamed2(owner, name, ctx, depth = 0) {
|
|
58241
|
+
if (!owner || depth > MAX_SPECIALIZATION_DEPTH)
|
|
58242
|
+
return void 0;
|
|
58243
|
+
const members = owner.members ?? [];
|
|
58244
|
+
for (const member of members) {
|
|
58245
|
+
if (member.value !== void 0 && declaresFeature2(member, name))
|
|
58246
|
+
return member;
|
|
57997
58247
|
}
|
|
57998
|
-
|
|
57999
|
-
if (
|
|
58000
|
-
return
|
|
58001
|
-
}
|
|
58002
|
-
return { node: condition, construct: `the '${condition.op}' operator` };
|
|
58248
|
+
for (const member of members) {
|
|
58249
|
+
if (declaresFeature2(member, name))
|
|
58250
|
+
return member;
|
|
58003
58251
|
}
|
|
58004
|
-
|
|
58252
|
+
for (const target of specializationTargets(owner)) {
|
|
58253
|
+
const resolved = ctx.options.resolveName?.(target);
|
|
58254
|
+
const inherited = memberNamed2(resolved, name, ctx, depth + 1);
|
|
58255
|
+
if (inherited)
|
|
58256
|
+
return inherited;
|
|
58257
|
+
}
|
|
58258
|
+
const typed = typeNodeOf(owner, ctx);
|
|
58259
|
+
return typed ? memberNamed2(typed, name, ctx, depth + 1) : void 0;
|
|
58005
58260
|
}
|
|
58006
|
-
function
|
|
58007
|
-
if (
|
|
58008
|
-
|
|
58009
|
-
|
|
58010
|
-
if (
|
|
58011
|
-
return
|
|
58012
|
-
return "this postfix expression";
|
|
58261
|
+
function declaresFeature2(node, name) {
|
|
58262
|
+
if (node.name === name)
|
|
58263
|
+
return true;
|
|
58264
|
+
for (const rel of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
|
|
58265
|
+
if (rel.kind && SPECIALIZATION_KINDS.has(rel.kind) && (rel.targets ?? []).includes(name))
|
|
58266
|
+
return true;
|
|
58013
58267
|
}
|
|
58014
|
-
|
|
58015
|
-
return "a plain feature reference";
|
|
58016
|
-
return "this expression form";
|
|
58268
|
+
return false;
|
|
58017
58269
|
}
|
|
58018
|
-
function
|
|
58019
|
-
|
|
58020
|
-
if (!Array.isArray(siblings))
|
|
58021
|
-
return [];
|
|
58022
|
-
const index = siblings.indexOf(node);
|
|
58023
|
-
if (index < 0)
|
|
58270
|
+
function attachedMetadata(node) {
|
|
58271
|
+
if (!node)
|
|
58024
58272
|
return [];
|
|
58025
|
-
const
|
|
58026
|
-
for (
|
|
58027
|
-
|
|
58028
|
-
|
|
58029
|
-
|
|
58030
|
-
|
|
58273
|
+
const found = [];
|
|
58274
|
+
for (const member of node.members ?? []) {
|
|
58275
|
+
if (member.$type === "MetadataAnnotation")
|
|
58276
|
+
addMetadata(found, member, member.type);
|
|
58277
|
+
}
|
|
58278
|
+
const container = node.$container;
|
|
58279
|
+
if (container?.$type === "PrefixMetadataMember") {
|
|
58280
|
+
for (const tag of container.tags ?? [])
|
|
58281
|
+
addMetadata(found, void 0, tag.type);
|
|
58031
58282
|
}
|
|
58032
|
-
|
|
58283
|
+
found.push(...container ? annotationsByMember(container).get(node) ?? [] : []);
|
|
58284
|
+
return found;
|
|
58033
58285
|
}
|
|
58034
|
-
function
|
|
58035
|
-
|
|
58036
|
-
|
|
58037
|
-
|
|
58038
|
-
|
|
58039
|
-
|
|
58040
|
-
|
|
58041
|
-
|
|
58286
|
+
function addMetadata(found, annotation, type) {
|
|
58287
|
+
if (type)
|
|
58288
|
+
found.push({ annotation, type });
|
|
58289
|
+
}
|
|
58290
|
+
var annotationsByContainer = /* @__PURE__ */ new WeakMap();
|
|
58291
|
+
function annotationsByMember(container) {
|
|
58292
|
+
const cached = annotationsByContainer.get(container);
|
|
58293
|
+
if (cached)
|
|
58294
|
+
return cached;
|
|
58295
|
+
const byMember = /* @__PURE__ */ new Map();
|
|
58296
|
+
const byName = /* @__PURE__ */ new Map();
|
|
58297
|
+
const attach = (member, entry) => {
|
|
58298
|
+
const list = byMember.get(member);
|
|
58299
|
+
if (list)
|
|
58300
|
+
list.push(entry);
|
|
58301
|
+
else
|
|
58302
|
+
byMember.set(member, [entry]);
|
|
58303
|
+
};
|
|
58304
|
+
const members = container.members ?? [];
|
|
58305
|
+
let pending = [];
|
|
58306
|
+
for (const member of members) {
|
|
58307
|
+
if (member.$type === "MetadataAnnotation" || member.$type === "MetadataDecl") {
|
|
58308
|
+
const type = member.$type === "MetadataAnnotation" ? member.type : member.typing?.type;
|
|
58309
|
+
if (!type)
|
|
58310
|
+
continue;
|
|
58311
|
+
const entry = { annotation: member, type };
|
|
58312
|
+
const targets = member.targets ?? [];
|
|
58313
|
+
if (targets.length > 0) {
|
|
58314
|
+
for (const target of targets) {
|
|
58315
|
+
const simple = target.split(/::|\./).pop();
|
|
58316
|
+
if (!simple)
|
|
58317
|
+
continue;
|
|
58318
|
+
const list = byName.get(simple);
|
|
58319
|
+
if (list)
|
|
58320
|
+
list.push(entry);
|
|
58321
|
+
else
|
|
58322
|
+
byName.set(simple, [entry]);
|
|
58323
|
+
}
|
|
58324
|
+
} else if (member.$type === "MetadataAnnotation") {
|
|
58325
|
+
pending.push(entry);
|
|
58326
|
+
}
|
|
58327
|
+
continue;
|
|
58328
|
+
}
|
|
58329
|
+
for (const entry of pending)
|
|
58330
|
+
attach(member, entry);
|
|
58331
|
+
pending = [];
|
|
58332
|
+
}
|
|
58333
|
+
if (byName.size > 0) {
|
|
58334
|
+
for (const member of members) {
|
|
58335
|
+
const entries = member.name ? byName.get(member.name) : void 0;
|
|
58336
|
+
if (entries)
|
|
58337
|
+
for (const entry of entries)
|
|
58338
|
+
attach(member, entry);
|
|
58339
|
+
}
|
|
58340
|
+
}
|
|
58341
|
+
annotationsByContainer.set(container, byMember);
|
|
58342
|
+
return byMember;
|
|
58343
|
+
}
|
|
58344
|
+
function findMetadata(type, ctx) {
|
|
58345
|
+
if (!type)
|
|
58346
|
+
return "unknown";
|
|
58347
|
+
for (const meta of ctx.metadata) {
|
|
58348
|
+
if (metadataMatches(type, meta, ctx))
|
|
58349
|
+
return meta;
|
|
58350
|
+
}
|
|
58351
|
+
if (metaclassMatches(type, ctx))
|
|
58352
|
+
return { type };
|
|
58353
|
+
return ctx.element ? void 0 : "unknown";
|
|
58354
|
+
}
|
|
58355
|
+
function metadataMatches(type, meta, ctx) {
|
|
58356
|
+
const filterRef = ctx.options.resolveReferences ? type.ref : void 0;
|
|
58357
|
+
const metaRef = ctx.options.resolveReferences ? meta.type.ref : void 0;
|
|
58358
|
+
if (filterRef && metaRef && filterRef === metaRef)
|
|
58359
|
+
return true;
|
|
58360
|
+
const metaName = meta.type.$refText;
|
|
58361
|
+
if (qualifiedNameMatches(type.$refText, metaName))
|
|
58362
|
+
return true;
|
|
58363
|
+
const metaDefinition = metaRef ?? (metaName ? ctx.options.resolveName?.(metaName) : void 0);
|
|
58364
|
+
return specializes(metaDefinition, type, ctx);
|
|
58365
|
+
}
|
|
58366
|
+
function specializes(node, type, ctx, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
58367
|
+
if (!node || depth > MAX_SPECIALIZATION_DEPTH || seen.has(node))
|
|
58368
|
+
return false;
|
|
58369
|
+
seen.add(node);
|
|
58370
|
+
for (const target of specializationTargets(node)) {
|
|
58371
|
+
if (qualifiedNameMatches(type.$refText, target))
|
|
58372
|
+
return true;
|
|
58373
|
+
const resolved = ctx.options.resolveName?.(target);
|
|
58374
|
+
if (resolved && ctx.options.resolveReferences && resolved === type.ref)
|
|
58375
|
+
return true;
|
|
58376
|
+
if (specializes(resolved, type, ctx, depth + 1, seen))
|
|
58377
|
+
return true;
|
|
58378
|
+
}
|
|
58379
|
+
return false;
|
|
58380
|
+
}
|
|
58381
|
+
function metaclassMatches(type, ctx) {
|
|
58382
|
+
if (!ctx.element)
|
|
58383
|
+
return false;
|
|
58384
|
+
const metaclass = metaclassNameOf(ctx.element);
|
|
58385
|
+
const written = type.$refText;
|
|
58386
|
+
if (!written)
|
|
58387
|
+
return false;
|
|
58388
|
+
if (qualifiedNameMatches(written, metaclass))
|
|
58389
|
+
return true;
|
|
58390
|
+
const definition = ctx.options.resolveName?.(`SysML::${metaclass}`) ?? ctx.options.resolveName?.(metaclass);
|
|
58391
|
+
return specializes(definition, type, ctx);
|
|
58392
|
+
}
|
|
58393
|
+
function metaclassNameOf(node) {
|
|
58394
|
+
if (isPackage(node))
|
|
58395
|
+
return "Package";
|
|
58396
|
+
const type = node.$type.endsWith("Decl") ? node.$type.slice(0, -"Decl".length) : node.$type;
|
|
58397
|
+
const isDef = node.isDef;
|
|
58398
|
+
if (typeof isDef === "boolean")
|
|
58399
|
+
return `${type}${isDef ? "Definition" : "Usage"}`;
|
|
58400
|
+
return type;
|
|
58401
|
+
}
|
|
58402
|
+
function classifyByType(op, type, ctx) {
|
|
58403
|
+
if (!type || !ctx.element)
|
|
58404
|
+
return INCONCLUSIVE2;
|
|
58405
|
+
const declared = ctx.element.typing?.type;
|
|
58406
|
+
if (!declared)
|
|
58407
|
+
return INCONCLUSIVE2;
|
|
58408
|
+
if (qualifiedNameMatches(type.$refText, declared.$refText))
|
|
58409
|
+
return { kind: "boolean", value: true };
|
|
58410
|
+
if (ctx.options.resolveReferences && type.ref && declared.ref === type.ref)
|
|
58411
|
+
return { kind: "boolean", value: true };
|
|
58412
|
+
if (op === "hastype")
|
|
58413
|
+
return { kind: "boolean", value: false };
|
|
58414
|
+
const declaredNode = (ctx.options.resolveReferences ? declared.ref : void 0) ?? (declared.$refText ? ctx.options.resolveName?.(declared.$refText) : void 0);
|
|
58415
|
+
if (!declaredNode)
|
|
58416
|
+
return INCONCLUSIVE2;
|
|
58417
|
+
return { kind: "boolean", value: specializes(declaredNode, type, ctx) };
|
|
58418
|
+
}
|
|
58419
|
+
function nameScope(ctx, depth = 0) {
|
|
58420
|
+
return (segments) => {
|
|
58421
|
+
if (depth > MAX_VALUE_DEPTH)
|
|
58422
|
+
return INCONCLUSIVE2;
|
|
58423
|
+
const resolved = ctx.options.resolveName?.(segments.join("::"));
|
|
58424
|
+
if (!resolved?.value)
|
|
58425
|
+
return INCONCLUSIVE2;
|
|
58426
|
+
return evaluateExpr(resolved.value, nameScope(ctx, depth + 1), extensionFor(ctx));
|
|
58427
|
+
};
|
|
58428
|
+
}
|
|
58429
|
+
function specializationTargets(node) {
|
|
58430
|
+
const targets = [];
|
|
58431
|
+
for (const rel of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
|
|
58432
|
+
if (rel.kind && SPECIALIZATION_KINDS.has(rel.kind))
|
|
58433
|
+
targets.push(...rel.targets ?? []);
|
|
58434
|
+
}
|
|
58435
|
+
return targets;
|
|
58436
|
+
}
|
|
58437
|
+
function typeNodeOf(node, ctx) {
|
|
58438
|
+
const type = node?.type ?? node?.typing?.type;
|
|
58439
|
+
if (!type)
|
|
58440
|
+
return void 0;
|
|
58441
|
+
const ref = ctx.options.resolveReferences ? type.ref : void 0;
|
|
58442
|
+
return ref ?? (type.$refText ? ctx.options.resolveName?.(type.$refText) : void 0);
|
|
58443
|
+
}
|
|
58444
|
+
function unwrapParen(node) {
|
|
58445
|
+
let cur = node;
|
|
58446
|
+
while (cur?.$type === "ParenExpr") {
|
|
58447
|
+
const items = cur.items ?? [];
|
|
58448
|
+
if (items.length !== 1)
|
|
58449
|
+
return cur;
|
|
58450
|
+
cur = items[0];
|
|
58451
|
+
}
|
|
58452
|
+
return cur;
|
|
58042
58453
|
}
|
|
58043
58454
|
function qualifiedNameMatches(a2, b) {
|
|
58044
58455
|
if (!a2 || !b)
|
|
@@ -58054,32 +58465,253 @@ function qualifiedNameMatches(a2, b) {
|
|
|
58054
58465
|
}
|
|
58055
58466
|
return true;
|
|
58056
58467
|
}
|
|
58057
|
-
|
|
58058
|
-
|
|
58059
|
-
|
|
58060
|
-
|
|
58061
|
-
|
|
58062
|
-
|
|
58063
|
-
|
|
58064
|
-
|
|
58065
|
-
|
|
58066
|
-
|
|
58067
|
-
|
|
58068
|
-
|
|
58069
|
-
|
|
58070
|
-
|
|
58071
|
-
|
|
58072
|
-
|
|
58073
|
-
|
|
58074
|
-
|
|
58075
|
-
|
|
58076
|
-
|
|
58077
|
-
|
|
58078
|
-
|
|
58079
|
-
|
|
58080
|
-
|
|
58081
|
-
|
|
58082
|
-
|
|
58468
|
+
|
|
58469
|
+
// ../language-server/out/src/services/import-visibility.js
|
|
58470
|
+
var GlobalDescriptionIndex = class _GlobalDescriptionIndex {
|
|
58471
|
+
/** Reuse an existing index; wrap a plain list. */
|
|
58472
|
+
static from(source) {
|
|
58473
|
+
return source instanceof _GlobalDescriptionIndex ? source : new _GlobalDescriptionIndex(source);
|
|
58474
|
+
}
|
|
58475
|
+
/** Exact name → descriptions carrying it (qualified and simple names alike). */
|
|
58476
|
+
byName = /* @__PURE__ */ new Map();
|
|
58477
|
+
/** Namespace path → descriptions for its DIRECT members (`A::B` → `A::B::C`). */
|
|
58478
|
+
directMembers = /* @__PURE__ */ new Map();
|
|
58479
|
+
/** Namespace path → descriptions for all its descendants (`A` → `A::B::C`). */
|
|
58480
|
+
nestedMembers = /* @__PURE__ */ new Map();
|
|
58481
|
+
constructor(descriptions) {
|
|
58482
|
+
for (const desc of descriptions) {
|
|
58483
|
+
push(this.byName, desc.name, desc);
|
|
58484
|
+
let sep2 = desc.name.indexOf("::");
|
|
58485
|
+
while (sep2 >= 0) {
|
|
58486
|
+
const prefix = desc.name.slice(0, sep2);
|
|
58487
|
+
push(this.nestedMembers, prefix, desc);
|
|
58488
|
+
const next = desc.name.indexOf("::", sep2 + 2);
|
|
58489
|
+
if (next < 0)
|
|
58490
|
+
push(this.directMembers, prefix, desc);
|
|
58491
|
+
sep2 = next;
|
|
58492
|
+
}
|
|
58493
|
+
}
|
|
58494
|
+
}
|
|
58495
|
+
named(name) {
|
|
58496
|
+
return this.byName.get(name) ?? EMPTY_DESCRIPTIONS;
|
|
58497
|
+
}
|
|
58498
|
+
firstNamed(name) {
|
|
58499
|
+
return this.byName.get(name)?.[0];
|
|
58500
|
+
}
|
|
58501
|
+
membersOf(path10, wildcard) {
|
|
58502
|
+
const map3 = wildcard === "shallow" ? this.directMembers : this.nestedMembers;
|
|
58503
|
+
return map3.get(path10) ?? EMPTY_DESCRIPTIONS;
|
|
58504
|
+
}
|
|
58505
|
+
};
|
|
58506
|
+
var EMPTY_DESCRIPTIONS = [];
|
|
58507
|
+
function push(map3, key, desc) {
|
|
58508
|
+
const list = map3.get(key);
|
|
58509
|
+
if (list)
|
|
58510
|
+
list.push(desc);
|
|
58511
|
+
else
|
|
58512
|
+
map3.set(key, [desc]);
|
|
58513
|
+
}
|
|
58514
|
+
function expandImportEntries(imp, globalDescriptions, options = {}) {
|
|
58515
|
+
const out = [];
|
|
58516
|
+
expandImportInto(imp, GlobalDescriptionIndex.from(globalDescriptions), out, options, /* @__PURE__ */ new Set());
|
|
58517
|
+
return dedupeEntries(out);
|
|
58518
|
+
}
|
|
58519
|
+
function importedPath(imp) {
|
|
58520
|
+
const segments = [imp.head];
|
|
58521
|
+
for (const seg of imp.segs) {
|
|
58522
|
+
if (seg.name)
|
|
58523
|
+
segments.push(seg.name);
|
|
58524
|
+
}
|
|
58525
|
+
return segments.length > 0 ? segments.join("::") : void 0;
|
|
58526
|
+
}
|
|
58527
|
+
function importForm(imp) {
|
|
58528
|
+
let wildcard = "none";
|
|
58529
|
+
let includesSelf = false;
|
|
58530
|
+
const importAll = imp.isImportAll === true;
|
|
58531
|
+
for (const seg of imp.segs) {
|
|
58532
|
+
if (seg.recursive) {
|
|
58533
|
+
wildcard = "recursive";
|
|
58534
|
+
includesSelf = !seg.star;
|
|
58535
|
+
} else if (seg.star) {
|
|
58536
|
+
wildcard = "shallow";
|
|
58537
|
+
includesSelf = false;
|
|
58538
|
+
}
|
|
58539
|
+
}
|
|
58540
|
+
return { wildcard, includesSelf, importAll };
|
|
58541
|
+
}
|
|
58542
|
+
function importWildcard(imp) {
|
|
58543
|
+
return importForm(imp).wildcard;
|
|
58544
|
+
}
|
|
58545
|
+
function importVisibility(imp) {
|
|
58546
|
+
return imp.visibility ?? "private";
|
|
58547
|
+
}
|
|
58548
|
+
function resolveDescription(name, globalDescriptions) {
|
|
58549
|
+
const index = GlobalDescriptionIndex.from(globalDescriptions);
|
|
58550
|
+
const normalized = name.trim();
|
|
58551
|
+
const direct = index.firstNamed(normalized);
|
|
58552
|
+
if (direct)
|
|
58553
|
+
return direct;
|
|
58554
|
+
const simple = normalized.split(/::|\./).pop();
|
|
58555
|
+
return simple ? index.firstNamed(simple) : void 0;
|
|
58556
|
+
}
|
|
58557
|
+
function descriptionKey(description) {
|
|
58558
|
+
return `${description.documentUri.toString()}#${description.path}`;
|
|
58559
|
+
}
|
|
58560
|
+
function namespaceMembers(node) {
|
|
58561
|
+
const n = node;
|
|
58562
|
+
return [...n?.elements ?? [], ...n?.members ?? []];
|
|
58563
|
+
}
|
|
58564
|
+
function expandImportInto(imp, globalDescriptions, out, options, visitedNamespaces) {
|
|
58565
|
+
const path10 = importedPath(imp);
|
|
58566
|
+
if (!path10)
|
|
58567
|
+
return;
|
|
58568
|
+
const start = out.length;
|
|
58569
|
+
const namedSegments = path10.split("::");
|
|
58570
|
+
const form = importForm(imp);
|
|
58571
|
+
if (form.wildcard === "none") {
|
|
58572
|
+
const targetDesc = resolveImportedDescription(path10, globalDescriptions, options, visitedNamespaces, form.importAll);
|
|
58573
|
+
if (targetDesc) {
|
|
58574
|
+
const alias = imp.alias ?? namedSegments[namedSegments.length - 1];
|
|
58575
|
+
if (alias)
|
|
58576
|
+
out.push({ name: alias, targetName: targetDesc.name, description: targetDesc });
|
|
58577
|
+
}
|
|
58578
|
+
} else {
|
|
58579
|
+
out.push(...selectMemberships(path10, form, globalDescriptions));
|
|
58580
|
+
expandNamespaceImports(path10, globalDescriptions, out, options, visitedNamespaces, form.importAll);
|
|
58581
|
+
}
|
|
58582
|
+
applyImportFilters(imp, out, start, options);
|
|
58583
|
+
}
|
|
58584
|
+
function applyImportFilters(imp, out, start, options) {
|
|
58585
|
+
const conditions = filterConditionsFor(imp);
|
|
58586
|
+
if (conditions.length === 0 || out.length === start)
|
|
58587
|
+
return;
|
|
58588
|
+
const kept = keepMatching(conditions, out.slice(start), options);
|
|
58589
|
+
out.length = start;
|
|
58590
|
+
out.push(...kept);
|
|
58591
|
+
}
|
|
58592
|
+
function applyFilters(imp, entries, options = {}) {
|
|
58593
|
+
const conditions = filterConditionsFor(imp);
|
|
58594
|
+
return conditions.length === 0 ? entries : keepMatching(conditions, entries, options);
|
|
58595
|
+
}
|
|
58596
|
+
function keepMatching(conditions, entries, options) {
|
|
58597
|
+
const evalOptions = {
|
|
58598
|
+
resolveReferences: options.resolveReferences !== false,
|
|
58599
|
+
resolveName: options.resolveName
|
|
58600
|
+
};
|
|
58601
|
+
return entries.filter((entry) => {
|
|
58602
|
+
const node = options.nodeOf?.(entry.description) ?? entry.description.node;
|
|
58603
|
+
return !node || conditions.every((c) => evaluateFilterCondition(c, node, evalOptions) !== false);
|
|
58604
|
+
});
|
|
58605
|
+
}
|
|
58606
|
+
function filterConditionsFor(imp) {
|
|
58607
|
+
const conditions = [];
|
|
58608
|
+
const owner = imp.$container;
|
|
58609
|
+
if (governsImportFilters(owner)) {
|
|
58610
|
+
for (const member of namespaceMembers(owner)) {
|
|
58611
|
+
const condition = member.condition;
|
|
58612
|
+
if (member.$type === "FilterMember" && condition)
|
|
58613
|
+
conditions.push(condition);
|
|
58614
|
+
}
|
|
58615
|
+
}
|
|
58616
|
+
for (const filter3 of imp.filters ?? []) {
|
|
58617
|
+
if (filter3.condition)
|
|
58618
|
+
conditions.push(filter3.condition);
|
|
58619
|
+
}
|
|
58620
|
+
return conditions;
|
|
58621
|
+
}
|
|
58622
|
+
function governsImportFilters(owner) {
|
|
58623
|
+
return !!owner && (isPackage(owner) || owner.$type === "Document");
|
|
58624
|
+
}
|
|
58625
|
+
function undecidableFilterCondition(condition, resolveName) {
|
|
58626
|
+
if (!condition)
|
|
58627
|
+
return void 0;
|
|
58628
|
+
if (isSelfClassifyExpr(condition))
|
|
58629
|
+
return void 0;
|
|
58630
|
+
if (isNotExpr(condition) && condition.operand) {
|
|
58631
|
+
return undecidableFilterCondition(condition.operand, resolveName);
|
|
58632
|
+
}
|
|
58633
|
+
if (condition.$type === "NotExpr")
|
|
58634
|
+
return void 0;
|
|
58635
|
+
if (isParenExpr(condition)) {
|
|
58636
|
+
return condition.items.length === 1 ? undecidableFilterCondition(condition.items[0], resolveName) : { node: condition, construct: "a parenthesized expression list" };
|
|
58637
|
+
}
|
|
58638
|
+
if (isBinExpr(condition)) {
|
|
58639
|
+
return undecidableFilterCondition(condition.left, resolveName) ?? undecidableFilterCondition(condition.right, resolveName);
|
|
58640
|
+
}
|
|
58641
|
+
if (isPostfixOp(condition)) {
|
|
58642
|
+
if ((condition.dot || condition.select) && condition.field) {
|
|
58643
|
+
return undecidableFilterCondition(condition.target, resolveName);
|
|
58644
|
+
}
|
|
58645
|
+
if (condition.arrow && condition.invoke)
|
|
58646
|
+
return { node: condition, construct: `the '->${condition.invoke}' invocation` };
|
|
58647
|
+
return { node: condition, construct: "this postfix expression" };
|
|
58648
|
+
}
|
|
58649
|
+
if (isPathExpr(condition)) {
|
|
58650
|
+
const target = resolveName?.(condition.path);
|
|
58651
|
+
return target?.value !== void 0 ? void 0 : { node: condition, construct: "a plain feature reference" };
|
|
58652
|
+
}
|
|
58653
|
+
if (condition.$type === "IfExpr") {
|
|
58654
|
+
const conditional = condition;
|
|
58655
|
+
return undecidableFilterCondition(conditional.cond, resolveName) ?? undecidableFilterCondition(conditional.thenExpr, resolveName) ?? undecidableFilterCondition(conditional.elseExpr, resolveName);
|
|
58656
|
+
}
|
|
58657
|
+
if (DECIDABLE_LITERAL_TYPES.has(condition.$type))
|
|
58658
|
+
return void 0;
|
|
58659
|
+
return { node: condition, construct: "this expression form" };
|
|
58660
|
+
}
|
|
58661
|
+
var DECIDABLE_LITERAL_TYPES = /* @__PURE__ */ new Set([
|
|
58662
|
+
"NumericPrimary",
|
|
58663
|
+
"LiteralBool",
|
|
58664
|
+
"LiteralStr",
|
|
58665
|
+
"LiteralNull"
|
|
58666
|
+
]);
|
|
58667
|
+
function resolveImportedDescription(path10, globalDescriptions, options, visitedNamespaces, importAll = false) {
|
|
58668
|
+
const direct = globalDescriptions.firstNamed(path10);
|
|
58669
|
+
if (direct)
|
|
58670
|
+
return direct;
|
|
58671
|
+
const split = path10.lastIndexOf("::");
|
|
58672
|
+
if (split < 0)
|
|
58673
|
+
return void 0;
|
|
58674
|
+
const ownerPath = path10.slice(0, split);
|
|
58675
|
+
const simpleName2 = path10.slice(split + 2);
|
|
58676
|
+
const exported = [];
|
|
58677
|
+
expandNamespaceImports(ownerPath, globalDescriptions, exported, options, visitedNamespaces, importAll);
|
|
58678
|
+
return exported.find((entry) => entry.name === simpleName2)?.description;
|
|
58679
|
+
}
|
|
58680
|
+
function selectMemberships(path10, form, globalDescriptions) {
|
|
58681
|
+
if (form.wildcard === "none")
|
|
58682
|
+
return [];
|
|
58683
|
+
const index = GlobalDescriptionIndex.from(globalDescriptions);
|
|
58684
|
+
const entries = [];
|
|
58685
|
+
if (form.includesSelf) {
|
|
58686
|
+
const simple = simpleNameOf(path10);
|
|
58687
|
+
const self2 = index.named(path10).find((desc) => form.importAll || !isPrivateDescription(desc));
|
|
58688
|
+
if (self2)
|
|
58689
|
+
entries.push({ name: simple, targetName: self2.name, description: self2 });
|
|
58690
|
+
}
|
|
58691
|
+
const prefixLength = path10.length + 2;
|
|
58692
|
+
for (const desc of index.membersOf(path10, form.wildcard)) {
|
|
58693
|
+
if (!form.importAll && isPrivateDescription(desc))
|
|
58694
|
+
continue;
|
|
58695
|
+
const rest = desc.name.slice(prefixLength);
|
|
58696
|
+
if (!rest)
|
|
58697
|
+
continue;
|
|
58698
|
+
const nested = rest.includes("::");
|
|
58699
|
+
if (nested && !isOwnedMembership(desc))
|
|
58700
|
+
continue;
|
|
58701
|
+
entries.push({ name: nested ? rest.slice(rest.lastIndexOf("::") + 2) : rest, targetName: desc.name, description: desc });
|
|
58702
|
+
}
|
|
58703
|
+
return entries;
|
|
58704
|
+
}
|
|
58705
|
+
function simpleNameOf(path10) {
|
|
58706
|
+
return path10.includes("::") ? path10.slice(path10.lastIndexOf("::") + 2) : path10;
|
|
58707
|
+
}
|
|
58708
|
+
function isOwnedMembership(desc) {
|
|
58709
|
+
const kind = desc.derivedKind;
|
|
58710
|
+
return kind !== "reexport" && kind !== "inherited";
|
|
58711
|
+
}
|
|
58712
|
+
function expandNamespaceImports(path10, globalDescriptions, out, options, visitedNamespaces, importAll = false) {
|
|
58713
|
+
for (const namespaceDesc of globalDescriptions.named(path10)) {
|
|
58714
|
+
const key = descriptionKey(namespaceDesc);
|
|
58083
58715
|
if (visitedNamespaces.has(key))
|
|
58084
58716
|
continue;
|
|
58085
58717
|
visitedNamespaces.add(key);
|
|
@@ -58087,11 +58719,13 @@ function expandNamespaceImports(path10, globalDescriptions, out, options, visite
|
|
|
58087
58719
|
for (const member of namespaceMembers(owner)) {
|
|
58088
58720
|
if (!isImport(member))
|
|
58089
58721
|
continue;
|
|
58090
|
-
|
|
58091
|
-
|
|
58092
|
-
|
|
58093
|
-
|
|
58094
|
-
|
|
58722
|
+
if (!importAll) {
|
|
58723
|
+
const visibility = importVisibility(member);
|
|
58724
|
+
if (visibility === "private")
|
|
58725
|
+
continue;
|
|
58726
|
+
if (visibility === "protected" && !options.protectedNamespaceKeys?.has(key))
|
|
58727
|
+
continue;
|
|
58728
|
+
}
|
|
58095
58729
|
expandImportInto(member, globalDescriptions, out, options, visitedNamespaces);
|
|
58096
58730
|
}
|
|
58097
58731
|
}
|
|
@@ -58505,11 +59139,11 @@ function evaluate(node, mode, ctx) {
|
|
|
58505
59139
|
return { kind: "unknown" };
|
|
58506
59140
|
}
|
|
58507
59141
|
if (isBinExpr(node)) {
|
|
58508
|
-
return
|
|
59142
|
+
return evaluateBin2(node, mode, ctx);
|
|
58509
59143
|
}
|
|
58510
59144
|
return { kind: "unknown" };
|
|
58511
59145
|
}
|
|
58512
|
-
function
|
|
59146
|
+
function evaluateBin2(node, mode, ctx) {
|
|
58513
59147
|
const op = node.op;
|
|
58514
59148
|
const left = evaluate(node.left, mode, ctx);
|
|
58515
59149
|
const right = evaluate(node.right, mode, ctx);
|
|
@@ -58649,6 +59283,18 @@ var DIAGNOSTIC_MESSAGES = {
|
|
|
58649
59283
|
// `first a then b;` and the `then` occurrence shorthand in a part), so the
|
|
58650
59284
|
// message names the construct it means rather than "action language".
|
|
58651
59285
|
SEM011_ACTION_ONLY_CONSTRUCT: (construct, clause, owner) => `${construct} may only be declared in the body of an action definition or usage (OMG SysML v2 Part 1 \xA7${clause}), not in ${owner}.`,
|
|
59286
|
+
// REQ-392 — issue #150. A `rep … language "sysml"` body is a legal representation
|
|
59287
|
+
// of the element it annotates (OMG KerML §7.4.3), so the two faults are "this is
|
|
59288
|
+
// not SysML" and "this is not THIS element". The parser's own wording is carried
|
|
59289
|
+
// through verbatim, because it names the token the reader has to go and fix.
|
|
59290
|
+
SYN076_EMBEDDED_REPRESENTATION_SYNTAX: (language, detail) => `This representation declares language "${language}", so its body must be valid ${language}: ${detail}`,
|
|
59291
|
+
SEM012_REPRESENTATION_WRONG_KIND: (expected, actual) => `A textual representation must represent the element it annotates. This body represents '${actual}', but it annotates '${expected}'.`,
|
|
59292
|
+
// REQ-392 — The body is resolved in the represented element's own context, so an
|
|
59293
|
+
// unresolvable name there is the same defect it would be in ordinary code. It is
|
|
59294
|
+
// reported under its own code so a team can tune representations separately.
|
|
59295
|
+
RES020_REPRESENTATION_UNRESOLVED: (name, language) => `'${name}' cannot be resolved from here, so this ${language} representation is not a valid representation of the element it annotates.`,
|
|
59296
|
+
RES020_REPRESENTATION_PATH_SEGMENT: (segment, owner, language) => `Feature path segment '${segment}' does not exist on '${owner}', so this ${language} representation is not a valid representation of the element it annotates.`,
|
|
59297
|
+
SEM012_REPRESENTATION_WRONG_NAME: (expected, actual) => `A textual representation must represent the element it annotates. This body represents '${actual}', but it annotates '${expected}'.`,
|
|
58652
59298
|
RES016_LIBRARY_SHADOWING: (name) => `'${name}' shadows a standard-library element of the same name; the library symbol is hidden in this scope.`,
|
|
58653
59299
|
// issue #183 — KerML namespace distinguishability (validateNamespaceDistinguishability).
|
|
58654
59300
|
// Owned siblings sharing a name/short name (or an alias clashing with an owned
|
|
@@ -58658,13 +59304,26 @@ var DIAGNOSTIC_MESSAGES = {
|
|
|
58658
59304
|
// implicit-redefinition resolution this validator does not yet model.
|
|
58659
59305
|
RES017_DUPLICATE_MEMBER: (name) => `'${name}' is already declared in this namespace. Members must be distinguishable by name \u2014 rename or remove the duplicate.`,
|
|
58660
59306
|
RES017_DUPLICATE_SHORT_NAME: (name) => `Short name '<${name}>' is already used in this namespace. Members must be distinguishable \u2014 rename the short name.`,
|
|
58661
|
-
// issue #102 — REQ-387. The filter evaluator (`
|
|
58662
|
-
// `evaluateFilterCondition`) decides
|
|
58663
|
-
//
|
|
58664
|
-
// open is the right default — under-importing would manufacture
|
|
58665
|
-
// RES001s — but an unevaluated filter produces a scope or view that
|
|
58666
|
-
// authoritative and is not, so the fail-open is stated
|
|
58667
|
-
RES018_UNEVALUATED_FILTER: (subject, construct) => `${subject} filter is not evaluated: ${construct} is outside the metadata-filter evaluator, which decides
|
|
59307
|
+
// issue #102 — REQ-387. The filter evaluator (`metadata-filter.ts`,
|
|
59308
|
+
// `evaluateFilterCondition`) decides the model-level predicate surface; the
|
|
59309
|
+
// invocation and collection forms outside it fail OPEN, keeping the member.
|
|
59310
|
+
// Failing open is the right default — under-importing would manufacture
|
|
59311
|
+
// spurious RES001s — but an unevaluated filter produces a scope or view that
|
|
59312
|
+
// looks authoritative and is not, so the fail-open is stated, not assumed.
|
|
59313
|
+
RES018_UNEVALUATED_FILTER: (subject, construct) => `${subject} filter is not evaluated: ${construct} is outside the metadata-filter evaluator, which decides metadata tests, the classification operators, metadata feature access, and the Boolean, comparison and arithmetic operators over them. The filter fails open \u2014 it is treated as pass-through and removes nothing.`,
|
|
59314
|
+
// issue #154 — OMG SysML v2 Part 1 §7.5.5 (Root Namespace). The root
|
|
59315
|
+
// namespace of a file is anonymous and unnamed, so nothing can import it:
|
|
59316
|
+
// a `public` or `protected` import owned directly by it claims a re-export
|
|
59317
|
+
// no other namespace is able to consume. The Release BNF requires `private`
|
|
59318
|
+
// there, and rewriting it is mechanical — the import keeps working exactly
|
|
59319
|
+
// as it did, since a root import was never re-exported to begin with.
|
|
59320
|
+
RES021_ROOT_IMPORT_VISIBILITY: (visibility) => `An import in a file's root namespace must be 'private' \u2014 nothing can import the root namespace, so '${visibility}' re-exports to no one.`,
|
|
59321
|
+
// issue #153 — OMG SysML v2 Part 1 §7.5.4 (Filtered Packages) puts an element
|
|
59322
|
+
// filter in a package, where it restricts that package's imported memberships;
|
|
59323
|
+
// a view body is the one other place it is defined for (it restricts what the
|
|
59324
|
+
// view exposes). Anywhere else the member parses but nothing consumes it, so
|
|
59325
|
+
// it silently does nothing.
|
|
59326
|
+
KSM012_FILTER_PLACEMENT: (owner) => `A 'filter' member is only meaningful in a package or a view \u2014 it has no effect in a ${owner} body.`,
|
|
58668
59327
|
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
58669
59328
|
// issue #213 — the KerML textual BNF binds `::` tighter than `.`: each
|
|
58670
59329
|
// dot-separated link of a FeatureChain is a complete QualifiedName, and only
|
|
@@ -58911,7 +59570,7 @@ function commentBody(text) {
|
|
|
58911
59570
|
return text.slice(2, -2);
|
|
58912
59571
|
return void 0;
|
|
58913
59572
|
}
|
|
58914
|
-
function
|
|
59573
|
+
function classify2(text) {
|
|
58915
59574
|
const body = commentBody(text);
|
|
58916
59575
|
if (body === void 0)
|
|
58917
59576
|
return void 0;
|
|
@@ -58966,7 +59625,7 @@ function scanFormatDirectives(document) {
|
|
|
58966
59625
|
const leaf = leaves[index];
|
|
58967
59626
|
if (!leaf.hidden)
|
|
58968
59627
|
continue;
|
|
58969
|
-
const classified =
|
|
59628
|
+
const classified = classify2(leaf.text);
|
|
58970
59629
|
if (!classified)
|
|
58971
59630
|
continue;
|
|
58972
59631
|
const comment = { offset: leaf.offset, end: leaf.end };
|
|
@@ -59067,6 +59726,8 @@ var SysmlIndexManager = class extends DefaultIndexManager {
|
|
|
59067
59726
|
// REQ-068 — preserve declared visibility for wildcard re-export.
|
|
59068
59727
|
...symbol.isPrivate ? { isPrivate: true } : {},
|
|
59069
59728
|
...symbol.visibility ? { visibility: symbol.visibility } : {},
|
|
59729
|
+
// issue #152 — a re-exported alias is not owned nesting.
|
|
59730
|
+
...symbol.derivedKind ? { derivedKind: symbol.derivedKind } : {},
|
|
59070
59731
|
// REQ-242 — issue #103 — keeps type completion to definitions.
|
|
59071
59732
|
...symbol.isUsage ? { isUsage: true } : {}
|
|
59072
59733
|
};
|
|
@@ -59142,7 +59803,7 @@ function encodeUnrestrictedName(value) {
|
|
|
59142
59803
|
}
|
|
59143
59804
|
|
|
59144
59805
|
// ../language-server/out/src/services/feature-path-resolver.js
|
|
59145
|
-
var
|
|
59806
|
+
var SPECIALIZATION_KINDS2 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
59146
59807
|
function nameOf(node) {
|
|
59147
59808
|
const name = node?.name;
|
|
59148
59809
|
if (typeof name === "string" && name.length > 0)
|
|
@@ -59455,7 +60116,7 @@ var FeaturePathResolver = class {
|
|
|
59455
60116
|
const relNode = node;
|
|
59456
60117
|
const result = [];
|
|
59457
60118
|
for (const relation of [...relNode.preRelationships ?? [], ...relNode.relationships ?? []]) {
|
|
59458
|
-
if (!relation.kind || !
|
|
60119
|
+
if (!relation.kind || !SPECIALIZATION_KINDS2.has(relation.kind))
|
|
59459
60120
|
continue;
|
|
59460
60121
|
for (const target of relation.targets ?? []) {
|
|
59461
60122
|
const description = this.pickDescription(snapshot.byName.get(target)) ?? this.pickDescription(snapshot.byName.get(lastSegment2(target)));
|
|
@@ -59481,7 +60142,7 @@ var FeaturePathResolver = class {
|
|
|
59481
60142
|
const candidates = refText ? snapshot.byName.get(refText) ?? snapshot.byName.get(lastSegment2(refText)) : void 0;
|
|
59482
60143
|
return candidates?.length === 1;
|
|
59483
60144
|
}
|
|
59484
|
-
const semanticRelationships = [...record.preRelationships ?? [], ...record.relationships ?? []].filter((relation) => relation.kind &&
|
|
60145
|
+
const semanticRelationships = [...record.preRelationships ?? [], ...record.relationships ?? []].filter((relation) => relation.kind && SPECIALIZATION_KINDS2.has(relation.kind));
|
|
59485
60146
|
return semanticRelationships.length > 0 && semanticRelationships.every((relation) => (relation.targets ?? []).every((target) => Boolean(this.nodeOf(this.pickDescription(snapshot.byName.get(target))) ?? this.nodeOf(this.pickDescription(snapshot.byName.get(lastSegment2(target)))))));
|
|
59486
60147
|
}
|
|
59487
60148
|
followAlias(target, snapshot) {
|
|
@@ -59596,84 +60257,352 @@ function isNamespaceOnlyDecl(node) {
|
|
|
59596
60257
|
return node.isDef === true;
|
|
59597
60258
|
}
|
|
59598
60259
|
|
|
59599
|
-
// ../language-server/out/src/services/
|
|
59600
|
-
|
|
59601
|
-
|
|
59602
|
-
":>>",
|
|
59603
|
-
"specializes",
|
|
59604
|
-
"subsets",
|
|
59605
|
-
"redefines"
|
|
59606
|
-
]);
|
|
59607
|
-
var COMPOSITION_KINDS = /* @__PURE__ */ new Set(["unions", "intersects", "differences"]);
|
|
59608
|
-
var MAX_CLOSURE_DEPTH = 32;
|
|
59609
|
-
function simpleTypeName(name) {
|
|
59610
|
-
const last2 = name.trim().split(/::|\./u).pop() ?? name.trim();
|
|
59611
|
-
return last2.replace(/^'(.*)'$/u, "$1");
|
|
60260
|
+
// ../language-server/out/src/services/comment-body.js
|
|
60261
|
+
function sourceOf(node) {
|
|
60262
|
+
return node.$cstNode?.root.fullText;
|
|
59612
60263
|
}
|
|
59613
|
-
function
|
|
59614
|
-
|
|
59615
|
-
|
|
59616
|
-
|
|
59617
|
-
|
|
59618
|
-
|
|
59619
|
-
const conjugated = typing.conjugate === true;
|
|
59620
|
-
for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
|
|
59621
|
-
const text = ref?.$refText?.trim();
|
|
59622
|
-
if (text)
|
|
59623
|
-
out.push({ text, simple: simpleTypeName(text), conjugated });
|
|
59624
|
-
}
|
|
60264
|
+
function cleanBlockBodyLines(raw, rawOffset) {
|
|
60265
|
+
let cut = raw.length - raw.trimStart().length;
|
|
60266
|
+
let body = raw.slice(cut).trimEnd();
|
|
60267
|
+
if (body.startsWith("/*")) {
|
|
60268
|
+
body = body.slice(2);
|
|
60269
|
+
cut += 2;
|
|
59625
60270
|
}
|
|
59626
|
-
|
|
59627
|
-
|
|
59628
|
-
|
|
59629
|
-
|
|
59630
|
-
const
|
|
59631
|
-
|
|
59632
|
-
|
|
59633
|
-
|
|
59634
|
-
|
|
59635
|
-
|
|
59636
|
-
|
|
59637
|
-
|
|
59638
|
-
}
|
|
60271
|
+
if (body.endsWith("*/"))
|
|
60272
|
+
body = body.slice(0, -2);
|
|
60273
|
+
const lines = [];
|
|
60274
|
+
let cursor = cut;
|
|
60275
|
+
for (const rawLine of body.split("\n")) {
|
|
60276
|
+
const gutter = /^\s*\*+ ?/u.exec(rawLine);
|
|
60277
|
+
const skip = gutter ? gutter[0].length : 0;
|
|
60278
|
+
lines.push({
|
|
60279
|
+
text: rawLine.slice(skip).replace(/\s+$/u, ""),
|
|
60280
|
+
offset: rawOffset + cursor + skip
|
|
60281
|
+
});
|
|
60282
|
+
cursor += rawLine.length + 1;
|
|
59639
60283
|
}
|
|
59640
|
-
|
|
59641
|
-
|
|
59642
|
-
|
|
59643
|
-
|
|
59644
|
-
|
|
59645
|
-
|
|
59646
|
-
if (
|
|
59647
|
-
|
|
59648
|
-
const targets = (rel.targets ?? []).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
59649
|
-
if (targets.length > 0)
|
|
59650
|
-
out.push({ kind: rel.kind, targets });
|
|
60284
|
+
while (lines.length > 0 && lines[0].text.trim() === "")
|
|
60285
|
+
lines.shift();
|
|
60286
|
+
while (lines.length > 0 && lines[lines.length - 1].text.trim() === "")
|
|
60287
|
+
lines.pop();
|
|
60288
|
+
if (lines.length > 0) {
|
|
60289
|
+
const lead = lines[0].text.length - lines[0].text.trimStart().length;
|
|
60290
|
+
if (lead > 0)
|
|
60291
|
+
lines[0] = { text: lines[0].text.slice(lead), offset: lines[0].offset + lead };
|
|
59651
60292
|
}
|
|
59652
|
-
return
|
|
60293
|
+
return lines;
|
|
59653
60294
|
}
|
|
59654
|
-
function
|
|
59655
|
-
return (
|
|
60295
|
+
function cleanBlockBody(inner) {
|
|
60296
|
+
return cleanBlockBodyLines(inner, 0).map((line) => line.text).join("\n");
|
|
59656
60297
|
}
|
|
59657
|
-
|
|
59658
|
-
|
|
59659
|
-
|
|
59660
|
-
NumericalValue: "number",
|
|
59661
|
-
Number: "number",
|
|
59662
|
-
Integer: "number",
|
|
59663
|
-
Rational: "number",
|
|
59664
|
-
Real: "number",
|
|
59665
|
-
Complex: "number",
|
|
59666
|
-
Natural: "number",
|
|
59667
|
-
Positive: "number",
|
|
59668
|
-
Cardinal: "number"
|
|
59669
|
-
};
|
|
59670
|
-
function literalKindOf(node) {
|
|
59671
|
-
if (!node)
|
|
60298
|
+
function docCommentBody(node) {
|
|
60299
|
+
const raw = node.doc;
|
|
60300
|
+
if (typeof raw !== "string")
|
|
59672
60301
|
return void 0;
|
|
59673
|
-
|
|
59674
|
-
|
|
59675
|
-
|
|
59676
|
-
|
|
60302
|
+
const start = raw.indexOf("/*");
|
|
60303
|
+
const end = raw.lastIndexOf("*/");
|
|
60304
|
+
if (start < 0 || end < start)
|
|
60305
|
+
return void 0;
|
|
60306
|
+
const body = cleanBlockBody(raw.slice(start, end + 2));
|
|
60307
|
+
return body.length > 0 ? body : void 0;
|
|
60308
|
+
}
|
|
60309
|
+
function trailingBlockBodySpan(node) {
|
|
60310
|
+
const cst = node.$cstNode;
|
|
60311
|
+
const text = sourceOf(node);
|
|
60312
|
+
if (!cst || text === void 0)
|
|
60313
|
+
return void 0;
|
|
60314
|
+
const rest = text.slice(cst.end);
|
|
60315
|
+
const open = rest.indexOf("/*");
|
|
60316
|
+
if (open < 0)
|
|
60317
|
+
return void 0;
|
|
60318
|
+
if (rest.slice(0, open).trim() !== "")
|
|
60319
|
+
return void 0;
|
|
60320
|
+
const close = rest.indexOf("*/", open + 2);
|
|
60321
|
+
if (close < 0)
|
|
60322
|
+
return void 0;
|
|
60323
|
+
const raw = rest.slice(open, close + 2);
|
|
60324
|
+
const lines = cleanBlockBodyLines(raw, cst.end + open);
|
|
60325
|
+
const body = lines.map((line) => line.text).join("\n");
|
|
60326
|
+
if (body.length === 0)
|
|
60327
|
+
return void 0;
|
|
60328
|
+
return { text: body, lines, open: cst.end + open, close: cst.end + close + 2 };
|
|
60329
|
+
}
|
|
60330
|
+
function trailingBlockBody(node) {
|
|
60331
|
+
return trailingBlockBodySpan(node)?.text;
|
|
60332
|
+
}
|
|
60333
|
+
function bodyOffsetAt(span, line, character) {
|
|
60334
|
+
const entry = Number.isInteger(line) ? span.lines[line] : void 0;
|
|
60335
|
+
if (!entry)
|
|
60336
|
+
return span.open;
|
|
60337
|
+
const column = Number.isFinite(character) ? character : 0;
|
|
60338
|
+
return entry.offset + Math.max(0, Math.min(column, entry.text.length));
|
|
60339
|
+
}
|
|
60340
|
+
|
|
60341
|
+
// ../language-server/out/src/services/embedded-representation.js
|
|
60342
|
+
var EMBEDDED_LANGUAGES = /* @__PURE__ */ new Set(["sysml", "kerml"]);
|
|
60343
|
+
var EXPRESSION_VALUED_OWNERS = /* @__PURE__ */ new Set([
|
|
60344
|
+
"AssertConstraintStmt",
|
|
60345
|
+
"AssumeConstraintStmt",
|
|
60346
|
+
"RequireConstraintStmt",
|
|
60347
|
+
"ConstraintDecl",
|
|
60348
|
+
"InvShorthand",
|
|
60349
|
+
"CalcDecl",
|
|
60350
|
+
"ExpressionDecl"
|
|
60351
|
+
]);
|
|
60352
|
+
function isEmbeddedLanguage(raw) {
|
|
60353
|
+
if (typeof raw !== "string")
|
|
60354
|
+
return false;
|
|
60355
|
+
return EMBEDDED_LANGUAGES.has(raw.replace(/^"|"$/gu, "").trim().toLowerCase());
|
|
60356
|
+
}
|
|
60357
|
+
function bareName(node) {
|
|
60358
|
+
const name = node?.name;
|
|
60359
|
+
return typeof name === "string" && name.length > 0 ? name.replace(/^'|'$/gu, "") : void 0;
|
|
60360
|
+
}
|
|
60361
|
+
function kindOf(node) {
|
|
60362
|
+
const decl = /^([A-Z][a-z]+)Decl$/.exec(node.$type);
|
|
60363
|
+
if (decl) {
|
|
60364
|
+
const base = decl[1].toLowerCase();
|
|
60365
|
+
return node.isDef ? `${base} def` : base;
|
|
60366
|
+
}
|
|
60367
|
+
switch (node.$type) {
|
|
60368
|
+
case "Package":
|
|
60369
|
+
return "package";
|
|
60370
|
+
case "InvShorthand":
|
|
60371
|
+
return "inv";
|
|
60372
|
+
case "AssertConstraintStmt":
|
|
60373
|
+
return "assert constraint";
|
|
60374
|
+
case "AssumeConstraintStmt":
|
|
60375
|
+
return "assume constraint";
|
|
60376
|
+
case "RequireConstraintStmt":
|
|
60377
|
+
return "require constraint";
|
|
60378
|
+
default:
|
|
60379
|
+
return node.$type;
|
|
60380
|
+
}
|
|
60381
|
+
}
|
|
60382
|
+
function hasErrors(result) {
|
|
60383
|
+
return result.lexerErrors.length > 0 || result.parserErrors.length > 0;
|
|
60384
|
+
}
|
|
60385
|
+
function describeParserError(error) {
|
|
60386
|
+
const image = error.token?.image ?? "";
|
|
60387
|
+
const expecting = /Expecting token of type '([^']+)'/u.exec(error.message ?? "");
|
|
60388
|
+
if (image === "") {
|
|
60389
|
+
return expecting ? `the body ends while '${expecting[1]}' is still expected.` : "the body ends before it is complete.";
|
|
60390
|
+
}
|
|
60391
|
+
if (error.name === "NotAllInputParsedException") {
|
|
60392
|
+
return `'${image}' is left over after the representation is already complete.`;
|
|
60393
|
+
}
|
|
60394
|
+
if (expecting)
|
|
60395
|
+
return `expected '${expecting[1]}' but found '${image}'.`;
|
|
60396
|
+
return `unexpected '${image}'.`;
|
|
60397
|
+
}
|
|
60398
|
+
function describeLexerError(error) {
|
|
60399
|
+
const character = /unexpected character: ->(.*?)<-/u.exec(error.message ?? "");
|
|
60400
|
+
return character ? `unexpected character '${character[1]}'.` : error.message ?? "the body cannot be read.";
|
|
60401
|
+
}
|
|
60402
|
+
function failureOf(result, span) {
|
|
60403
|
+
const endLine = Math.max(0, span.lines.length - 1);
|
|
60404
|
+
const end = { line: endLine, character: span.lines[endLine]?.text.length ?? 0 };
|
|
60405
|
+
const lexical = result.lexerErrors[0];
|
|
60406
|
+
const syntactic = result.parserErrors[0];
|
|
60407
|
+
if (lexical && Number.isFinite(lexical.line)) {
|
|
60408
|
+
return {
|
|
60409
|
+
line: lexical.line - 1,
|
|
60410
|
+
character: Math.max(0, (Number.isFinite(lexical.column) ? lexical.column : 1) - 1),
|
|
60411
|
+
message: describeLexerError(lexical)
|
|
60412
|
+
};
|
|
60413
|
+
}
|
|
60414
|
+
if (syntactic) {
|
|
60415
|
+
const token = syntactic.token;
|
|
60416
|
+
const message = describeParserError(syntactic);
|
|
60417
|
+
if (Number.isFinite(token?.startLine) && Number.isFinite(token?.startColumn)) {
|
|
60418
|
+
return { line: token.startLine - 1, character: token.startColumn - 1, message };
|
|
60419
|
+
}
|
|
60420
|
+
return { ...end, message };
|
|
60421
|
+
}
|
|
60422
|
+
return { ...end, message: lexical ? describeLexerError(lexical) : "the body is not valid SysML." };
|
|
60423
|
+
}
|
|
60424
|
+
function conformance(parsed, owner) {
|
|
60425
|
+
if (!parsed || !owner || owner.$type === "Document")
|
|
60426
|
+
return { status: "ok" };
|
|
60427
|
+
const sameKind = parsed.$type === owner.$type && Boolean(parsed.isDef) === Boolean(owner.isDef);
|
|
60428
|
+
if (!sameKind) {
|
|
60429
|
+
return { status: "mismatch", mismatch: { reason: "kind", expected: kindOf(owner), actual: kindOf(parsed) } };
|
|
60430
|
+
}
|
|
60431
|
+
const expected = bareName(owner);
|
|
60432
|
+
const actual = bareName(parsed);
|
|
60433
|
+
if (expected && actual && expected !== actual) {
|
|
60434
|
+
return { status: "mismatch", mismatch: { reason: "name", expected, actual } };
|
|
60435
|
+
}
|
|
60436
|
+
return { status: "ok" };
|
|
60437
|
+
}
|
|
60438
|
+
function nodesOf(root3) {
|
|
60439
|
+
return [root3, ...ast_utils_exports.streamAllContents(root3)];
|
|
60440
|
+
}
|
|
60441
|
+
function declaredNames(root3) {
|
|
60442
|
+
const names = /* @__PURE__ */ new Set();
|
|
60443
|
+
for (const node of nodesOf(root3)) {
|
|
60444
|
+
const name = node.name;
|
|
60445
|
+
if (typeof name === "string" && name.length > 0)
|
|
60446
|
+
names.add(name.replace(/^'|'$/gu, ""));
|
|
60447
|
+
}
|
|
60448
|
+
return names;
|
|
60449
|
+
}
|
|
60450
|
+
function graftInto(fragment, owner) {
|
|
60451
|
+
const mutable = fragment;
|
|
60452
|
+
mutable.$container = owner;
|
|
60453
|
+
mutable.$containerProperty = "members";
|
|
60454
|
+
}
|
|
60455
|
+
function firstSegment(refText) {
|
|
60456
|
+
return (refText.split("::")[0] ?? refText).replace(/^'|'$/gu, "").trim();
|
|
60457
|
+
}
|
|
60458
|
+
function unresolvedReferences(fragment, owner) {
|
|
60459
|
+
graftInto(fragment, owner);
|
|
60460
|
+
const own = declaredNames(fragment);
|
|
60461
|
+
const out = [];
|
|
60462
|
+
for (const node of nodesOf(fragment)) {
|
|
60463
|
+
for (const [property3, value] of Object.entries(node)) {
|
|
60464
|
+
if (property3.startsWith("$"))
|
|
60465
|
+
continue;
|
|
60466
|
+
for (const candidate of Array.isArray(value) ? value : [value]) {
|
|
60467
|
+
if (!isReference(candidate))
|
|
60468
|
+
continue;
|
|
60469
|
+
const reference = candidate;
|
|
60470
|
+
const refText = reference.$refText;
|
|
60471
|
+
if (!refText || own.has(firstSegment(refText)))
|
|
60472
|
+
continue;
|
|
60473
|
+
let resolved;
|
|
60474
|
+
try {
|
|
60475
|
+
resolved = reference.ref;
|
|
60476
|
+
} catch {
|
|
60477
|
+
return [];
|
|
60478
|
+
}
|
|
60479
|
+
if (resolved)
|
|
60480
|
+
continue;
|
|
60481
|
+
const range = reference.$refNode?.range;
|
|
60482
|
+
if (!range)
|
|
60483
|
+
continue;
|
|
60484
|
+
out.push({
|
|
60485
|
+
refText,
|
|
60486
|
+
line: range.start.line,
|
|
60487
|
+
character: range.start.character,
|
|
60488
|
+
length: Math.max(1, range.end.character - range.start.character)
|
|
60489
|
+
});
|
|
60490
|
+
}
|
|
60491
|
+
}
|
|
60492
|
+
}
|
|
60493
|
+
return out;
|
|
60494
|
+
}
|
|
60495
|
+
function evaluateRepresentation(parser, rep) {
|
|
60496
|
+
if (!isEmbeddedLanguage(rep.language))
|
|
60497
|
+
return void 0;
|
|
60498
|
+
const span = trailingBlockBodySpan(rep);
|
|
60499
|
+
if (!span)
|
|
60500
|
+
return void 0;
|
|
60501
|
+
const owner = rep.$container;
|
|
60502
|
+
const context = owner && owner.$type !== "Document" ? owner : void 0;
|
|
60503
|
+
const declaration = parser.parse(span.text, { rule: "NamespaceElement" });
|
|
60504
|
+
if (!hasErrors(declaration)) {
|
|
60505
|
+
return {
|
|
60506
|
+
span,
|
|
60507
|
+
verdict: conformance(declaration.value, owner),
|
|
60508
|
+
unresolved: context ? unresolvedReferences(declaration.value, context) : [],
|
|
60509
|
+
fragment: declaration.value,
|
|
60510
|
+
tier: "declaration"
|
|
60511
|
+
};
|
|
60512
|
+
}
|
|
60513
|
+
if (owner && EXPRESSION_VALUED_OWNERS.has(owner.$type)) {
|
|
60514
|
+
const expression = parser.parse(span.text, { rule: "Expr" });
|
|
60515
|
+
if (!hasErrors(expression)) {
|
|
60516
|
+
return {
|
|
60517
|
+
span,
|
|
60518
|
+
verdict: { status: "ok" },
|
|
60519
|
+
unresolved: context ? unresolvedReferences(expression.value, context) : [],
|
|
60520
|
+
fragment: expression.value,
|
|
60521
|
+
tier: "expression"
|
|
60522
|
+
};
|
|
60523
|
+
}
|
|
60524
|
+
}
|
|
60525
|
+
return { span, verdict: { status: "unparsed", failure: failureOf(declaration, span) }, unresolved: [] };
|
|
60526
|
+
}
|
|
60527
|
+
|
|
60528
|
+
// ../language-server/out/src/services/conformance.js
|
|
60529
|
+
var SPECIALIZATION_KINDS3 = /* @__PURE__ */ new Set([
|
|
60530
|
+
":>",
|
|
60531
|
+
":>>",
|
|
60532
|
+
"specializes",
|
|
60533
|
+
"subsets",
|
|
60534
|
+
"redefines"
|
|
60535
|
+
]);
|
|
60536
|
+
var COMPOSITION_KINDS = /* @__PURE__ */ new Set(["unions", "intersects", "differences"]);
|
|
60537
|
+
var MAX_CLOSURE_DEPTH = 32;
|
|
60538
|
+
function simpleTypeName(name) {
|
|
60539
|
+
const last2 = name.trim().split(/::|\./u).pop() ?? name.trim();
|
|
60540
|
+
return last2.replace(/^'(.*)'$/u, "$1");
|
|
60541
|
+
}
|
|
60542
|
+
function declaredTypesOf(node) {
|
|
60543
|
+
const decl = node;
|
|
60544
|
+
const out = [];
|
|
60545
|
+
for (const typing of [decl.typing, ...decl.moreTypings ?? []]) {
|
|
60546
|
+
if (!typing)
|
|
60547
|
+
continue;
|
|
60548
|
+
const conjugated = typing.conjugate === true;
|
|
60549
|
+
for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
|
|
60550
|
+
const text = ref?.$refText?.trim();
|
|
60551
|
+
if (text)
|
|
60552
|
+
out.push({ text, simple: simpleTypeName(text), conjugated });
|
|
60553
|
+
}
|
|
60554
|
+
}
|
|
60555
|
+
return out;
|
|
60556
|
+
}
|
|
60557
|
+
function specializedNamesOf(node) {
|
|
60558
|
+
const decl = node;
|
|
60559
|
+
const out = [];
|
|
60560
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
60561
|
+
if (!rel.kind || !SPECIALIZATION_KINDS3.has(rel.kind))
|
|
60562
|
+
continue;
|
|
60563
|
+
for (const target of rel.targets ?? []) {
|
|
60564
|
+
const text = target.trim();
|
|
60565
|
+
if (text)
|
|
60566
|
+
out.push(text);
|
|
60567
|
+
}
|
|
60568
|
+
}
|
|
60569
|
+
return out;
|
|
60570
|
+
}
|
|
60571
|
+
function compositionGroupsOf(node) {
|
|
60572
|
+
const decl = node;
|
|
60573
|
+
const out = [];
|
|
60574
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
60575
|
+
if (!rel.kind || !COMPOSITION_KINDS.has(rel.kind))
|
|
60576
|
+
continue;
|
|
60577
|
+
const targets = (rel.targets ?? []).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
60578
|
+
if (targets.length > 0)
|
|
60579
|
+
out.push({ kind: rel.kind, targets });
|
|
60580
|
+
}
|
|
60581
|
+
return out;
|
|
60582
|
+
}
|
|
60583
|
+
function isAbstractDecl(node) {
|
|
60584
|
+
return (node.modifiers ?? []).includes("abstract");
|
|
60585
|
+
}
|
|
60586
|
+
var SCALAR_ROOT_KINDS = {
|
|
60587
|
+
String: "string",
|
|
60588
|
+
Boolean: "boolean",
|
|
60589
|
+
NumericalValue: "number",
|
|
60590
|
+
Number: "number",
|
|
60591
|
+
Integer: "number",
|
|
60592
|
+
Rational: "number",
|
|
60593
|
+
Real: "number",
|
|
60594
|
+
Complex: "number",
|
|
60595
|
+
Natural: "number",
|
|
60596
|
+
Positive: "number",
|
|
60597
|
+
Cardinal: "number"
|
|
60598
|
+
};
|
|
60599
|
+
function literalKindOf(node) {
|
|
60600
|
+
if (!node)
|
|
60601
|
+
return void 0;
|
|
60602
|
+
switch (node.$type) {
|
|
60603
|
+
case "LiteralStr":
|
|
60604
|
+
return "string";
|
|
60605
|
+
case "LiteralBool":
|
|
59677
60606
|
return "boolean";
|
|
59678
60607
|
case "NumericPrimary":
|
|
59679
60608
|
return "number";
|
|
@@ -59944,7 +60873,7 @@ function maskNonCode(text) {
|
|
|
59944
60873
|
}
|
|
59945
60874
|
return out.join("");
|
|
59946
60875
|
}
|
|
59947
|
-
var
|
|
60876
|
+
var SPECIALIZATION_KINDS4 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
59948
60877
|
var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
|
|
59949
60878
|
"AssignNode",
|
|
59950
60879
|
"SendNode",
|
|
@@ -60034,7 +60963,14 @@ var SysmlValidator = class _SysmlValidator {
|
|
|
60034
60963
|
langiumDocuments;
|
|
60035
60964
|
astNodeLocator;
|
|
60036
60965
|
featurePaths;
|
|
60966
|
+
// REQ-396 — One SysmlValidator instance is registered against BOTH the SysML and
|
|
60967
|
+
// the KerML services (sysml-module.ts), so the parser used to read an embedded
|
|
60968
|
+
// representation is looked up from the document being validated rather than
|
|
60969
|
+
// captured here. The two share one grammar today; this keeps that from becoming
|
|
60970
|
+
// load-bearing.
|
|
60971
|
+
serviceRegistry;
|
|
60037
60972
|
constructor(services) {
|
|
60973
|
+
this.serviceRegistry = services.shared.ServiceRegistry;
|
|
60038
60974
|
this.indexManager = services.shared.workspace.IndexManager;
|
|
60039
60975
|
this.langiumDocuments = services.shared.workspace.LangiumDocuments;
|
|
60040
60976
|
this.astNodeLocator = services.workspace.AstNodeLocator;
|
|
@@ -60050,23 +60986,38 @@ var SysmlValidator = class _SysmlValidator {
|
|
|
60050
60986
|
// Langium linker cannot diagnose a missing intermediate feature. Resolve the
|
|
60051
60987
|
// chain here and underline only the first invalid segment.
|
|
60052
60988
|
checkPathExpr(node, accept) {
|
|
60989
|
+
const fault = this.featurePathFault(node);
|
|
60990
|
+
if (!fault)
|
|
60991
|
+
return;
|
|
60992
|
+
accept(severity("RES001", "error"), DIAGNOSTIC_MESSAGES.RES001_FEATURE_PATH_SEGMENT(fault.segment, fault.owner), {
|
|
60993
|
+
node,
|
|
60994
|
+
range: fault.range,
|
|
60995
|
+
code: "RES001",
|
|
60996
|
+
data: { featurePathSegment: true }
|
|
60997
|
+
});
|
|
60998
|
+
}
|
|
60999
|
+
// REQ-317, REQ-396 — The one place that decides whether a written feature path
|
|
61000
|
+
// has a provably absent segment. Extracted so an embedded representation body is
|
|
61001
|
+
// judged by exactly this rule (issue #150 review): a body is grafted onto the
|
|
61002
|
+
// element it represents and is therefore unreachable from the document walk that
|
|
61003
|
+
// dispatches `checkPathExpr`, so without a shared decision the two would drift
|
|
61004
|
+
// and a body would quietly escape a diagnostic the surrounding model receives.
|
|
61005
|
+
featurePathFault(node) {
|
|
60053
61006
|
let declaration = node.$container;
|
|
60054
61007
|
while (declaration && !isPartDecl(declaration))
|
|
60055
61008
|
declaration = declaration.$container;
|
|
60056
61009
|
const modifiers2 = declaration?.modifiers ?? [];
|
|
60057
61010
|
if (!declaration || !modifiers2.includes("ref"))
|
|
60058
|
-
return;
|
|
61011
|
+
return void 0;
|
|
60059
61012
|
const resolution = this.featurePaths.resolve(node);
|
|
60060
61013
|
if (resolution.unresolvedIndex === void 0)
|
|
60061
|
-
return;
|
|
61014
|
+
return void 0;
|
|
60062
61015
|
const invalid = resolution.segments[resolution.unresolvedIndex];
|
|
60063
|
-
|
|
60064
|
-
|
|
60065
|
-
|
|
60066
|
-
range: invalid.cst.range
|
|
60067
|
-
|
|
60068
|
-
data: { featurePathSegment: true }
|
|
60069
|
-
});
|
|
61016
|
+
return {
|
|
61017
|
+
segment: invalid.text,
|
|
61018
|
+
owner: resolution.unresolvedIndex > 0 ? resolution.segments[resolution.unresolvedIndex - 1].text : "the current scope",
|
|
61019
|
+
range: invalid.cst.range
|
|
61020
|
+
};
|
|
60070
61021
|
}
|
|
60071
61022
|
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
60072
61023
|
// issue #213 — RES019: `::` binds tighter than `.`. Each dot-separated link of
|
|
@@ -60254,10 +61205,13 @@ var SysmlValidator = class _SysmlValidator {
|
|
|
60254
61205
|
if (!node.visibility) {
|
|
60255
61206
|
accept(severity("SYN067", "error"), "Import visibility is required by the Release syntax; use 'private import' unless re-export is intended.", { node, code: "SYN067" });
|
|
60256
61207
|
}
|
|
61208
|
+
if (node.visibility && node.visibility !== "private" && node.$container?.$type === "Document") {
|
|
61209
|
+
accept(severity("RES021", "error"), DIAGNOSTIC_MESSAGES.RES021_ROOT_IMPORT_VISIBILITY(node.visibility), { node, property: "visibility", code: "RES021" });
|
|
61210
|
+
}
|
|
60257
61211
|
const headStr = node.head ?? "";
|
|
60258
61212
|
const segsStr = node.segs.map((s) => {
|
|
60259
61213
|
if (s.recursive)
|
|
60260
|
-
return "::**";
|
|
61214
|
+
return s.star ? "::*::**" : "::**";
|
|
60261
61215
|
if (s.star)
|
|
60262
61216
|
return "::*";
|
|
60263
61217
|
return `::${s.name ?? ""}`;
|
|
@@ -60297,6 +61251,7 @@ var SysmlValidator = class _SysmlValidator {
|
|
|
60297
61251
|
this.checkConnectorForms(node, accept);
|
|
60298
61252
|
this.checkActionStartSuccessions(node, accept);
|
|
60299
61253
|
this.checkAnnotationForms(node, accept);
|
|
61254
|
+
this.checkEmbeddedRepresentations(node, accept);
|
|
60300
61255
|
this.checkLanguageDisjointness(node, accept);
|
|
60301
61256
|
this.checkKermlWellFormedness(node, accept);
|
|
60302
61257
|
this.checkFilterExpressions(node, accept);
|
|
@@ -60637,6 +61592,132 @@ ${baseIndent}}`;
|
|
|
60637
61592
|
}
|
|
60638
61593
|
}
|
|
60639
61594
|
}
|
|
61595
|
+
// REQ-396 — SYN076/SEM012 embedded textual representations (issue #150).
|
|
61596
|
+
// A `rep … language "sysml"` (or `"kerml"`, matched case-insensitively) is not
|
|
61597
|
+
// opaque content: OMG KerML §7.4.3 requires its body to be a legal representation
|
|
61598
|
+
// of the element it annotates. So the body is processed by the comment-body rules,
|
|
61599
|
+
// parsed, and compared against that element:
|
|
61600
|
+
// SYN076 — the body is not valid SysML, reported ON the offending character
|
|
61601
|
+
// inside the body rather than on the `rep` keyword.
|
|
61602
|
+
// SEM012 — the body parses but represents a different element (wrong kind, or
|
|
61603
|
+
// the right kind under a different name).
|
|
61604
|
+
// Every other language stays opaque and is never parsed — an `alf`, `ocl` or
|
|
61605
|
+
// `yaml` body is content, and the vendored OMG corpus holds only those.
|
|
61606
|
+
checkEmbeddedRepresentations(node, accept) {
|
|
61607
|
+
const doc = ast_utils_exports.getDocument(node);
|
|
61608
|
+
if (!doc?.textDocument)
|
|
61609
|
+
return;
|
|
61610
|
+
let parser;
|
|
61611
|
+
for (const child of ast_utils_exports.streamAllContents(node)) {
|
|
61612
|
+
if (child.$type !== "RepStmt")
|
|
61613
|
+
continue;
|
|
61614
|
+
if (!isEmbeddedLanguage(child.language))
|
|
61615
|
+
continue;
|
|
61616
|
+
parser ??= this.serviceRegistry.getServices(doc.uri).parser.LangiumParser;
|
|
61617
|
+
const evaluated = evaluateRepresentation(parser, child);
|
|
61618
|
+
if (!evaluated)
|
|
61619
|
+
continue;
|
|
61620
|
+
const { span, verdict } = evaluated;
|
|
61621
|
+
const language = String(child.language ?? "").replace(/^"|"$/gu, "");
|
|
61622
|
+
if (verdict.status === "unparsed") {
|
|
61623
|
+
const { line, character, message } = verdict.failure;
|
|
61624
|
+
const anchor = bodyOffsetAt(span, line, character);
|
|
61625
|
+
const after = bodyOffsetAt(span, line, character + 1);
|
|
61626
|
+
const from = after > anchor ? anchor : bodyOffsetAt(span, line, Math.max(0, character - 1));
|
|
61627
|
+
accept(severity("SYN076", "error"), DIAGNOSTIC_MESSAGES.SYN076_EMBEDDED_REPRESENTATION_SYNTAX(language, message), {
|
|
61628
|
+
node: child,
|
|
61629
|
+
range: {
|
|
61630
|
+
start: doc.textDocument.positionAt(from),
|
|
61631
|
+
end: doc.textDocument.positionAt(Math.max(after, anchor))
|
|
61632
|
+
},
|
|
61633
|
+
code: "SYN076"
|
|
61634
|
+
});
|
|
61635
|
+
continue;
|
|
61636
|
+
}
|
|
61637
|
+
for (const reference of evaluated.unresolved) {
|
|
61638
|
+
accept(severity("RES020", "warning"), DIAGNOSTIC_MESSAGES.RES020_REPRESENTATION_UNRESOLVED(reference.refText, language), {
|
|
61639
|
+
node: child,
|
|
61640
|
+
range: {
|
|
61641
|
+
start: doc.textDocument.positionAt(bodyOffsetAt(span, reference.line, reference.character)),
|
|
61642
|
+
end: doc.textDocument.positionAt(bodyOffsetAt(span, reference.line, reference.character + reference.length))
|
|
61643
|
+
},
|
|
61644
|
+
code: "RES020"
|
|
61645
|
+
});
|
|
61646
|
+
}
|
|
61647
|
+
if (evaluated.fragment) {
|
|
61648
|
+
this.checkEmbeddedDialect(child, evaluated.fragment, language, span, doc, accept);
|
|
61649
|
+
this.checkEmbeddedFeaturePaths(child, evaluated.fragment, language, span, doc, accept);
|
|
61650
|
+
}
|
|
61651
|
+
if (verdict.status === "ok")
|
|
61652
|
+
continue;
|
|
61653
|
+
const { reason, expected, actual } = verdict.mismatch;
|
|
61654
|
+
const owner = child.$container;
|
|
61655
|
+
accept(severity("SEM012", "warning"), reason === "kind" ? DIAGNOSTIC_MESSAGES.SEM012_REPRESENTATION_WRONG_KIND(expected, actual) : DIAGNOSTIC_MESSAGES.SEM012_REPRESENTATION_WRONG_NAME(expected, actual), {
|
|
61656
|
+
node: child,
|
|
61657
|
+
range: {
|
|
61658
|
+
start: doc.textDocument.positionAt(bodyOffsetAt(span, 0, 0)),
|
|
61659
|
+
end: doc.textDocument.positionAt(bodyOffsetAt(span, 0, span.lines[0]?.text.length ?? 0))
|
|
61660
|
+
},
|
|
61661
|
+
code: "SEM012",
|
|
61662
|
+
relatedInformation: owner ? [relatedInfo(owner, "The element this representation annotates.")].filter((info) => info !== void 0) : void 0
|
|
61663
|
+
});
|
|
61664
|
+
}
|
|
61665
|
+
}
|
|
61666
|
+
// REQ-396 — SYN100/SYN101 inside a representation body (issue #150 review).
|
|
61667
|
+
// The normative rule is that the body is legal in the language the representation
|
|
61668
|
+
// NAMES, which is not the language of the file it sits in: a `.sysml` file may
|
|
61669
|
+
// carry a `language "kerml"` representation, and its body may then use no
|
|
61670
|
+
// SysML-only construct. `checkLanguageDisjointness` answers a different question
|
|
61671
|
+
// — what may this FILE contain — from the host URI, so the same tables are read
|
|
61672
|
+
// here against the declared language instead.
|
|
61673
|
+
checkEmbeddedDialect(rep, fragment, language, span, doc, accept) {
|
|
61674
|
+
const dialect = language.trim().toLowerCase();
|
|
61675
|
+
const isKerml = dialect === "kerml";
|
|
61676
|
+
const forbidden = isKerml ? SYSML_ONLY_TYPES : KERML_ONLY_TYPES;
|
|
61677
|
+
const code = isKerml ? "SYN100" : "SYN101";
|
|
61678
|
+
for (const node of [fragment, ...ast_utils_exports.streamAllContents(fragment)]) {
|
|
61679
|
+
if (!forbidden.has(node.$type))
|
|
61680
|
+
continue;
|
|
61681
|
+
const range = node.$cstNode?.range;
|
|
61682
|
+
if (!range)
|
|
61683
|
+
continue;
|
|
61684
|
+
accept(severity(code, "error"), isKerml ? `'${declKeyword(node)}' is a SysML construct and is not available in a "${language}" representation.` : `'${declKeyword(node)}' is a KerML-only construct \u2014 use the SysML form in a "${language}" representation.`, {
|
|
61685
|
+
node: rep,
|
|
61686
|
+
range: this.bodyRange(span, doc, range),
|
|
61687
|
+
code
|
|
61688
|
+
});
|
|
61689
|
+
}
|
|
61690
|
+
}
|
|
61691
|
+
// REQ-396 — RES020 for a written feature path with a provably absent segment
|
|
61692
|
+
// (issue #150 review). `checkPathExpr` is registered as a node-level check, so
|
|
61693
|
+
// Langium dispatches it by walking the document AST and never reaches the grafted
|
|
61694
|
+
// fragment. The decision itself is shared with it through `featurePathFault`, so
|
|
61695
|
+
// a body is held to the same rule as the model around it rather than a parallel
|
|
61696
|
+
// one that could drift; only the code differs, keeping every fault found IN a
|
|
61697
|
+
// representation body under the one severity a team can tune.
|
|
61698
|
+
checkEmbeddedFeaturePaths(rep, fragment, language, span, doc, accept) {
|
|
61699
|
+
for (const node of [fragment, ...ast_utils_exports.streamAllContents(fragment)]) {
|
|
61700
|
+
if (!this.featurePaths.isPathExpr(node))
|
|
61701
|
+
continue;
|
|
61702
|
+
const fault = this.featurePathFault(node);
|
|
61703
|
+
if (!fault)
|
|
61704
|
+
continue;
|
|
61705
|
+
accept(severity("RES020", "warning"), DIAGNOSTIC_MESSAGES.RES020_REPRESENTATION_PATH_SEGMENT(fault.segment, fault.owner, language), {
|
|
61706
|
+
node: rep,
|
|
61707
|
+
range: this.bodyRange(span, doc, fault.range),
|
|
61708
|
+
code: "RES020"
|
|
61709
|
+
});
|
|
61710
|
+
}
|
|
61711
|
+
}
|
|
61712
|
+
// REQ-396 — A range inside a parsed body, expressed in document coordinates.
|
|
61713
|
+
// Fragment CST positions are line/character within the PROCESSED body, which is
|
|
61714
|
+
// exactly what the span's line table converts.
|
|
61715
|
+
bodyRange(span, doc, range) {
|
|
61716
|
+
return {
|
|
61717
|
+
start: doc.textDocument.positionAt(bodyOffsetAt(span, range.start.line, range.start.character)),
|
|
61718
|
+
end: doc.textDocument.positionAt(bodyOffsetAt(span, range.end.line, range.end.character))
|
|
61719
|
+
};
|
|
61720
|
+
}
|
|
60640
61721
|
// REQ-311 — SYN050/051 connector syntax, with a specific message in place of
|
|
60641
61722
|
// the grammar's generic parse error:
|
|
60642
61723
|
// SYN050 — `connect a with b;` (use `connect a to b;`).
|
|
@@ -61146,6 +62227,7 @@ ${baseIndent}}`;
|
|
|
61146
62227
|
const index = this.buildIndex();
|
|
61147
62228
|
const imports = [];
|
|
61148
62229
|
const exposePaths = [];
|
|
62230
|
+
const filterMembers = [];
|
|
61149
62231
|
const decls = [];
|
|
61150
62232
|
const verifyStmts = [];
|
|
61151
62233
|
const satisfyStmts = [];
|
|
@@ -61159,6 +62241,8 @@ ${baseIndent}}`;
|
|
|
61159
62241
|
aliasMap.set(alias, path10);
|
|
61160
62242
|
} else if (isExposePath(child))
|
|
61161
62243
|
exposePaths.push(child);
|
|
62244
|
+
else if (child.$type === "FilterMember")
|
|
62245
|
+
filterMembers.push(child);
|
|
61162
62246
|
else if (isVerifyStmt(child))
|
|
61163
62247
|
verifyStmts.push(child);
|
|
61164
62248
|
else if (isSatisfyStmt(child))
|
|
@@ -61175,7 +62259,7 @@ ${baseIndent}}`;
|
|
|
61175
62259
|
this.checkPrivateImports(imports, index, accept);
|
|
61176
62260
|
this.checkPrivateWildcardReferences(node, imports, index, accept);
|
|
61177
62261
|
this.checkImportCycles(imports, index, accept);
|
|
61178
|
-
this.checkUnevaluatedFilters(imports, exposePaths, accept);
|
|
62262
|
+
this.checkUnevaluatedFilters(imports, exposePaths, filterMembers, index, accept);
|
|
61179
62263
|
if (sysmlDiagnosticSettings.unusedImports !== "off") {
|
|
61180
62264
|
this.checkUnusedImports(node, imports, index, sysmlDiagnosticSettings.unusedImports, accept);
|
|
61181
62265
|
}
|
|
@@ -61603,6 +62687,10 @@ ${baseIndent}}`;
|
|
|
61603
62687
|
if (condition && isDefinitelyNonBoolean(condition)) {
|
|
61604
62688
|
accept(severity("KSM008", "error"), "A filter condition must be a Boolean expression.", { node: child, code: "KSM008" });
|
|
61605
62689
|
}
|
|
62690
|
+
const owner = child.$container;
|
|
62691
|
+
if (owner && !isFilterHost(owner)) {
|
|
62692
|
+
accept(severity("KSM012", "error"), DIAGNOSTIC_MESSAGES.KSM012_FILTER_PLACEMENT(kindLabel(owner)), { node: child, code: "KSM012" });
|
|
62693
|
+
}
|
|
61606
62694
|
}
|
|
61607
62695
|
}
|
|
61608
62696
|
// REQ-328 — KSM006: a type-composition `unions`/`intersects`/`differences`
|
|
@@ -61892,7 +62980,8 @@ ${baseIndent}}`;
|
|
|
61892
62980
|
const node = this.resolveUnique(nsName, index);
|
|
61893
62981
|
const ownsNamespace = node !== void 0 && (isPackage(node) || node.$type === "NamespaceDecl" || (node.members?.length ?? 0) > 0);
|
|
61894
62982
|
if (node && !ownsNamespace) {
|
|
61895
|
-
|
|
62983
|
+
const written = imp.segs.some((s) => s.recursive && s.star) ? `${nsName}::*::**` : `${nsName}::**`;
|
|
62984
|
+
accept(severity("RES007", "error"), `Recursive import '${written}' requires '${nsName}' to be a package, namespace, or usage that owns nested members.`, { node: imp, code: "RES007" });
|
|
61896
62985
|
}
|
|
61897
62986
|
}
|
|
61898
62987
|
// REQ-323 — RES008: an `alias … for X` whose target `X` does not resolve.
|
|
@@ -62019,6 +63108,8 @@ ${baseIndent}}`;
|
|
|
62019
63108
|
// REQ-320 — RES004 importing a private element from outside its namespace
|
|
62020
63109
|
checkPrivateImports(imports, index, accept) {
|
|
62021
63110
|
for (const imp of imports) {
|
|
63111
|
+
if (importForm(imp).importAll)
|
|
63112
|
+
continue;
|
|
62022
63113
|
const path10 = importedPath(imp);
|
|
62023
63114
|
if (!path10)
|
|
62024
63115
|
continue;
|
|
@@ -62041,13 +63132,15 @@ ${baseIndent}}`;
|
|
|
62041
63132
|
// reference so the user learns why a `Pkg::*` did not bring it in.
|
|
62042
63133
|
checkPrivateWildcardReferences(node, imports, index, accept) {
|
|
62043
63134
|
const wildcards = [];
|
|
63135
|
+
const importAllPaths = [];
|
|
62044
63136
|
for (const imp of imports) {
|
|
62045
|
-
const
|
|
62046
|
-
if (
|
|
63137
|
+
const form = importForm(imp);
|
|
63138
|
+
if (form.wildcard === "none")
|
|
62047
63139
|
continue;
|
|
62048
63140
|
const path10 = importedPath(imp);
|
|
62049
|
-
if (path10)
|
|
62050
|
-
|
|
63141
|
+
if (!path10)
|
|
63142
|
+
continue;
|
|
63143
|
+
(form.importAll ? importAllPaths : wildcards).push({ path: path10, recursive: form.wildcard === "recursive" });
|
|
62051
63144
|
}
|
|
62052
63145
|
if (wildcards.length === 0)
|
|
62053
63146
|
return;
|
|
@@ -62068,8 +63161,10 @@ ${baseIndent}}`;
|
|
|
62068
63161
|
const ownerQn = ownerPkg ? qualifiedNameOf(ownerPkg) : void 0;
|
|
62069
63162
|
if (!ownerQn)
|
|
62070
63163
|
continue;
|
|
62071
|
-
const
|
|
62072
|
-
if (!
|
|
63164
|
+
const reaches = (w) => w.recursive ? ownerQn === w.path || ownerQn.startsWith(w.path + "::") : ownerQn === w.path;
|
|
63165
|
+
if (!wildcards.some(reaches))
|
|
63166
|
+
continue;
|
|
63167
|
+
if (importAllPaths.some(reaches))
|
|
62073
63168
|
continue;
|
|
62074
63169
|
const refNode = ref.$refNode?.astNode;
|
|
62075
63170
|
if (refNode && isWithinNamespaceOf(refNode, target))
|
|
@@ -62151,9 +63246,10 @@ ${baseIndent}}`;
|
|
|
62151
63246
|
* unevaluated filter to break a build raise it per code through
|
|
62152
63247
|
* `sysml.validation.severities` (REQ-240).
|
|
62153
63248
|
*/
|
|
62154
|
-
checkUnevaluatedFilters(imports, exposePaths, accept) {
|
|
63249
|
+
checkUnevaluatedFilters(imports, exposePaths, filterMembers, index, accept) {
|
|
63250
|
+
const resolveName = (name) => this.resolveUnique(name, index);
|
|
62155
63251
|
const report = (condition, subject) => {
|
|
62156
|
-
const undecidable = undecidableFilterCondition(condition);
|
|
63252
|
+
const undecidable = undecidableFilterCondition(condition, resolveName);
|
|
62157
63253
|
if (!undecidable)
|
|
62158
63254
|
return;
|
|
62159
63255
|
accept(severity("RES018", "info"), DIAGNOSTIC_MESSAGES.RES018_UNEVALUATED_FILTER(subject, undecidable.construct), { node: undecidable.node, code: "RES018" });
|
|
@@ -62163,6 +63259,11 @@ ${baseIndent}}`;
|
|
|
62163
63259
|
report(filter3.condition, "Import");
|
|
62164
63260
|
for (const path10 of exposePaths)
|
|
62165
63261
|
report(path10.condition, "Expose");
|
|
63262
|
+
for (const member of filterMembers) {
|
|
63263
|
+
if (governsImportFilters(member.$container)) {
|
|
63264
|
+
report(member.condition, "Package");
|
|
63265
|
+
}
|
|
63266
|
+
}
|
|
62166
63267
|
}
|
|
62167
63268
|
// REQ-324 — RES009 unused import (configurable, OFF by default)
|
|
62168
63269
|
checkUnusedImports(root3, imports, index, level, accept) {
|
|
@@ -62183,7 +63284,7 @@ ${baseIndent}}`;
|
|
|
62183
63284
|
return;
|
|
62184
63285
|
const visited = /* @__PURE__ */ new Set();
|
|
62185
63286
|
const reachesSelf = (node) => {
|
|
62186
|
-
for (const targetName of
|
|
63287
|
+
for (const targetName of specializationTargets2(node)) {
|
|
62187
63288
|
const target = this.resolve(targetName, index, node);
|
|
62188
63289
|
if (!target)
|
|
62189
63290
|
continue;
|
|
@@ -62570,14 +63671,14 @@ function shortNameOf(node) {
|
|
|
62570
63671
|
function shortNameNodeOf(node) {
|
|
62571
63672
|
return node.shortName;
|
|
62572
63673
|
}
|
|
62573
|
-
function
|
|
63674
|
+
function specializationTargets2(node) {
|
|
62574
63675
|
const out = [];
|
|
62575
63676
|
const rels = [
|
|
62576
63677
|
...node.preRelationships ?? [],
|
|
62577
63678
|
...node.relationships ?? []
|
|
62578
63679
|
];
|
|
62579
63680
|
for (const rel of rels) {
|
|
62580
|
-
if (rel.kind &&
|
|
63681
|
+
if (rel.kind && SPECIALIZATION_KINDS4.has(rel.kind))
|
|
62581
63682
|
out.push(...rel.targets);
|
|
62582
63683
|
}
|
|
62583
63684
|
return out;
|
|
@@ -62928,7 +64029,13 @@ function introducedNames(imp, index, nodeOf) {
|
|
|
62928
64029
|
const protectedNamespaceKeys = protectedNamespaceKeysFor(imp.$container, globalDescs, nodeOf);
|
|
62929
64030
|
return expandImportEntries(imp, globalDescs, {
|
|
62930
64031
|
nodeOf,
|
|
62931
|
-
protectedNamespaceKeys
|
|
64032
|
+
protectedNamespaceKeys,
|
|
64033
|
+
// issue #153 — filters may need a metadata definition's default value or
|
|
64034
|
+
// a specialization chain; both are index lookups, not cross-references.
|
|
64035
|
+
resolveName: (name) => {
|
|
64036
|
+
const description = globalDescs.firstNamed(name);
|
|
64037
|
+
return description ? nodeOf(description) : void 0;
|
|
64038
|
+
}
|
|
62932
64039
|
}).map((entry) => ({
|
|
62933
64040
|
simple: entry.name,
|
|
62934
64041
|
targetQn: entry.targetName,
|
|
@@ -62949,13 +64056,13 @@ function protectedNamespaceKeysFor(context, globalDescs, nodeOf) {
|
|
|
62949
64056
|
const node = nodeOf(desc);
|
|
62950
64057
|
if (!node || !isDeclLike(node))
|
|
62951
64058
|
return;
|
|
62952
|
-
for (const inherited of
|
|
64059
|
+
for (const inherited of specializationTargets2(node))
|
|
62953
64060
|
collect(inherited);
|
|
62954
64061
|
};
|
|
62955
64062
|
let cur = context;
|
|
62956
64063
|
while (cur) {
|
|
62957
64064
|
if (isDeclLike(cur)) {
|
|
62958
|
-
for (const target of
|
|
64065
|
+
for (const target of specializationTargets2(cur))
|
|
62959
64066
|
collect(target);
|
|
62960
64067
|
}
|
|
62961
64068
|
cur = cur.$container;
|
|
@@ -63009,6 +64116,15 @@ function importIsUsed(imp, index, usedFull, usedFirst, nodeOf) {
|
|
|
63009
64116
|
}
|
|
63010
64117
|
return false;
|
|
63011
64118
|
}
|
|
64119
|
+
var FILTER_HOST_TYPES = /* @__PURE__ */ new Set([
|
|
64120
|
+
"ViewDecl",
|
|
64121
|
+
"ViewpointDecl",
|
|
64122
|
+
"RenderingDecl",
|
|
64123
|
+
"Document"
|
|
64124
|
+
]);
|
|
64125
|
+
function isFilterHost(owner) {
|
|
64126
|
+
return isPackage(owner) || FILTER_HOST_TYPES.has(owner.$type);
|
|
64127
|
+
}
|
|
63012
64128
|
function kindLabel(node) {
|
|
63013
64129
|
const m = /^([A-Z][a-z]+)Decl$/.exec(node.$type);
|
|
63014
64130
|
return m ? m[1].toLowerCase() : node.$type;
|
|
@@ -63511,54 +64627,8 @@ function outlineGroupForType(astType) {
|
|
|
63511
64627
|
return CATEGORY_TO_OUTLINE_GROUP[categoryForType(astType)] ?? "structure";
|
|
63512
64628
|
}
|
|
63513
64629
|
|
|
63514
|
-
// ../language-server/out/src/services/comment-body.js
|
|
63515
|
-
function sourceOf(node) {
|
|
63516
|
-
return node.$cstNode?.root.fullText;
|
|
63517
|
-
}
|
|
63518
|
-
function cleanBlockBody(inner) {
|
|
63519
|
-
let body = inner.trim();
|
|
63520
|
-
if (body.startsWith("/*"))
|
|
63521
|
-
body = body.slice(2);
|
|
63522
|
-
if (body.endsWith("*/"))
|
|
63523
|
-
body = body.slice(0, -2);
|
|
63524
|
-
const lines = body.split("\n").map((line) => line.replace(/^\s*\*+ ?/u, "").replace(/\s+$/u, ""));
|
|
63525
|
-
while (lines.length > 0 && lines[0].trim() === "")
|
|
63526
|
-
lines.shift();
|
|
63527
|
-
while (lines.length > 0 && lines[lines.length - 1].trim() === "")
|
|
63528
|
-
lines.pop();
|
|
63529
|
-
return lines.join("\n").trim();
|
|
63530
|
-
}
|
|
63531
|
-
function docCommentBody(node) {
|
|
63532
|
-
const raw = node.doc;
|
|
63533
|
-
if (typeof raw !== "string")
|
|
63534
|
-
return void 0;
|
|
63535
|
-
const start = raw.indexOf("/*");
|
|
63536
|
-
const end = raw.lastIndexOf("*/");
|
|
63537
|
-
if (start < 0 || end < start)
|
|
63538
|
-
return void 0;
|
|
63539
|
-
const body = cleanBlockBody(raw.slice(start, end + 2));
|
|
63540
|
-
return body.length > 0 ? body : void 0;
|
|
63541
|
-
}
|
|
63542
|
-
function trailingBlockBody(node) {
|
|
63543
|
-
const cst = node.$cstNode;
|
|
63544
|
-
const text = sourceOf(node);
|
|
63545
|
-
if (!cst || text === void 0)
|
|
63546
|
-
return void 0;
|
|
63547
|
-
const rest = text.slice(cst.end);
|
|
63548
|
-
const open = rest.indexOf("/*");
|
|
63549
|
-
if (open < 0)
|
|
63550
|
-
return void 0;
|
|
63551
|
-
if (rest.slice(0, open).trim() !== "")
|
|
63552
|
-
return void 0;
|
|
63553
|
-
const close = rest.indexOf("*/", open + 2);
|
|
63554
|
-
if (close < 0)
|
|
63555
|
-
return void 0;
|
|
63556
|
-
const body = cleanBlockBody(rest.slice(open, close + 2));
|
|
63557
|
-
return body.length > 0 ? body : void 0;
|
|
63558
|
-
}
|
|
63559
|
-
|
|
63560
64630
|
// ../language-server/out/src/services/document-symbol-provider.js
|
|
63561
|
-
var
|
|
64631
|
+
var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", "specializes"]);
|
|
63562
64632
|
var REDEFINITION_KINDS = /* @__PURE__ */ new Set([":>>", "redefines"]);
|
|
63563
64633
|
var INHERITABLE_FEATURE_TYPES = /* @__PURE__ */ new Set([
|
|
63564
64634
|
"ActionDecl",
|
|
@@ -63623,11 +64693,11 @@ function buildLocalSymbolIndex(root3) {
|
|
|
63623
64693
|
}
|
|
63624
64694
|
return symbols;
|
|
63625
64695
|
}
|
|
63626
|
-
function
|
|
64696
|
+
function specializationTargets3(node) {
|
|
63627
64697
|
const n = node;
|
|
63628
64698
|
const out = [];
|
|
63629
64699
|
for (const rel of [...n.preRelationships ?? [], ...n.relationships ?? []]) {
|
|
63630
|
-
if (rel.kind &&
|
|
64700
|
+
if (rel.kind && SPECIALIZATION_KINDS5.has(rel.kind))
|
|
63631
64701
|
out.push(...rel.targets ?? []);
|
|
63632
64702
|
}
|
|
63633
64703
|
return out;
|
|
@@ -63746,7 +64816,7 @@ function inheritedFeatureSymbols(node, inheritedRange, context, seen = /* @__PUR
|
|
|
63746
64816
|
return [];
|
|
63747
64817
|
seen.add(node);
|
|
63748
64818
|
const symbols = [];
|
|
63749
|
-
for (const targetName of
|
|
64819
|
+
for (const targetName of specializationTargets3(node)) {
|
|
63750
64820
|
const target = resolveLocalTarget(targetName, context);
|
|
63751
64821
|
if (!target || seen.has(target))
|
|
63752
64822
|
continue;
|
|
@@ -64351,7 +65421,7 @@ function nearestAncestor(node, types) {
|
|
|
64351
65421
|
}
|
|
64352
65422
|
return void 0;
|
|
64353
65423
|
}
|
|
64354
|
-
function
|
|
65424
|
+
function exprText2(node) {
|
|
64355
65425
|
return node?.$cstNode?.text?.trim().replace(/\s+/gu, " ") ?? "";
|
|
64356
65426
|
}
|
|
64357
65427
|
function conditionTypeLabel(node) {
|
|
@@ -64362,7 +65432,7 @@ function conditionTypeLabel(node) {
|
|
|
64362
65432
|
if (["AndExpr", "OrExpr", "XorExpr", "NotExpr", "CompareExpr", "ClassifyOp"].includes(node.$type)) {
|
|
64363
65433
|
return "Boolean";
|
|
64364
65434
|
}
|
|
64365
|
-
const text =
|
|
65435
|
+
const text = exprText2(node);
|
|
64366
65436
|
return /\b(true|false)\b|[=!<>]=?|(?:\band\b|\bor\b|\bnot\b|\bxor\b)/u.test(text) ? "Boolean" : "Boolean (expected)";
|
|
64367
65437
|
}
|
|
64368
65438
|
function buildConditionalHover(node) {
|
|
@@ -64376,7 +65446,7 @@ function buildConditionalHover(node) {
|
|
|
64376
65446
|
"",
|
|
64377
65447
|
"Canonical form: `if condition ? thenExpression else elseExpression`",
|
|
64378
65448
|
`Then marker: ${usesQuestion ? "canonical `?`" : "non-canonical `then`; use `?`"}`,
|
|
64379
|
-
`Condition: \`${
|
|
65449
|
+
`Condition: \`${exprText2(n.cond)}\``,
|
|
64380
65450
|
`Condition type: ${conditionTypeLabel(n.cond)}`,
|
|
64381
65451
|
"",
|
|
64382
65452
|
sourceFooter(nodeSource(node))
|
|
@@ -66514,7 +67584,15 @@ var SysmlScopeProvider = class extends DefaultScopeProvider {
|
|
|
66514
67584
|
// metadata `.ref` here re-enters the linker (cyclic reference error,
|
|
66515
67585
|
// and the reference is poisoned with a cached failure). Match filters
|
|
66516
67586
|
// by textual name only on this path; the validator resolves refs.
|
|
66517
|
-
resolveReferences: false
|
|
67587
|
+
resolveReferences: false,
|
|
67588
|
+
// issue #153 — the index lookup a filter needs for a metadata
|
|
67589
|
+
// definition's default, a specialization chain or an enumeration
|
|
67590
|
+
// member. It reads the symbol table rather than a cross-reference,
|
|
67591
|
+
// so it is safe on this path where `.ref` is not.
|
|
67592
|
+
resolveName: (name) => {
|
|
67593
|
+
const description = globalDescs.firstNamed(name);
|
|
67594
|
+
return description ? this.nodeOf(description) : void 0;
|
|
67595
|
+
}
|
|
66518
67596
|
};
|
|
66519
67597
|
const result = [];
|
|
66520
67598
|
for (const imp of this.visibleImportsFrom(contextNode)) {
|
|
@@ -66574,7 +67652,7 @@ var SysmlScopeProvider = class extends DefaultScopeProvider {
|
|
|
66574
67652
|
const visitedTargets = /* @__PURE__ */ new Set();
|
|
66575
67653
|
let cur = contextNode;
|
|
66576
67654
|
while (cur) {
|
|
66577
|
-
for (const target of
|
|
67655
|
+
for (const target of specializationTargets4(cur)) {
|
|
66578
67656
|
this.collectProtectedNamespace(target, globalDescs, keys3, nodes, visitedTargets);
|
|
66579
67657
|
}
|
|
66580
67658
|
cur = cur.$container;
|
|
@@ -66596,7 +67674,7 @@ var SysmlScopeProvider = class extends DefaultScopeProvider {
|
|
|
66596
67674
|
keys3.add(key);
|
|
66597
67675
|
nodes.push(node);
|
|
66598
67676
|
}
|
|
66599
|
-
for (const inherited of
|
|
67677
|
+
for (const inherited of specializationTargets4(node)) {
|
|
66600
67678
|
this.collectProtectedNamespace(inherited, globalDescs, keys3, nodes, visitedTargets);
|
|
66601
67679
|
}
|
|
66602
67680
|
}
|
|
@@ -66615,16 +67693,7 @@ var SysmlScopeProvider = class extends DefaultScopeProvider {
|
|
|
66615
67693
|
// every reference and re-expanded the whole standard library each time
|
|
66616
67694
|
// (measured on a 1 500-line model: 226 misses over 349 references, 16 s).
|
|
66617
67695
|
importContextKey(contextNode, protectedNamespaces) {
|
|
66618
|
-
const
|
|
66619
|
-
let cur = contextNode;
|
|
66620
|
-
while (cur) {
|
|
66621
|
-
for (const member of namespaceMembers(cur)) {
|
|
66622
|
-
if (isImport(member))
|
|
66623
|
-
parts.push(importSignature(member));
|
|
66624
|
-
}
|
|
66625
|
-
cur = cur.$container;
|
|
66626
|
-
}
|
|
66627
|
-
const imports = parts.length > 0 ? parts.join(" ") : "root";
|
|
67696
|
+
const imports = importContextSignature(contextNode);
|
|
66628
67697
|
return protectedNamespaces.key ? `${imports} ${protectedNamespaces.key}` : imports;
|
|
66629
67698
|
}
|
|
66630
67699
|
nodeOf(desc) {
|
|
@@ -66640,6 +67709,23 @@ var SysmlScopeProvider = class extends DefaultScopeProvider {
|
|
|
66640
67709
|
function ownsProtectedImport(node) {
|
|
66641
67710
|
return namespaceMembers(node).some((member) => isImport(member) && importVisibility(member) === "protected");
|
|
66642
67711
|
}
|
|
67712
|
+
function importContextSignature(contextNode) {
|
|
67713
|
+
const parts = [];
|
|
67714
|
+
let cur = contextNode;
|
|
67715
|
+
while (cur) {
|
|
67716
|
+
for (const member of namespaceMembers(cur)) {
|
|
67717
|
+
if (isImport(member))
|
|
67718
|
+
parts.push(importSignature(member));
|
|
67719
|
+
else if (member.$type === "FilterMember")
|
|
67720
|
+
parts.push(filterSignature(member));
|
|
67721
|
+
}
|
|
67722
|
+
cur = cur.$container;
|
|
67723
|
+
}
|
|
67724
|
+
return parts.length > 0 ? parts.join(" ") : "root";
|
|
67725
|
+
}
|
|
67726
|
+
function filterSignature(member) {
|
|
67727
|
+
return `filter ${member.$cstNode?.text?.replace(/\s+/gu, " ").trim() ?? "?"}`;
|
|
67728
|
+
}
|
|
66643
67729
|
function importSignature(imp) {
|
|
66644
67730
|
const text = imp.$cstNode?.text;
|
|
66645
67731
|
if (text)
|
|
@@ -66647,12 +67733,12 @@ function importSignature(imp) {
|
|
|
66647
67733
|
const segments = imp.segs.map((seg) => `${seg.name ?? ""}${seg.star ? "*" : ""}${seg.recursive ? "**" : ""}`);
|
|
66648
67734
|
return `${importVisibility(imp)} ${imp.head}::${segments.join("::")}${imp.alias ? ` as ${imp.alias}` : ""}`;
|
|
66649
67735
|
}
|
|
66650
|
-
var
|
|
66651
|
-
function
|
|
67736
|
+
var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
67737
|
+
function specializationTargets4(node) {
|
|
66652
67738
|
const n = node;
|
|
66653
67739
|
const out = [];
|
|
66654
67740
|
for (const rel of [...n.preRelationships ?? [], ...n.relationships ?? []]) {
|
|
66655
|
-
if (rel.kind &&
|
|
67741
|
+
if (rel.kind && SPECIALIZATION_KINDS6.has(rel.kind))
|
|
66656
67742
|
out.push(...rel.targets ?? []);
|
|
66657
67743
|
}
|
|
66658
67744
|
return out;
|
|
@@ -66731,7 +67817,10 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
66731
67817
|
const description = {
|
|
66732
67818
|
...entry.description,
|
|
66733
67819
|
name: `${ownerAlias}::${entry.name}`,
|
|
66734
|
-
isDerivedAlias: true
|
|
67820
|
+
isDerivedAlias: true,
|
|
67821
|
+
// issue #152 — a membership seen through a re-export,
|
|
67822
|
+
// not one this namespace owns.
|
|
67823
|
+
derivedKind: "reexport"
|
|
66735
67824
|
};
|
|
66736
67825
|
const key = exportAliasKey(description);
|
|
66737
67826
|
if (seen.has(key))
|
|
@@ -66752,7 +67841,7 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
66752
67841
|
// linker can resolve the qualified spelling without a full type evaluator.
|
|
66753
67842
|
addInheritedQualifiedAliases(root3, exports2) {
|
|
66754
67843
|
const seen = new Set(exports2.map(exportAliasKey));
|
|
66755
|
-
const nodes = Array.from(ast_utils_exports.streamAllContents(root3)).filter((node) =>
|
|
67844
|
+
const nodes = Array.from(ast_utils_exports.streamAllContents(root3)).filter((node) => specializationTargets5(node).length > 0);
|
|
66756
67845
|
if (nodes.length === 0)
|
|
66757
67846
|
return;
|
|
66758
67847
|
const ownerAliases = aliasesByNode(exports2);
|
|
@@ -66760,7 +67849,7 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
66760
67849
|
const sourceDescriptions = new GlobalDescriptionIndex(exports2);
|
|
66761
67850
|
const additions = [];
|
|
66762
67851
|
for (const node of nodes) {
|
|
66763
|
-
const targets =
|
|
67852
|
+
const targets = specializationTargets5(node);
|
|
66764
67853
|
const aliases = ownerAliases.get(node) ?? [];
|
|
66765
67854
|
if (aliases.length === 0)
|
|
66766
67855
|
continue;
|
|
@@ -66773,7 +67862,9 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
66773
67862
|
const description = {
|
|
66774
67863
|
...inherited,
|
|
66775
67864
|
name: `${ownerAlias}::${suffix}`,
|
|
66776
|
-
isDerivedAlias: true
|
|
67865
|
+
isDerivedAlias: true,
|
|
67866
|
+
// issue #152 — an implicit inherited membership.
|
|
67867
|
+
derivedKind: "inherited"
|
|
66777
67868
|
};
|
|
66778
67869
|
const key = exportAliasKey(description);
|
|
66779
67870
|
if (seen.has(key))
|
|
@@ -66857,7 +67948,7 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
66857
67948
|
...base,
|
|
66858
67949
|
...visibility ? { visibility } : {},
|
|
66859
67950
|
...visibility === "private" ? { isPrivate: true } : {},
|
|
66860
|
-
...alias.derived ? { isDerivedAlias: true } : {},
|
|
67951
|
+
...alias.derived ? { isDerivedAlias: true, derivedKind: "relative" } : {},
|
|
66861
67952
|
// REQ-242 — issue #103 — mirrors what the precomputed library index
|
|
66862
67953
|
// records, so consumers read def-ness the same way for workspace and
|
|
66863
67954
|
// library symbols.
|
|
@@ -66906,39 +67997,26 @@ function directImportEntries(imp, descriptions) {
|
|
|
66906
67997
|
const path10 = importedPath(imp);
|
|
66907
67998
|
if (!path10)
|
|
66908
67999
|
return [];
|
|
66909
|
-
const
|
|
66910
|
-
|
|
68000
|
+
const form = importForm(imp);
|
|
68001
|
+
const options = {
|
|
68002
|
+
resolveReferences: false,
|
|
68003
|
+
resolveName: (name) => descriptions.firstNamed(name)?.node
|
|
68004
|
+
};
|
|
68005
|
+
if (form.wildcard === "none") {
|
|
66911
68006
|
const description = descriptions.firstNamed(path10);
|
|
66912
68007
|
if (!description)
|
|
66913
68008
|
return [];
|
|
66914
|
-
|
|
66915
|
-
|
|
66916
|
-
const entries = [];
|
|
66917
|
-
const seen = /* @__PURE__ */ new Set();
|
|
66918
|
-
for (const description of descriptions.membersOf(path10, wildcard)) {
|
|
66919
|
-
const visibility = description;
|
|
66920
|
-
if (visibility.isPrivate || visibility.visibility === "private")
|
|
66921
|
-
continue;
|
|
66922
|
-
const rest = description.name.slice(path10.length + 2);
|
|
66923
|
-
if (!rest)
|
|
66924
|
-
continue;
|
|
66925
|
-
const name = rest.split("::").pop();
|
|
66926
|
-
if (!name)
|
|
66927
|
-
continue;
|
|
66928
|
-
const key = `${name}|${description.documentUri.toString()}|${description.path}`;
|
|
66929
|
-
if (seen.has(key))
|
|
66930
|
-
continue;
|
|
66931
|
-
seen.add(key);
|
|
66932
|
-
entries.push({ name, description });
|
|
68009
|
+
const name = imp.alias ?? path10.split("::").pop() ?? path10;
|
|
68010
|
+
return applyFilters(imp, [{ name, targetName: description.name, description }], options);
|
|
66933
68011
|
}
|
|
66934
|
-
return
|
|
68012
|
+
return applyFilters(imp, selectMemberships(path10, form, descriptions), options);
|
|
66935
68013
|
}
|
|
66936
|
-
var
|
|
66937
|
-
function
|
|
68014
|
+
var SPECIALIZATION_KINDS7 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
68015
|
+
function specializationTargets5(node) {
|
|
66938
68016
|
const value = node;
|
|
66939
68017
|
const targets = [];
|
|
66940
68018
|
for (const relationship of [...value.preRelationships ?? [], ...value.relationships ?? []]) {
|
|
66941
|
-
if (relationship.kind &&
|
|
68019
|
+
if (relationship.kind && SPECIALIZATION_KINDS7.has(relationship.kind)) {
|
|
66942
68020
|
targets.push(...relationship.targets ?? []);
|
|
66943
68021
|
}
|
|
66944
68022
|
}
|
|
@@ -67251,6 +68329,15 @@ var SysmlCodeActionProvider = class {
|
|
|
67251
68329
|
});
|
|
67252
68330
|
}
|
|
67253
68331
|
}
|
|
68332
|
+
if (code === "RES021") {
|
|
68333
|
+
actions.push({
|
|
68334
|
+
title: "Make this root import 'private'",
|
|
68335
|
+
kind: import_vscode_languageserver18.CodeActionKind.QuickFix,
|
|
68336
|
+
isPreferred: true,
|
|
68337
|
+
diagnostics: [diagnostic],
|
|
68338
|
+
edit: { changes: { [uri]: [import_vscode_languageserver18.TextEdit.replace(diagnostic.range, "private")] } }
|
|
68339
|
+
});
|
|
68340
|
+
}
|
|
67254
68341
|
if (code === "RES015" && isImportFixData(diagnostic.data)) {
|
|
67255
68342
|
const importPath = diagnostic.data.importPath;
|
|
67256
68343
|
const pkg = nearestAncestor2(node, isPackage);
|
|
@@ -68781,341 +69868,6 @@ function effectiveNameHint(node) {
|
|
|
68781
69868
|
};
|
|
68782
69869
|
}
|
|
68783
69870
|
|
|
68784
|
-
// ../language-server/out/src/services/requirement-eval.js
|
|
68785
|
-
var UNRESOLVED = { kind: "unresolved" };
|
|
68786
|
-
var INCONCLUSIVE = { kind: "inconclusive" };
|
|
68787
|
-
var REDEFINE_KINDS = /* @__PURE__ */ new Set([":>>", ":>", "redefines", "subsets"]);
|
|
68788
|
-
function declaresFeature(node, name) {
|
|
68789
|
-
if (node.name === name)
|
|
68790
|
-
return true;
|
|
68791
|
-
for (const rel of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
|
|
68792
|
-
if (rel.kind && REDEFINE_KINDS.has(rel.kind) && (rel.targets ?? []).includes(name))
|
|
68793
|
-
return true;
|
|
68794
|
-
}
|
|
68795
|
-
return false;
|
|
68796
|
-
}
|
|
68797
|
-
function evaluateExpr(node, scope) {
|
|
68798
|
-
if (!node)
|
|
68799
|
-
return INCONCLUSIVE;
|
|
68800
|
-
const n = node;
|
|
68801
|
-
switch (n.$type) {
|
|
68802
|
-
case "NumericPrimary":
|
|
68803
|
-
return typeof n.numVal === "number" ? { kind: "number", value: n.numVal } : INCONCLUSIVE;
|
|
68804
|
-
case "LiteralBool":
|
|
68805
|
-
return { kind: "boolean", value: n.value === "true" };
|
|
68806
|
-
case "LiteralStr":
|
|
68807
|
-
return { kind: "string", value: decodeStringLiteral(String(n.value ?? "")) };
|
|
68808
|
-
case "LiteralNull":
|
|
68809
|
-
return INCONCLUSIVE;
|
|
68810
|
-
case "ParenExpr": {
|
|
68811
|
-
const items = n.items ?? [];
|
|
68812
|
-
return items.length === 1 ? evaluateExpr(items[0], scope) : INCONCLUSIVE;
|
|
68813
|
-
}
|
|
68814
|
-
case "UnaryMinusExpr": {
|
|
68815
|
-
const v = evaluateExpr(n.operand, scope);
|
|
68816
|
-
return v.kind === "number" ? { kind: "number", value: -v.value } : passThrough(v);
|
|
68817
|
-
}
|
|
68818
|
-
case "UnaryPlusExpr":
|
|
68819
|
-
return evaluateExpr(n.operand, scope);
|
|
68820
|
-
case "NotExpr": {
|
|
68821
|
-
if (!n.operand)
|
|
68822
|
-
return INCONCLUSIVE;
|
|
68823
|
-
const v = evaluateExpr(n.operand, scope);
|
|
68824
|
-
return v.kind === "boolean" ? { kind: "boolean", value: !v.value } : passThrough(v);
|
|
68825
|
-
}
|
|
68826
|
-
case "PathExpr":
|
|
68827
|
-
return scope(String(n.path).split("."));
|
|
68828
|
-
case "IfExpr": {
|
|
68829
|
-
const cond = evaluateExpr(n.cond, scope);
|
|
68830
|
-
if (cond.kind !== "boolean")
|
|
68831
|
-
return passThrough(cond);
|
|
68832
|
-
return cond.value ? evaluateExpr(n.thenExpr, scope) : evaluateExpr(n.elseExpr, scope);
|
|
68833
|
-
}
|
|
68834
|
-
case "PostfixOp": {
|
|
68835
|
-
if (n.unit && n.unitValue)
|
|
68836
|
-
return evaluateExpr(n.unitValue, scope);
|
|
68837
|
-
if (n.operand)
|
|
68838
|
-
return evaluateExpr(n.operand, scope);
|
|
68839
|
-
return INCONCLUSIVE;
|
|
68840
|
-
}
|
|
68841
|
-
case "BinExpr":
|
|
68842
|
-
return evaluateBin2(n, scope);
|
|
68843
|
-
default:
|
|
68844
|
-
return INCONCLUSIVE;
|
|
68845
|
-
}
|
|
68846
|
-
}
|
|
68847
|
-
function passThrough(v) {
|
|
68848
|
-
return v.kind === "unresolved" ? UNRESOLVED : INCONCLUSIVE;
|
|
68849
|
-
}
|
|
68850
|
-
function decodeStringLiteral(raw) {
|
|
68851
|
-
let body = raw;
|
|
68852
|
-
if (body.length >= 2 && body.startsWith('"') && body.endsWith('"')) {
|
|
68853
|
-
body = body.slice(1, -1);
|
|
68854
|
-
}
|
|
68855
|
-
return body.replace(/\\(.)/gu, (_m, ch) => {
|
|
68856
|
-
switch (ch) {
|
|
68857
|
-
case "n":
|
|
68858
|
-
return "\n";
|
|
68859
|
-
case "t":
|
|
68860
|
-
return " ";
|
|
68861
|
-
case "b":
|
|
68862
|
-
return "\b";
|
|
68863
|
-
case "f":
|
|
68864
|
-
return "\f";
|
|
68865
|
-
default:
|
|
68866
|
-
return ch;
|
|
68867
|
-
}
|
|
68868
|
-
});
|
|
68869
|
-
}
|
|
68870
|
-
function evaluateBin2(node, scope) {
|
|
68871
|
-
const op = String(node.op);
|
|
68872
|
-
const left = evaluateExpr(node.left, scope);
|
|
68873
|
-
if (op === "and" || op === "&") {
|
|
68874
|
-
if (left.kind === "boolean" && !left.value)
|
|
68875
|
-
return { kind: "boolean", value: false };
|
|
68876
|
-
} else if (op === "or" || op === "|") {
|
|
68877
|
-
if (left.kind === "boolean" && left.value)
|
|
68878
|
-
return { kind: "boolean", value: true };
|
|
68879
|
-
} else if (op === "implies") {
|
|
68880
|
-
if (left.kind === "boolean" && !left.value)
|
|
68881
|
-
return { kind: "boolean", value: true };
|
|
68882
|
-
}
|
|
68883
|
-
const right = evaluateExpr(node.right, scope);
|
|
68884
|
-
if (left.kind === "unresolved" || right.kind === "unresolved")
|
|
68885
|
-
return UNRESOLVED;
|
|
68886
|
-
if (left.kind === "inconclusive" || right.kind === "inconclusive")
|
|
68887
|
-
return INCONCLUSIVE;
|
|
68888
|
-
switch (op) {
|
|
68889
|
-
case "+":
|
|
68890
|
-
case "-":
|
|
68891
|
-
case "*":
|
|
68892
|
-
case "/":
|
|
68893
|
-
case "%":
|
|
68894
|
-
case "**":
|
|
68895
|
-
case "^":
|
|
68896
|
-
if (left.kind === "number" && right.kind === "number") {
|
|
68897
|
-
return { kind: "number", value: arith(op, left.value, right.value) };
|
|
68898
|
-
}
|
|
68899
|
-
return INCONCLUSIVE;
|
|
68900
|
-
case "<":
|
|
68901
|
-
case ">":
|
|
68902
|
-
case "<=":
|
|
68903
|
-
case ">=":
|
|
68904
|
-
if (left.kind === "number" && right.kind === "number") {
|
|
68905
|
-
return { kind: "boolean", value: compare(op, left.value, right.value) };
|
|
68906
|
-
}
|
|
68907
|
-
return INCONCLUSIVE;
|
|
68908
|
-
case "==":
|
|
68909
|
-
case "!=":
|
|
68910
|
-
case "===":
|
|
68911
|
-
case "!==": {
|
|
68912
|
-
const eq3 = valuesEqual(left, right);
|
|
68913
|
-
if (eq3 === void 0)
|
|
68914
|
-
return INCONCLUSIVE;
|
|
68915
|
-
return { kind: "boolean", value: op.startsWith("!") ? !eq3 : eq3 };
|
|
68916
|
-
}
|
|
68917
|
-
case "and":
|
|
68918
|
-
case "&":
|
|
68919
|
-
return bothBool(left, right, (a2, b) => a2 && b);
|
|
68920
|
-
case "or":
|
|
68921
|
-
case "|":
|
|
68922
|
-
return bothBool(left, right, (a2, b) => a2 || b);
|
|
68923
|
-
case "xor":
|
|
68924
|
-
return bothBool(left, right, (a2, b) => a2 !== b);
|
|
68925
|
-
case "implies":
|
|
68926
|
-
return bothBool(left, right, (a2, b) => !a2 || b);
|
|
68927
|
-
default:
|
|
68928
|
-
return INCONCLUSIVE;
|
|
68929
|
-
}
|
|
68930
|
-
}
|
|
68931
|
-
function arith(op, a2, b) {
|
|
68932
|
-
switch (op) {
|
|
68933
|
-
case "+":
|
|
68934
|
-
return a2 + b;
|
|
68935
|
-
case "-":
|
|
68936
|
-
return a2 - b;
|
|
68937
|
-
case "*":
|
|
68938
|
-
return a2 * b;
|
|
68939
|
-
case "/":
|
|
68940
|
-
return a2 / b;
|
|
68941
|
-
case "%":
|
|
68942
|
-
return a2 % b;
|
|
68943
|
-
case "**":
|
|
68944
|
-
case "^":
|
|
68945
|
-
return a2 ** b;
|
|
68946
|
-
default:
|
|
68947
|
-
return NaN;
|
|
68948
|
-
}
|
|
68949
|
-
}
|
|
68950
|
-
function compare(op, a2, b) {
|
|
68951
|
-
switch (op) {
|
|
68952
|
-
case "<":
|
|
68953
|
-
return a2 < b;
|
|
68954
|
-
case ">":
|
|
68955
|
-
return a2 > b;
|
|
68956
|
-
case "<=":
|
|
68957
|
-
return a2 <= b;
|
|
68958
|
-
case ">=":
|
|
68959
|
-
return a2 >= b;
|
|
68960
|
-
default:
|
|
68961
|
-
return false;
|
|
68962
|
-
}
|
|
68963
|
-
}
|
|
68964
|
-
function valuesEqual(a2, b) {
|
|
68965
|
-
if (a2.kind === "number" && b.kind === "number")
|
|
68966
|
-
return a2.value === b.value;
|
|
68967
|
-
if (a2.kind === "boolean" && b.kind === "boolean")
|
|
68968
|
-
return a2.value === b.value;
|
|
68969
|
-
if (a2.kind === "string" && b.kind === "string")
|
|
68970
|
-
return a2.value === b.value;
|
|
68971
|
-
return void 0;
|
|
68972
|
-
}
|
|
68973
|
-
function bothBool(a2, b, f) {
|
|
68974
|
-
if (a2.kind === "boolean" && b.kind === "boolean")
|
|
68975
|
-
return { kind: "boolean", value: f(a2.value, b.value) };
|
|
68976
|
-
return INCONCLUSIVE;
|
|
68977
|
-
}
|
|
68978
|
-
function memberNamed(node, name, seen = /* @__PURE__ */ new Set()) {
|
|
68979
|
-
if (!node || seen.has(node))
|
|
68980
|
-
return void 0;
|
|
68981
|
-
seen.add(node);
|
|
68982
|
-
for (const member of node.members ?? []) {
|
|
68983
|
-
if (member.value !== void 0 && declaresFeature(member, name))
|
|
68984
|
-
return member;
|
|
68985
|
-
}
|
|
68986
|
-
for (const member of node.members ?? []) {
|
|
68987
|
-
if (declaresFeature(member, name))
|
|
68988
|
-
return member;
|
|
68989
|
-
}
|
|
68990
|
-
const typeRef = node.typing?.type?.ref;
|
|
68991
|
-
return typeRef ? memberNamed(typeRef, name, seen) : void 0;
|
|
68992
|
-
}
|
|
68993
|
-
function resolveFeatureValue(root3, segments) {
|
|
68994
|
-
let cur = root3;
|
|
68995
|
-
for (const seg of segments) {
|
|
68996
|
-
cur = memberNamed(cur, seg);
|
|
68997
|
-
if (!cur)
|
|
68998
|
-
return UNRESOLVED;
|
|
68999
|
-
}
|
|
69000
|
-
if (cur.value)
|
|
69001
|
-
return evaluateExpr(cur.value, () => INCONCLUSIVE);
|
|
69002
|
-
return INCONCLUSIVE;
|
|
69003
|
-
}
|
|
69004
|
-
function subjectScope(subjectName, subjectBinding) {
|
|
69005
|
-
const binding = subjectBinding;
|
|
69006
|
-
return (segments) => {
|
|
69007
|
-
if (!binding)
|
|
69008
|
-
return INCONCLUSIVE;
|
|
69009
|
-
if (subjectName && segments[0] === subjectName) {
|
|
69010
|
-
const rest = segments.slice(1);
|
|
69011
|
-
if (rest.length === 0)
|
|
69012
|
-
return INCONCLUSIVE;
|
|
69013
|
-
return resolveFeatureValue(binding, rest);
|
|
69014
|
-
}
|
|
69015
|
-
return resolveFeatureValue(binding, segments);
|
|
69016
|
-
};
|
|
69017
|
-
}
|
|
69018
|
-
function subjectNameOf(req) {
|
|
69019
|
-
const subject = (req.members ?? []).find((m) => m.$type === "SubjectDecl");
|
|
69020
|
-
return subject?.name;
|
|
69021
|
-
}
|
|
69022
|
-
function gatherConstraints(req) {
|
|
69023
|
-
const out = [];
|
|
69024
|
-
for (const member of req.members ?? []) {
|
|
69025
|
-
if (member.$type === "RequireConstraintStmt" && member.body) {
|
|
69026
|
-
out.push({ kind: "require", body: member.body, text: exprText2(member.body) });
|
|
69027
|
-
} else if (member.$type === "AssumeConstraintStmt" && member.body) {
|
|
69028
|
-
out.push({ kind: "assume", body: member.body, text: exprText2(member.body) });
|
|
69029
|
-
}
|
|
69030
|
-
}
|
|
69031
|
-
return out;
|
|
69032
|
-
}
|
|
69033
|
-
function exprText2(node) {
|
|
69034
|
-
return node.$cstNode?.text?.trim() ?? "";
|
|
69035
|
-
}
|
|
69036
|
-
function evaluateRequirement(req, subjectBinding) {
|
|
69037
|
-
const requirement = req;
|
|
69038
|
-
const subjectName = subjectNameOf(requirement);
|
|
69039
|
-
const scope = subjectScope(subjectName, subjectBinding);
|
|
69040
|
-
const constraints = gatherConstraints(requirement);
|
|
69041
|
-
const details = [];
|
|
69042
|
-
let sawInconclusive = false;
|
|
69043
|
-
let sawUnresolved = false;
|
|
69044
|
-
let failed = false;
|
|
69045
|
-
for (const c of constraints) {
|
|
69046
|
-
const v = evaluateExpr(c.body, scope);
|
|
69047
|
-
let status2;
|
|
69048
|
-
if (v.kind === "unresolved") {
|
|
69049
|
-
status2 = "unresolved";
|
|
69050
|
-
sawUnresolved = true;
|
|
69051
|
-
} else if (v.kind !== "boolean") {
|
|
69052
|
-
status2 = "inconclusive";
|
|
69053
|
-
sawInconclusive = true;
|
|
69054
|
-
} else if (v.value) {
|
|
69055
|
-
status2 = "pass";
|
|
69056
|
-
} else if (c.kind === "require") {
|
|
69057
|
-
status2 = "fail";
|
|
69058
|
-
failed = true;
|
|
69059
|
-
} else {
|
|
69060
|
-
status2 = "inconclusive";
|
|
69061
|
-
sawInconclusive = true;
|
|
69062
|
-
}
|
|
69063
|
-
details.push({ kind: c.kind, status: status2, text: c.text });
|
|
69064
|
-
}
|
|
69065
|
-
let status;
|
|
69066
|
-
if (constraints.length === 0)
|
|
69067
|
-
status = "inconclusive";
|
|
69068
|
-
else if (failed)
|
|
69069
|
-
status = "fail";
|
|
69070
|
-
else if (sawUnresolved)
|
|
69071
|
-
status = "unresolved";
|
|
69072
|
-
else if (sawInconclusive)
|
|
69073
|
-
status = "inconclusive";
|
|
69074
|
-
else
|
|
69075
|
-
status = "pass";
|
|
69076
|
-
return { status, details };
|
|
69077
|
-
}
|
|
69078
|
-
function bindingName(by) {
|
|
69079
|
-
const n = by;
|
|
69080
|
-
if (n?.$type !== "PathExpr")
|
|
69081
|
-
return void 0;
|
|
69082
|
-
return n.path?.split(/::|\./).pop();
|
|
69083
|
-
}
|
|
69084
|
-
function evaluateVerificationCase(caseNode, resolveRequirement, resolvePart) {
|
|
69085
|
-
const node = caseNode;
|
|
69086
|
-
const subject = (node.members ?? []).find((m) => m.$type === "SubjectDecl");
|
|
69087
|
-
const subjectBoundName = bindingName(subject?.value);
|
|
69088
|
-
const subjectBinding = (subjectBoundName ? resolvePart(subjectBoundName) : void 0) ?? subject;
|
|
69089
|
-
const verifies = [];
|
|
69090
|
-
for (const member of node.members ?? []) {
|
|
69091
|
-
if (member.$type !== "VerifyStmt")
|
|
69092
|
-
continue;
|
|
69093
|
-
const targetName = String(member.target ?? "").split(/::|\./).pop();
|
|
69094
|
-
if (!targetName)
|
|
69095
|
-
continue;
|
|
69096
|
-
const req = resolveRequirement(targetName);
|
|
69097
|
-
if (!req) {
|
|
69098
|
-
verifies.push({ requirement: targetName, status: "unresolved" });
|
|
69099
|
-
continue;
|
|
69100
|
-
}
|
|
69101
|
-
const boundName = bindingName(member.by);
|
|
69102
|
-
const binding = (boundName ? resolvePart(boundName) : void 0) ?? subjectBinding;
|
|
69103
|
-
verifies.push({ requirement: targetName, status: evaluateRequirement(req, binding).status });
|
|
69104
|
-
}
|
|
69105
|
-
let status = "inconclusive";
|
|
69106
|
-
if (verifies.length === 0)
|
|
69107
|
-
status = "inconclusive";
|
|
69108
|
-
else if (verifies.some((v) => v.status === "fail"))
|
|
69109
|
-
status = "fail";
|
|
69110
|
-
else if (verifies.some((v) => v.status === "unresolved"))
|
|
69111
|
-
status = "error";
|
|
69112
|
-
else if (verifies.some((v) => v.status === "inconclusive"))
|
|
69113
|
-
status = "inconclusive";
|
|
69114
|
-
else
|
|
69115
|
-
status = "pass";
|
|
69116
|
-
return { status, verifies };
|
|
69117
|
-
}
|
|
69118
|
-
|
|
69119
69871
|
// ../language-server/out/src/services/codelens-provider.js
|
|
69120
69872
|
function walkAst(node, fn) {
|
|
69121
69873
|
fn(node);
|
|
@@ -71093,7 +71845,7 @@ async function runValidation(command) {
|
|
|
71093
71845
|
}
|
|
71094
71846
|
|
|
71095
71847
|
// src/main.ts
|
|
71096
|
-
var VERSION2 = true ? "0.
|
|
71848
|
+
var VERSION2 = true ? "0.18.0" : "dev";
|
|
71097
71849
|
async function main(argv) {
|
|
71098
71850
|
const command = parseArgs(argv);
|
|
71099
71851
|
if (command.kind === "help") {
|