sysml-validate 0.15.4 → 0.15.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/out/main.js +903 -74
- 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
|
@@ -58670,7 +58670,22 @@ var DIAGNOSTIC_MESSAGES = {
|
|
|
58670
58670
|
// REQ-007 — SysML v1 → v2 migration guardrail.
|
|
58671
58671
|
MIG001_V1_KEYWORD: (keyword, v2, note) => `'${keyword}' is a SysML v1 construct, not a SysML v2 keyword. ${note} Use '${v2}'.`,
|
|
58672
58672
|
MIG002_V1_STEREOTYPE_KNOWN: (stereotype, v2, note) => `SysML v2 has no stereotypes. ${note} Replace \xAB${stereotype}\xBB with '${v2}'.`,
|
|
58673
|
-
MIG002_V1_STEREOTYPE_UNKNOWN: (stereotype) => `SysML v2 has no \xAB${stereotype}\xBB stereotype. Model it as a 'metadata def' applied with '@', or use the matching v2 definition keyword
|
|
58673
|
+
MIG002_V1_STEREOTYPE_UNKNOWN: (stereotype) => `SysML v2 has no \xAB${stereotype}\xBB stereotype. Model it as a 'metadata def' applied with '@', or use the matching v2 definition keyword.`,
|
|
58674
|
+
// REQ-390 — issue #104. Whole-model type conformance. Each message names the
|
|
58675
|
+
// two types it compared and the relationship that required them to agree, so
|
|
58676
|
+
// the reader can see WHICH end to change without opening the other file.
|
|
58677
|
+
SSM017_REDEFINITION_TYPE: (feature, subType, superType) => `Type '${subType}' does not specialize '${superType}', the type of the redefined feature '${feature}'. A redefinition narrows a feature \u2014 it cannot re-type it to something unrelated.`,
|
|
58678
|
+
SSM018_CONNECTOR_END_TYPES: (keyword, sourceType, targetType) => `'${keyword}' binds features of unrelated types '${sourceType}' and '${targetType}'. A binding asserts its two ends hold the same value, so their types must be related \u2014 one specializing the other, or conjugates ('~').`,
|
|
58679
|
+
SSM019_VALUE_TYPE: (typeName, expected, actual) => `A ${actual} literal is not a value of '${typeName}', which accepts ${expected === "number" ? "a numeric" : `a ${expected}`} value.`,
|
|
58680
|
+
SSM020_FLOW_PAYLOAD: (payload, endKind, endType) => `Payload '${payload}' is unrelated to the flow's ${endKind} type '${endType}'. A flow carries its payload between features that can hold it.`,
|
|
58681
|
+
SSM021_ABSTRACT_TYPE: (usage, typeName) => `'${usage}' is typed only by the abstract definition '${typeName}'. An abstract definition has no complete form \u2014 give the usage a concrete type, subset a concrete usage, or mark it 'abstract' too.`,
|
|
58682
|
+
SSM022_DEFINITION_DOMAIN: (keyword, typeName, typeKeyword, expected) => `A '${keyword}' usage cannot be defined by '${typeName}', which is a '${typeKeyword} def'. Type it by ${expected}.`,
|
|
58683
|
+
SSM023_GUARD_NOT_BOOLEAN: (construct) => `A ${construct} guard must be a Boolean expression \u2014 this one cannot evaluate to true or false.`,
|
|
58684
|
+
SSM024_ASSIGNMENT_VALUE: (target, typeName, expected, actual) => `'${target}' is a '${typeName}', which holds ${expected === "number" ? "a numeric" : `a ${expected}`} value \u2014 the assigned expression is ${actual === "number" ? "numeric" : actual}.`,
|
|
58685
|
+
SSM025_ACTION_PARAMETER_COUNT: (usage, declared, typeName, available) => `'${usage}' declares ${declared} directed parameter${declared === 1 ? "" : "s"} but its definition '${typeName}' has ${available}. An action usage's parameters correspond positionally to its definition's, so there is no ${available === 0 ? "parameter" : `${available + 1}th parameter`} to correspond to.`,
|
|
58686
|
+
SSM025_ACTION_PARAMETER_DIRECTION: (position, mine, typeName, theirs) => `Parameter ${position} is '${mine}' but the corresponding parameter of '${typeName}' is '${theirs}'. Positional correspondence redefines that parameter, and a redefinition cannot reverse a parameter's direction.`,
|
|
58687
|
+
SSM026_REDEFINITION_DIRECTION: (feature, mine, theirs) => `Direction '${mine}' reverses the redefined feature '${feature}', which is '${theirs}'. A redefinition refines a feature \u2014 it cannot turn an input into an output.`,
|
|
58688
|
+
SSM027_INTERFACE_END_TYPE: (position, endType, definition, expected) => `End ${position} is a '${endType}', but '${definition}' declares that end as '${expected}'. An interface usage connects through the ends its definition declares.`
|
|
58674
58689
|
};
|
|
58675
58690
|
var KEYWORD_TOOLTIPS = {
|
|
58676
58691
|
// Package / namespace
|
|
@@ -58934,7 +58949,9 @@ var SysmlIndexManager = class extends DefaultIndexManager {
|
|
|
58934
58949
|
selectionSegment: symbol.selectionSegment,
|
|
58935
58950
|
// REQ-068 — preserve declared visibility for wildcard re-export.
|
|
58936
58951
|
...symbol.isPrivate ? { isPrivate: true } : {},
|
|
58937
|
-
...symbol.visibility ? { visibility: symbol.visibility } : {}
|
|
58952
|
+
...symbol.visibility ? { visibility: symbol.visibility } : {},
|
|
58953
|
+
// REQ-242 — issue #103 — keeps type completion to definitions.
|
|
58954
|
+
...symbol.isUsage ? { isUsage: true } : {}
|
|
58938
58955
|
};
|
|
58939
58956
|
}
|
|
58940
58957
|
};
|
|
@@ -59133,6 +59150,46 @@ var FeaturePathResolver = class {
|
|
|
59133
59150
|
isPathExpr(node) {
|
|
59134
59151
|
return isPathExpr(node);
|
|
59135
59152
|
}
|
|
59153
|
+
// REQ-242 — issue #103: the members reachable through a path the user is
|
|
59154
|
+
// still typing (`engine.power.`). Completion cannot go through `resolve`,
|
|
59155
|
+
// which needs a parsed `PathExpr` with a CST leaf per segment; the text
|
|
59156
|
+
// after the last separator is not part of any node yet. The resolution
|
|
59157
|
+
// rules are otherwise identical, so the same root/child walk answers it —
|
|
59158
|
+
// which is what makes member completion see cross-file and inherited
|
|
59159
|
+
// members that a document-local name search cannot reach.
|
|
59160
|
+
membersForPath(context, steps) {
|
|
59161
|
+
if (steps.length === 0)
|
|
59162
|
+
return [];
|
|
59163
|
+
const root3 = ast_utils_exports.getDocument(context).parseResult.value;
|
|
59164
|
+
const snapshot = this.snapshot(root3);
|
|
59165
|
+
let current2 = this.resolveRoot(context, steps[0].text, snapshot);
|
|
59166
|
+
for (let index = 1; index < steps.length; index += 1) {
|
|
59167
|
+
if (!current2.node && !current2.description)
|
|
59168
|
+
return [];
|
|
59169
|
+
current2 = this.resolveChild(current2, steps[index].text, steps, index, snapshot);
|
|
59170
|
+
}
|
|
59171
|
+
const owner = this.followAlias(current2, snapshot);
|
|
59172
|
+
const node = owner.node ?? this.nodeOf(owner.description);
|
|
59173
|
+
return node ? this.visibleMembers(node, snapshot) : [];
|
|
59174
|
+
}
|
|
59175
|
+
// REQ-242 — issue #103: an element's own named children plus everything it
|
|
59176
|
+
// inherits, following typing (`part p : Engine`) and every specialization
|
|
59177
|
+
// relationship transitively. A usage carries almost no members of its own;
|
|
59178
|
+
// essentially all of them come from the type it is defined by and that
|
|
59179
|
+
// type's supertypes.
|
|
59180
|
+
visibleMembers(node, snapshot = this.snapshot(ast_utils_exports.getDocument(node).parseResult.value)) {
|
|
59181
|
+
const result = [];
|
|
59182
|
+
const seen = /* @__PURE__ */ new Set();
|
|
59183
|
+
for (const owner of [node, ...this.typedAndSpecializedOwners(node, snapshot)]) {
|
|
59184
|
+
for (const child of directNamedChildren(owner)) {
|
|
59185
|
+
if (seen.has(child))
|
|
59186
|
+
continue;
|
|
59187
|
+
seen.add(child);
|
|
59188
|
+
result.push(child);
|
|
59189
|
+
}
|
|
59190
|
+
}
|
|
59191
|
+
return result;
|
|
59192
|
+
}
|
|
59136
59193
|
segmentsOf(node) {
|
|
59137
59194
|
const cst = node.$cstNode;
|
|
59138
59195
|
if (!cst)
|
|
@@ -59422,6 +59479,282 @@ function isNamespaceOnlyDecl(node) {
|
|
|
59422
59479
|
return node.isDef === true;
|
|
59423
59480
|
}
|
|
59424
59481
|
|
|
59482
|
+
// ../language-server/out/src/services/conformance.js
|
|
59483
|
+
var SPECIALIZATION_KINDS2 = /* @__PURE__ */ new Set([
|
|
59484
|
+
":>",
|
|
59485
|
+
":>>",
|
|
59486
|
+
"specializes",
|
|
59487
|
+
"subsets",
|
|
59488
|
+
"redefines"
|
|
59489
|
+
]);
|
|
59490
|
+
var COMPOSITION_KINDS = /* @__PURE__ */ new Set(["unions", "intersects", "differences"]);
|
|
59491
|
+
var MAX_CLOSURE_DEPTH = 32;
|
|
59492
|
+
function simpleTypeName(name) {
|
|
59493
|
+
const last2 = name.trim().split(/::|\./u).pop() ?? name.trim();
|
|
59494
|
+
return last2.replace(/^'(.*)'$/u, "$1");
|
|
59495
|
+
}
|
|
59496
|
+
function declaredTypesOf(node) {
|
|
59497
|
+
const decl = node;
|
|
59498
|
+
const out = [];
|
|
59499
|
+
for (const typing of [decl.typing, ...decl.moreTypings ?? []]) {
|
|
59500
|
+
if (!typing)
|
|
59501
|
+
continue;
|
|
59502
|
+
const conjugated = typing.conjugate === true;
|
|
59503
|
+
for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
|
|
59504
|
+
const text = ref?.$refText?.trim();
|
|
59505
|
+
if (text)
|
|
59506
|
+
out.push({ text, simple: simpleTypeName(text), conjugated });
|
|
59507
|
+
}
|
|
59508
|
+
}
|
|
59509
|
+
return out;
|
|
59510
|
+
}
|
|
59511
|
+
function specializedNamesOf(node) {
|
|
59512
|
+
const decl = node;
|
|
59513
|
+
const out = [];
|
|
59514
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
59515
|
+
if (!rel.kind || !SPECIALIZATION_KINDS2.has(rel.kind))
|
|
59516
|
+
continue;
|
|
59517
|
+
for (const target of rel.targets ?? []) {
|
|
59518
|
+
const text = target.trim();
|
|
59519
|
+
if (text)
|
|
59520
|
+
out.push(text);
|
|
59521
|
+
}
|
|
59522
|
+
}
|
|
59523
|
+
return out;
|
|
59524
|
+
}
|
|
59525
|
+
function compositionGroupsOf(node) {
|
|
59526
|
+
const decl = node;
|
|
59527
|
+
const out = [];
|
|
59528
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
59529
|
+
if (!rel.kind || !COMPOSITION_KINDS.has(rel.kind))
|
|
59530
|
+
continue;
|
|
59531
|
+
const targets = (rel.targets ?? []).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
59532
|
+
if (targets.length > 0)
|
|
59533
|
+
out.push({ kind: rel.kind, targets });
|
|
59534
|
+
}
|
|
59535
|
+
return out;
|
|
59536
|
+
}
|
|
59537
|
+
function isAbstractDecl(node) {
|
|
59538
|
+
return (node.modifiers ?? []).includes("abstract");
|
|
59539
|
+
}
|
|
59540
|
+
var SCALAR_ROOT_KINDS = {
|
|
59541
|
+
String: "string",
|
|
59542
|
+
Boolean: "boolean",
|
|
59543
|
+
NumericalValue: "number",
|
|
59544
|
+
Number: "number",
|
|
59545
|
+
Integer: "number",
|
|
59546
|
+
Rational: "number",
|
|
59547
|
+
Real: "number",
|
|
59548
|
+
Complex: "number",
|
|
59549
|
+
Natural: "number",
|
|
59550
|
+
Positive: "number",
|
|
59551
|
+
Cardinal: "number"
|
|
59552
|
+
};
|
|
59553
|
+
function literalKindOf(node) {
|
|
59554
|
+
if (!node)
|
|
59555
|
+
return void 0;
|
|
59556
|
+
switch (node.$type) {
|
|
59557
|
+
case "LiteralStr":
|
|
59558
|
+
return "string";
|
|
59559
|
+
case "LiteralBool":
|
|
59560
|
+
return "boolean";
|
|
59561
|
+
case "NumericPrimary":
|
|
59562
|
+
return "number";
|
|
59563
|
+
// A signed literal is still a literal of the same kind.
|
|
59564
|
+
case "UnaryMinusExpr":
|
|
59565
|
+
case "UnaryPlusExpr":
|
|
59566
|
+
return literalKindOf(node.operand);
|
|
59567
|
+
// A single-item parenthesis carries its item's kind through.
|
|
59568
|
+
case "ParenExpr": {
|
|
59569
|
+
const items = node.items ?? [];
|
|
59570
|
+
return items.length === 1 ? literalKindOf(items[0]) : void 0;
|
|
59571
|
+
}
|
|
59572
|
+
default:
|
|
59573
|
+
return void 0;
|
|
59574
|
+
}
|
|
59575
|
+
}
|
|
59576
|
+
var BOOLEAN_RESULT_OPS = /* @__PURE__ */ new Set([
|
|
59577
|
+
"and",
|
|
59578
|
+
"&",
|
|
59579
|
+
"or",
|
|
59580
|
+
"|",
|
|
59581
|
+
"xor",
|
|
59582
|
+
"implies",
|
|
59583
|
+
"==",
|
|
59584
|
+
"!=",
|
|
59585
|
+
"===",
|
|
59586
|
+
"!==",
|
|
59587
|
+
"<",
|
|
59588
|
+
"<=",
|
|
59589
|
+
">",
|
|
59590
|
+
">=",
|
|
59591
|
+
"hastype",
|
|
59592
|
+
"istype",
|
|
59593
|
+
"@",
|
|
59594
|
+
"@@"
|
|
59595
|
+
]);
|
|
59596
|
+
var NUMERIC_RESULT_OPS = /* @__PURE__ */ new Set(["-", "*", "/", "%", "**", "^"]);
|
|
59597
|
+
function expressionKindOf(node) {
|
|
59598
|
+
if (!node)
|
|
59599
|
+
return void 0;
|
|
59600
|
+
const literal = literalKindOf(node);
|
|
59601
|
+
if (literal)
|
|
59602
|
+
return literal;
|
|
59603
|
+
switch (node.$type) {
|
|
59604
|
+
case "NotExpr":
|
|
59605
|
+
case "QuantifierExpr":
|
|
59606
|
+
case "SelfClassifyExpr":
|
|
59607
|
+
return "boolean";
|
|
59608
|
+
case "ClassifyOp": {
|
|
59609
|
+
const op = node.op;
|
|
59610
|
+
return op && BOOLEAN_RESULT_OPS.has(op) ? "boolean" : void 0;
|
|
59611
|
+
}
|
|
59612
|
+
case "ParenExpr": {
|
|
59613
|
+
const items = node.items ?? [];
|
|
59614
|
+
return items.length === 1 ? expressionKindOf(items[0]) : void 0;
|
|
59615
|
+
}
|
|
59616
|
+
case "UnaryMinusExpr":
|
|
59617
|
+
case "UnaryPlusExpr": {
|
|
59618
|
+
return expressionKindOf(node.operand) === "number" ? "number" : void 0;
|
|
59619
|
+
}
|
|
59620
|
+
case "IfExpr": {
|
|
59621
|
+
const branch = node;
|
|
59622
|
+
const left = expressionKindOf(branch.thenExpr ?? branch.then);
|
|
59623
|
+
const right = expressionKindOf(branch.elseExpr ?? branch.else);
|
|
59624
|
+
return left && left === right ? left : void 0;
|
|
59625
|
+
}
|
|
59626
|
+
case "BinExpr": {
|
|
59627
|
+
const bin = node;
|
|
59628
|
+
const op = bin.op;
|
|
59629
|
+
if (!op)
|
|
59630
|
+
return void 0;
|
|
59631
|
+
if (BOOLEAN_RESULT_OPS.has(op))
|
|
59632
|
+
return "boolean";
|
|
59633
|
+
if (NUMERIC_RESULT_OPS.has(op))
|
|
59634
|
+
return "number";
|
|
59635
|
+
const left = expressionKindOf(bin.left);
|
|
59636
|
+
return (op === "+" || op === "??") && left && left === expressionKindOf(bin.right) ? left : void 0;
|
|
59637
|
+
}
|
|
59638
|
+
default:
|
|
59639
|
+
return void 0;
|
|
59640
|
+
}
|
|
59641
|
+
}
|
|
59642
|
+
var ConformanceModel = class {
|
|
59643
|
+
resolve;
|
|
59644
|
+
closures = /* @__PURE__ */ new Map();
|
|
59645
|
+
/**
|
|
59646
|
+
* @param resolve A written type name → its declaration, or `undefined` when
|
|
59647
|
+
* the name is absent, ambiguous, or its document is not loaded. The
|
|
59648
|
+
* validator supplies its `resolveUnique`, so an ambiguous name is treated
|
|
59649
|
+
* exactly as an unreadable one: it makes the walk incomplete rather than
|
|
59650
|
+
* resolving to an arbitrary same-named element.
|
|
59651
|
+
*/
|
|
59652
|
+
constructor(resolve7) {
|
|
59653
|
+
this.resolve = resolve7;
|
|
59654
|
+
}
|
|
59655
|
+
/** The transitive supertype names of the type written as `name`. */
|
|
59656
|
+
closureOf(name) {
|
|
59657
|
+
return this.walk(name, /* @__PURE__ */ new Set());
|
|
59658
|
+
}
|
|
59659
|
+
// The closure is keyed by SIMPLE name throughout: a supertype is written
|
|
59660
|
+
// qualified in one file and bare in the next, and both spell the same type.
|
|
59661
|
+
// Two unrelated types that share a simple name can therefore look related —
|
|
59662
|
+
// which only ever makes a check stay silent, never fire.
|
|
59663
|
+
walk(name, visiting) {
|
|
59664
|
+
const key = name.trim();
|
|
59665
|
+
const simple = simpleTypeName(key);
|
|
59666
|
+
const cached = this.closures.get(key);
|
|
59667
|
+
if (cached)
|
|
59668
|
+
return cached;
|
|
59669
|
+
if (visiting.has(key) || visiting.size >= MAX_CLOSURE_DEPTH) {
|
|
59670
|
+
return { names: /* @__PURE__ */ new Set([simple]), complete: false };
|
|
59671
|
+
}
|
|
59672
|
+
const node = this.resolve(key);
|
|
59673
|
+
if (!node)
|
|
59674
|
+
return { names: /* @__PURE__ */ new Set([simple]), complete: false };
|
|
59675
|
+
visiting.add(key);
|
|
59676
|
+
const names = /* @__PURE__ */ new Set([simple]);
|
|
59677
|
+
let complete = true;
|
|
59678
|
+
const absorb = (closure3) => {
|
|
59679
|
+
for (const each of closure3.names)
|
|
59680
|
+
names.add(each);
|
|
59681
|
+
complete &&= closure3.complete;
|
|
59682
|
+
};
|
|
59683
|
+
for (const supertype of [...declaredTypesOf(node).map((t) => t.text), ...specializedNamesOf(node)]) {
|
|
59684
|
+
absorb(this.walk(supertype, visiting));
|
|
59685
|
+
}
|
|
59686
|
+
for (const group of compositionGroupsOf(node)) {
|
|
59687
|
+
if (group.kind === "intersects") {
|
|
59688
|
+
for (const operand of group.targets)
|
|
59689
|
+
absorb(this.walk(operand, visiting));
|
|
59690
|
+
} else if (group.kind === "differences") {
|
|
59691
|
+
absorb(this.walk(group.targets[0], visiting));
|
|
59692
|
+
} else {
|
|
59693
|
+
let shared;
|
|
59694
|
+
for (const operand of group.targets) {
|
|
59695
|
+
const closure3 = this.walk(operand, visiting);
|
|
59696
|
+
complete &&= closure3.complete;
|
|
59697
|
+
shared = shared === void 0 ? new Set(closure3.names) : new Set([...shared].filter((each) => closure3.names.has(each)));
|
|
59698
|
+
}
|
|
59699
|
+
for (const each of shared ?? [])
|
|
59700
|
+
names.add(each);
|
|
59701
|
+
}
|
|
59702
|
+
}
|
|
59703
|
+
visiting.delete(key);
|
|
59704
|
+
const closure2 = { names, complete };
|
|
59705
|
+
this.closures.set(key, closure2);
|
|
59706
|
+
return closure2;
|
|
59707
|
+
}
|
|
59708
|
+
/** Does the type written as `subName` specialize the type written as `superName`? */
|
|
59709
|
+
conforms(subName, superName) {
|
|
59710
|
+
const target = simpleTypeName(superName);
|
|
59711
|
+
const closure2 = this.closureOf(subName);
|
|
59712
|
+
if (closure2.names.has(target))
|
|
59713
|
+
return "conforms";
|
|
59714
|
+
return closure2.complete ? "unrelated" : "unknown";
|
|
59715
|
+
}
|
|
59716
|
+
/** Are two written types related in EITHER direction? Used where the model
|
|
59717
|
+
* states an equality (a binding, a flow payload) rather than a refinement. */
|
|
59718
|
+
compatible(a2, b) {
|
|
59719
|
+
const forward = this.conforms(a2, b);
|
|
59720
|
+
if (forward === "conforms")
|
|
59721
|
+
return "conforms";
|
|
59722
|
+
const backward = this.conforms(b, a2);
|
|
59723
|
+
if (backward === "conforms")
|
|
59724
|
+
return "conforms";
|
|
59725
|
+
if (forward === "unknown" || backward === "unknown")
|
|
59726
|
+
return "unknown";
|
|
59727
|
+
return "unrelated";
|
|
59728
|
+
}
|
|
59729
|
+
/** The declaration a written type name names, when it is readable. */
|
|
59730
|
+
declarationOf(name) {
|
|
59731
|
+
return this.resolve(name);
|
|
59732
|
+
}
|
|
59733
|
+
/**
|
|
59734
|
+
* The literal shape a declared type accepts, or `undefined` when the model
|
|
59735
|
+
* does not say. Two independent sources agree on the answer:
|
|
59736
|
+
* • the specialization closure reaching one of the ScalarValues roots, and
|
|
59737
|
+
* • the precomputed dimension table, which knows every `*Value` quantity of
|
|
59738
|
+
* the OMG `Quantities and Units` library is numeric — so `MassValue` is
|
|
59739
|
+
* decided without parsing a single library file.
|
|
59740
|
+
* A closure that reaches two DIFFERENT roots is a model defect of its own
|
|
59741
|
+
* and is reported as undecided here rather than guessed.
|
|
59742
|
+
*/
|
|
59743
|
+
literalKindAccepted(typeName) {
|
|
59744
|
+
const closure2 = this.closureOf(typeName);
|
|
59745
|
+
let kind;
|
|
59746
|
+
for (const name of closure2.names) {
|
|
59747
|
+
const root3 = SCALAR_ROOT_KINDS[name] ?? (quantityDimension(name) ? "number" : void 0);
|
|
59748
|
+
if (!root3)
|
|
59749
|
+
continue;
|
|
59750
|
+
if (kind && kind !== root3)
|
|
59751
|
+
return void 0;
|
|
59752
|
+
kind = root3;
|
|
59753
|
+
}
|
|
59754
|
+
return kind;
|
|
59755
|
+
}
|
|
59756
|
+
};
|
|
59757
|
+
|
|
59425
59758
|
// ../language-server/out/src/services/validator.js
|
|
59426
59759
|
var severityOverrides = {};
|
|
59427
59760
|
function setSeverityOverrides(overrides) {
|
|
@@ -59494,7 +59827,7 @@ function maskNonCode(text) {
|
|
|
59494
59827
|
}
|
|
59495
59828
|
return out.join("");
|
|
59496
59829
|
}
|
|
59497
|
-
var
|
|
59830
|
+
var SPECIALIZATION_KINDS3 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
59498
59831
|
var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
|
|
59499
59832
|
"AssignNode",
|
|
59500
59833
|
"SendNode",
|
|
@@ -60737,6 +61070,336 @@ ${baseIndent}}`;
|
|
|
60737
61070
|
this.checkInverseOfTargets(decl, index, accept);
|
|
60738
61071
|
this.checkTypeComposition(decl, index, accept);
|
|
60739
61072
|
}
|
|
61073
|
+
this.checkTypeConformance(decls, index, accept);
|
|
61074
|
+
}
|
|
61075
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
61076
|
+
// REQ-390 — SSM017-SSM021: whole-model type conformance (issue #104)
|
|
61077
|
+
// ══════════════════════════════════════════════════════════════════════
|
|
61078
|
+
// Every check below is silent unless the model says otherwise DEFINITIVELY:
|
|
61079
|
+
// `ConformanceModel` answers `unrelated` only when it read every supertype on
|
|
61080
|
+
// the walk, so a type rooted in the unparsed standard library yields
|
|
61081
|
+
// `unknown` and no diagnostic. That is what keeps the OMG corpus clean while
|
|
61082
|
+
// still catching the workspace-local mistakes these codes exist for.
|
|
61083
|
+
checkTypeConformance(decls, index, accept) {
|
|
61084
|
+
const model = new ConformanceModel((name) => this.resolveUnique(name, index));
|
|
61085
|
+
for (const decl of decls) {
|
|
61086
|
+
this.checkRedefinitionTypeConformance(decl, model, index, accept);
|
|
61087
|
+
this.checkValueAssignability(decl, model, accept);
|
|
61088
|
+
this.checkAbstractTyping(decl, model, accept);
|
|
61089
|
+
this.checkConnectorEndTypes(decl, model, index, accept);
|
|
61090
|
+
this.checkFlowPayload(decl, model, index, accept);
|
|
61091
|
+
this.checkDefinitionDomain(decl, model, accept);
|
|
61092
|
+
this.checkGuardIsBoolean(decl, accept);
|
|
61093
|
+
this.checkAssignmentValue(decl, model, index, accept);
|
|
61094
|
+
this.checkActionParameterCorrespondence(decl, model, accept);
|
|
61095
|
+
this.checkRedefinitionDirection(decl, index, accept);
|
|
61096
|
+
this.checkInterfaceEndTypes(decl, model, index, accept);
|
|
61097
|
+
}
|
|
61098
|
+
}
|
|
61099
|
+
// REQ-390 — SSM017: a redefining feature narrows the feature it redefines, so
|
|
61100
|
+
// its type must specialize the redefined feature's type (OMG KerML 8.4.4.5.4
|
|
61101
|
+
// Redefinition; SysML v2 Part 1 §7.7.4). Re-typing to something unrelated
|
|
61102
|
+
// silently produces a feature that no longer fits where the original did.
|
|
61103
|
+
// KSM002 already guards the multiplicity half of the same rule.
|
|
61104
|
+
checkRedefinitionTypeConformance(decl, model, index, accept) {
|
|
61105
|
+
const mine = soleDeclaredType(decl);
|
|
61106
|
+
if (!mine || mine.conjugated)
|
|
61107
|
+
return;
|
|
61108
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
61109
|
+
const kind = rel.kind;
|
|
61110
|
+
if (kind !== ":>>" && kind !== "redefines")
|
|
61111
|
+
continue;
|
|
61112
|
+
for (const target of rel.targets ?? []) {
|
|
61113
|
+
const redefined = this.resolveUnique(target, index);
|
|
61114
|
+
if (!redefined)
|
|
61115
|
+
continue;
|
|
61116
|
+
const theirs = soleDeclaredType(redefined);
|
|
61117
|
+
if (!theirs || theirs.conjugated)
|
|
61118
|
+
continue;
|
|
61119
|
+
if (model.conforms(mine.text, theirs.text) !== "unrelated")
|
|
61120
|
+
continue;
|
|
61121
|
+
accept(severity("SSM017", "error"), DIAGNOSTIC_MESSAGES.SSM017_REDEFINITION_TYPE(simpleTypeName(target), mine.text, theirs.text), { node: decl, code: "SSM017", relatedInformation: declarationSite(redefined, target) });
|
|
61122
|
+
}
|
|
61123
|
+
}
|
|
61124
|
+
}
|
|
61125
|
+
// REQ-390 — SSM018: a BINDING connector asserts that its two ends have the
|
|
61126
|
+
// same values (OMG KerML 8.2.5.5.2 BindingConnector; SysML v2 Part 1
|
|
61127
|
+
// §7.9.4), so their types must be related — one specializing the other, or
|
|
61128
|
+
// both the same. Nothing can be both a `Fuel` and a `Signal`, so a binding
|
|
61129
|
+
// across unrelated types describes a model that cannot hold.
|
|
61130
|
+
//
|
|
61131
|
+
// A plain `connect` is deliberately NOT judged, and the OMG corpus is why:
|
|
61132
|
+
// Annex A's SimpleVehicleModel connects `DiffPort` to `AxlePort` and
|
|
61133
|
+
// `ShaftPort_a` to `ShaftPort_b`, four bare port definitions with nothing in
|
|
61134
|
+
// common. A connection relates two things — it does not equate them — so
|
|
61135
|
+
// conformance is not a rule there, and the deeper interface-end rule (an
|
|
61136
|
+
// `interface def`'s own ends constraining what its usages may connect) is
|
|
61137
|
+
// the remaining part of issue #104's connector bullet.
|
|
61138
|
+
//
|
|
61139
|
+
// A conjugated end is skipped throughout: `~T` inverts the type's directions
|
|
61140
|
+
// and is exactly how two `T` ends are legitimately joined.
|
|
61141
|
+
checkConnectorEndTypes(decl, model, index, accept) {
|
|
61142
|
+
const keyword = BINDING_KEYWORDS[decl.$type];
|
|
61143
|
+
if (!keyword)
|
|
61144
|
+
return;
|
|
61145
|
+
for (const [sourcePath, targetPath] of binaryConnectorEnds(decl)) {
|
|
61146
|
+
const source = this.endType(sourcePath, index);
|
|
61147
|
+
const target = this.endType(targetPath, index);
|
|
61148
|
+
if (!source || !target)
|
|
61149
|
+
continue;
|
|
61150
|
+
if (source.conjugated || target.conjugated)
|
|
61151
|
+
continue;
|
|
61152
|
+
if (model.compatible(source.text, target.text) !== "unrelated")
|
|
61153
|
+
continue;
|
|
61154
|
+
accept(severity("SSM018", "error"), DIAGNOSTIC_MESSAGES.SSM018_CONNECTOR_END_TYPES(keyword, source.text, target.text), { node: decl, code: "SSM018" });
|
|
61155
|
+
}
|
|
61156
|
+
}
|
|
61157
|
+
/** The declared type of a connector end, when the end resolves unambiguously
|
|
61158
|
+
* to a usage carrying exactly one written type. */
|
|
61159
|
+
endType(path10, index) {
|
|
61160
|
+
const node = this.resolveUnique(path10, index);
|
|
61161
|
+
if (!node || node.isDef === true)
|
|
61162
|
+
return void 0;
|
|
61163
|
+
return soleDeclaredType(node);
|
|
61164
|
+
}
|
|
61165
|
+
// REQ-390 — SSM019: a feature's value must be a value of its type (OMG KerML
|
|
61166
|
+
// 8.4.4.7 FeatureValue). Only BARE LITERALS are judged, against types whose
|
|
61167
|
+
// scalar root the model can name — `ScalarValues` reached through the
|
|
61168
|
+
// specialization closure, or a `Quantities and Units` value type named by the
|
|
61169
|
+
// dimension table. Anything computed keeps its silence: inferring the type of
|
|
61170
|
+
// an arbitrary expression is the deferred half of issue #104.
|
|
61171
|
+
checkValueAssignability(decl, model, accept) {
|
|
61172
|
+
const declared = soleDeclaredType(decl);
|
|
61173
|
+
if (!declared || declared.conjugated)
|
|
61174
|
+
return;
|
|
61175
|
+
const expected = model.literalKindAccepted(declared.text);
|
|
61176
|
+
if (!expected)
|
|
61177
|
+
return;
|
|
61178
|
+
const withDefault = decl;
|
|
61179
|
+
for (const value of [withDefault.value, withDefault.default?.value]) {
|
|
61180
|
+
const actual = expressionKindOf(value);
|
|
61181
|
+
if (!actual || actual === expected)
|
|
61182
|
+
continue;
|
|
61183
|
+
accept(severity("SSM019", "error"), DIAGNOSTIC_MESSAGES.SSM019_VALUE_TYPE(declared.text, expected, actual), { node: value, code: "SSM019" });
|
|
61184
|
+
}
|
|
61185
|
+
}
|
|
61186
|
+
// REQ-390 — SSM020: a flow's payload travels from its source feature to its
|
|
61187
|
+
// target feature, so each end must be able to hold it (OMG SysML v2 Part 1
|
|
61188
|
+
// §7.12 ItemFlow / PayloadFeature). Reported per end, and only when the end
|
|
61189
|
+
// resolves unambiguously and carries exactly one written type.
|
|
61190
|
+
checkFlowPayload(decl, model, index, accept) {
|
|
61191
|
+
if (decl.$type !== "FlowStmt")
|
|
61192
|
+
return;
|
|
61193
|
+
const flow = decl;
|
|
61194
|
+
const payload = flowPayloadType(flow.payload);
|
|
61195
|
+
if (!payload || payload.conjugated)
|
|
61196
|
+
return;
|
|
61197
|
+
for (const [endKind, path10] of [["source", flow.source], ["target", flow.target]]) {
|
|
61198
|
+
if (!path10)
|
|
61199
|
+
continue;
|
|
61200
|
+
const end = this.resolveUnique(path10, index);
|
|
61201
|
+
const endType = end ? soleDeclaredType(end) : void 0;
|
|
61202
|
+
if (!endType || endType.conjugated)
|
|
61203
|
+
continue;
|
|
61204
|
+
if (model.compatible(payload.text, endType.text) !== "unrelated")
|
|
61205
|
+
continue;
|
|
61206
|
+
accept(severity("SSM020", "error"), DIAGNOSTIC_MESSAGES.SSM020_FLOW_PAYLOAD(payload.text, endKind, endType.text), { node: decl, code: "SSM020" });
|
|
61207
|
+
}
|
|
61208
|
+
}
|
|
61209
|
+
// REQ-390 — SSM021: a usage typed ONLY by an abstract definition names no
|
|
61210
|
+
// complete form (OMG SysML v2 Part 1 §7.4.2 — an abstract definition
|
|
61211
|
+
// classifies nothing on its own; every instance belongs to a specialization).
|
|
61212
|
+
// Deliberately narrow, because typing against an abstract definition is a
|
|
61213
|
+
// normal intermediate step:
|
|
61214
|
+
// · the usage itself may be `abstract`, a `variation`, or a `variant`;
|
|
61215
|
+
// · it may narrow the abstract type through a further `:>`/`subsets`/
|
|
61216
|
+
// `redefines`, which is the sanctioned way to reach a concrete form;
|
|
61217
|
+
// · a definition is not a usage — `part def A :> AbstractB` is ordinary
|
|
61218
|
+
// specialization and is not touched;
|
|
61219
|
+
// · a usage that owns members refines the type in place.
|
|
61220
|
+
// What is left is the case the code is for: a leaf usage that says only
|
|
61221
|
+
// "one of these", where the model never says which. It defaults to a HINT,
|
|
61222
|
+
// not an error — the text is legal, and the modeller may be mid-decomposition.
|
|
61223
|
+
checkAbstractTyping(decl, model, accept) {
|
|
61224
|
+
if (decl.isDef === true || !isCompositeOrRefUsage(decl))
|
|
61225
|
+
return;
|
|
61226
|
+
if (isAbstractDecl(decl))
|
|
61227
|
+
return;
|
|
61228
|
+
const modifiers2 = decl.modifiers ?? [];
|
|
61229
|
+
if (modifiers2.includes("variation") || modifiers2.includes("variant"))
|
|
61230
|
+
return;
|
|
61231
|
+
if (specializedNamesOf(decl).length > 0)
|
|
61232
|
+
return;
|
|
61233
|
+
if ((decl.members ?? []).length > 0)
|
|
61234
|
+
return;
|
|
61235
|
+
const declared = soleDeclaredType(decl);
|
|
61236
|
+
if (!declared || declared.conjugated)
|
|
61237
|
+
return;
|
|
61238
|
+
const type = model.declarationOf(declared.text);
|
|
61239
|
+
if (!type || !isAbstractDecl(type) || type.isDef !== true)
|
|
61240
|
+
return;
|
|
61241
|
+
accept(severity("SSM021", "hint"), DIAGNOSTIC_MESSAGES.SSM021_ABSTRACT_TYPE(decl.name ?? `this ${kindLabel(decl)}`, declared.text), { node: decl, code: "SSM021", relatedInformation: declarationSite(type, declared.text) });
|
|
61242
|
+
}
|
|
61243
|
+
// REQ-390 — SSM022: a usage names a definition of ITS OWN kind (OMG SysML v2
|
|
61244
|
+
// Part 1 §7.2 — every usage kind has a matching definition kind, and §7.4's
|
|
61245
|
+
// `Usage::definition` is typed to it). `part p : SomeAttributeDef` is not a
|
|
61246
|
+
// narrower part, it is a category error the rest of the model then inherits.
|
|
61247
|
+
//
|
|
61248
|
+
// Judged only when the written type resolves to a SysML DEFINITION whose
|
|
61249
|
+
// keyword is knowable. A KerML classifier (`class`, `struct`, `datatype`,
|
|
61250
|
+
// `behavior`) is always accepted — a SysML definition specializes the kernel,
|
|
61251
|
+
// and typing a usage straight against a kernel classifier is legal — as is
|
|
61252
|
+
// anything the workspace cannot read. `USAGE_DEFINITION_DOMAINS` errs WIDE,
|
|
61253
|
+
// admitting each kind's metamodel supertypes (a part definition is an item
|
|
61254
|
+
// definition, a case definition is an action definition), so only genuinely
|
|
61255
|
+
// disjoint families are reported.
|
|
61256
|
+
checkDefinitionDomain(decl, model, accept) {
|
|
61257
|
+
if (decl.isDef === true)
|
|
61258
|
+
return;
|
|
61259
|
+
const domain = USAGE_DEFINITION_DOMAINS[decl.$type];
|
|
61260
|
+
if (!domain)
|
|
61261
|
+
return;
|
|
61262
|
+
for (const declared of declaredTypesOf(decl)) {
|
|
61263
|
+
const type = model.declarationOf(declared.text);
|
|
61264
|
+
if (!type || type.isDef !== true)
|
|
61265
|
+
continue;
|
|
61266
|
+
if (domain.allowed.has(type.$type))
|
|
61267
|
+
continue;
|
|
61268
|
+
accept(severity("SSM022", "error"), DIAGNOSTIC_MESSAGES.SSM022_DEFINITION_DOMAIN(domain.keyword, declared.text, kindLabel(type), domain.expected), { node: decl, code: "SSM022", relatedInformation: declarationSite(type, declared.text) });
|
|
61269
|
+
}
|
|
61270
|
+
}
|
|
61271
|
+
// REQ-390 — SSM023: a guard decides whether a transition or succession is
|
|
61272
|
+
// taken, so it must be able to be true or false (OMG SysML v2 Part 1 §7.19.4
|
|
61273
|
+
// TransitionUsage `guard`, §7.17.5 GuardedSuccession). Uses the same
|
|
61274
|
+
// conservative "definitely not Boolean" test as KSM008 on filter conditions —
|
|
61275
|
+
// a bare feature path may well resolve to a Boolean attribute and is left
|
|
61276
|
+
// alone; a string, a quantity, or an arithmetic expression cannot.
|
|
61277
|
+
checkGuardIsBoolean(decl, accept) {
|
|
61278
|
+
const guard = decl.guard;
|
|
61279
|
+
if (!guard)
|
|
61280
|
+
return;
|
|
61281
|
+
const nonBoolean = isDefinitelyNonBoolean(guard) || expressionKindOf(guard) === "string" || expressionKindOf(guard) === "number";
|
|
61282
|
+
if (!nonBoolean)
|
|
61283
|
+
return;
|
|
61284
|
+
accept(severity("SSM023", "error"), DIAGNOSTIC_MESSAGES.SSM023_GUARD_NOT_BOOLEAN(GUARD_CONSTRUCTS[decl.$type] ?? "succession"), { node: guard, code: "SSM023" });
|
|
61285
|
+
}
|
|
61286
|
+
// REQ-390 — SSM024: `assign x := expr` writes a value into a feature, so the
|
|
61287
|
+
// same rule SSM019 applies to a declared value applies here (OMG SysML v2
|
|
61288
|
+
// Part 1 §7.17.7 AssignmentActionUsage). The target is a feature path; only
|
|
61289
|
+
// an unambiguously resolved one carrying exactly one written type is judged.
|
|
61290
|
+
checkAssignmentValue(decl, model, index, accept) {
|
|
61291
|
+
if (decl.$type !== "AssignNode")
|
|
61292
|
+
return;
|
|
61293
|
+
const node = decl;
|
|
61294
|
+
if (!node.target || !node.value)
|
|
61295
|
+
return;
|
|
61296
|
+
const target = this.resolveUnique(node.target, index);
|
|
61297
|
+
const declared = target ? soleDeclaredType(target) : void 0;
|
|
61298
|
+
if (!declared || declared.conjugated)
|
|
61299
|
+
return;
|
|
61300
|
+
const expected = model.literalKindAccepted(declared.text);
|
|
61301
|
+
const actual = expressionKindOf(node.value);
|
|
61302
|
+
if (!expected || !actual || expected === actual)
|
|
61303
|
+
return;
|
|
61304
|
+
accept(severity("SSM024", "error"), DIAGNOSTIC_MESSAGES.SSM024_ASSIGNMENT_VALUE(node.target, declared.text, expected, actual), { node: node.value, code: "SSM024" });
|
|
61305
|
+
}
|
|
61306
|
+
// REQ-390 — SSM025: an action usage's directed parameters correspond
|
|
61307
|
+
// POSITIONALLY to its definition's (OMG SysML v2 Part 1 §7.16.4 — the n-th
|
|
61308
|
+
// parameter of the usage implicitly redefines the n-th of the definition).
|
|
61309
|
+
// Two consequences are checkable without modelling implicit redefinition
|
|
61310
|
+
// itself: the usage cannot declare more parameters than there are to
|
|
61311
|
+
// correspond to, and a parameter it does declare cannot reverse the
|
|
61312
|
+
// direction of the one it lines up with.
|
|
61313
|
+
//
|
|
61314
|
+
// A parameter that redefines EXPLICITLY is skipped — it names its
|
|
61315
|
+
// counterpart rather than taking it by position, and SSM026 judges that one.
|
|
61316
|
+
checkActionParameterCorrespondence(decl, model, accept) {
|
|
61317
|
+
if (decl.isDef === true || !PARAMETERIZED_USAGE_TYPES.has(decl.$type))
|
|
61318
|
+
return;
|
|
61319
|
+
const declared = soleDeclaredType(decl);
|
|
61320
|
+
if (!declared || declared.conjugated)
|
|
61321
|
+
return;
|
|
61322
|
+
const definition = model.declarationOf(declared.text);
|
|
61323
|
+
if (!definition || definition.isDef !== true)
|
|
61324
|
+
return;
|
|
61325
|
+
const mine = directedParameters(decl);
|
|
61326
|
+
if (mine.length === 0)
|
|
61327
|
+
return;
|
|
61328
|
+
const theirs = directedParameters(definition);
|
|
61329
|
+
if (theirs.length === 0)
|
|
61330
|
+
return;
|
|
61331
|
+
if (mine.length > theirs.length) {
|
|
61332
|
+
accept(severity("SSM025", "error"), DIAGNOSTIC_MESSAGES.SSM025_ACTION_PARAMETER_COUNT(decl.name ?? `this ${kindLabel(decl)}`, mine.length, declared.text, theirs.length), { node: mine[theirs.length].node, code: "SSM025" });
|
|
61333
|
+
return;
|
|
61334
|
+
}
|
|
61335
|
+
for (let position = 0; position < mine.length; position += 1) {
|
|
61336
|
+
if (specializedNamesOf(mine[position].node).length > 0)
|
|
61337
|
+
continue;
|
|
61338
|
+
if (mine[position].direction === theirs[position].direction)
|
|
61339
|
+
continue;
|
|
61340
|
+
accept(severity("SSM025", "error"), DIAGNOSTIC_MESSAGES.SSM025_ACTION_PARAMETER_DIRECTION(position + 1, mine[position].direction, declared.text, theirs[position].direction), { node: mine[position].node, code: "SSM025" });
|
|
61341
|
+
}
|
|
61342
|
+
}
|
|
61343
|
+
// REQ-390 — SSM026: a redefinition refines the feature it names, and a
|
|
61344
|
+
// feature's direction is part of what it is (OMG KerML 8.4.4.5.4 — a
|
|
61345
|
+
// redefining feature's direction must be consistent with the redefined
|
|
61346
|
+
// one's). Turning an `in` into an `out` does not narrow anything; it
|
|
61347
|
+
// reverses the flow the supertype declared and every caller relies on.
|
|
61348
|
+
// `inout` is compatible with either, so only a straight in/out flip is
|
|
61349
|
+
// reported.
|
|
61350
|
+
checkRedefinitionDirection(decl, index, accept) {
|
|
61351
|
+
const mine = directionOf(decl);
|
|
61352
|
+
if (mine !== "in" && mine !== "out")
|
|
61353
|
+
return;
|
|
61354
|
+
for (const rel of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
|
|
61355
|
+
const kind = rel.kind;
|
|
61356
|
+
if (kind !== ":>>" && kind !== "redefines")
|
|
61357
|
+
continue;
|
|
61358
|
+
for (const target of rel.targets ?? []) {
|
|
61359
|
+
const redefined = this.resolveUnique(target, index);
|
|
61360
|
+
if (!redefined)
|
|
61361
|
+
continue;
|
|
61362
|
+
const theirs = directionOf(redefined);
|
|
61363
|
+
if (theirs !== "in" && theirs !== "out")
|
|
61364
|
+
continue;
|
|
61365
|
+
if (theirs === mine)
|
|
61366
|
+
continue;
|
|
61367
|
+
accept(severity("SSM026", "error"), DIAGNOSTIC_MESSAGES.SSM026_REDEFINITION_DIRECTION(simpleTypeName(target), mine, theirs), { node: decl, code: "SSM026", relatedInformation: declarationSite(redefined, target) });
|
|
61368
|
+
}
|
|
61369
|
+
}
|
|
61370
|
+
}
|
|
61371
|
+
// REQ-390 — SSM027: an interface usage connects through the ends its
|
|
61372
|
+
// definition declares (OMG SysML v2 Part 1 §7.11.3 — an InterfaceUsage's
|
|
61373
|
+
// connector ends redefine the InterfaceDefinition's `end` features, in
|
|
61374
|
+
// order). This is the part of issue #104's connector bullet that survives
|
|
61375
|
+
// the corpus: a plain `connect` states no conformance, but an interface
|
|
61376
|
+
// whose DEFINITION names its end types does.
|
|
61377
|
+
checkInterfaceEndTypes(decl, model, index, accept) {
|
|
61378
|
+
if (decl.$type !== "InterfaceDecl" || decl.isDef === true)
|
|
61379
|
+
return;
|
|
61380
|
+
const declared = soleDeclaredType(decl);
|
|
61381
|
+
if (!declared || declared.conjugated)
|
|
61382
|
+
return;
|
|
61383
|
+
const definition = model.declarationOf(declared.text);
|
|
61384
|
+
if (!definition || definition.isDef !== true)
|
|
61385
|
+
return;
|
|
61386
|
+
const expected = interfaceEndTypes(definition);
|
|
61387
|
+
const connect = decl.connect;
|
|
61388
|
+
const written = [connect?.source, connect?.target];
|
|
61389
|
+
if (expected.length !== written.length)
|
|
61390
|
+
return;
|
|
61391
|
+
for (let position = 0; position < written.length; position += 1) {
|
|
61392
|
+
const path10 = endPath(written[position]);
|
|
61393
|
+
const wanted = expected[position];
|
|
61394
|
+
if (!path10 || !wanted || wanted.conjugated)
|
|
61395
|
+
continue;
|
|
61396
|
+
const end = this.endType(path10, index);
|
|
61397
|
+
if (!end || end.conjugated)
|
|
61398
|
+
continue;
|
|
61399
|
+
if (model.conforms(end.text, wanted.text) !== "unrelated")
|
|
61400
|
+
continue;
|
|
61401
|
+
accept(severity("SSM027", "error"), DIAGNOSTIC_MESSAGES.SSM027_INTERFACE_END_TYPE(position + 1, end.text, declared.text, wanted.text), { node: decl, code: "SSM027" });
|
|
61402
|
+
}
|
|
60740
61403
|
}
|
|
60741
61404
|
// ══════════════════════════════════════════════════════════════════════
|
|
60742
61405
|
// REQ-160 — occurrence portions: `timeslice` / `snapshot` well-formedness
|
|
@@ -61768,7 +62431,7 @@ function specializationTargets(node) {
|
|
|
61768
62431
|
...node.relationships ?? []
|
|
61769
62432
|
];
|
|
61770
62433
|
for (const rel of rels) {
|
|
61771
|
-
if (rel.kind &&
|
|
62434
|
+
if (rel.kind && SPECIALIZATION_KINDS3.has(rel.kind))
|
|
61772
62435
|
out.push(...rel.targets);
|
|
61773
62436
|
}
|
|
61774
62437
|
return out;
|
|
@@ -61821,6 +62484,103 @@ function literalBound(b) {
|
|
|
61821
62484
|
function sameDocument(a2, b) {
|
|
61822
62485
|
return ast_utils_exports.getDocument(a2).uri.toString() === ast_utils_exports.getDocument(b).uri.toString();
|
|
61823
62486
|
}
|
|
62487
|
+
function soleDeclaredType(node) {
|
|
62488
|
+
const types = declaredTypesOf(node);
|
|
62489
|
+
return types.length === 1 ? types[0] : void 0;
|
|
62490
|
+
}
|
|
62491
|
+
function declarationSite(node, label) {
|
|
62492
|
+
const range = node.$cstNode?.range;
|
|
62493
|
+
if (!range)
|
|
62494
|
+
return void 0;
|
|
62495
|
+
return [{
|
|
62496
|
+
location: { uri: ast_utils_exports.getDocument(node).uri.toString(), range },
|
|
62497
|
+
message: `'${simpleTypeName(label)}' is declared here`
|
|
62498
|
+
}];
|
|
62499
|
+
}
|
|
62500
|
+
var BINDING_KEYWORDS = {
|
|
62501
|
+
BindStmt: "bind",
|
|
62502
|
+
BindingDecl: "binding",
|
|
62503
|
+
BindingConnectorStmt: "binding"
|
|
62504
|
+
};
|
|
62505
|
+
function endPath(end) {
|
|
62506
|
+
const path10 = end?.path?.trim();
|
|
62507
|
+
return path10 && path10.length > 0 ? path10 : void 0;
|
|
62508
|
+
}
|
|
62509
|
+
function binaryConnectorEnds(decl) {
|
|
62510
|
+
const node = decl;
|
|
62511
|
+
const pairs = [];
|
|
62512
|
+
const push2 = (a2, b) => {
|
|
62513
|
+
const from = endPath(a2);
|
|
62514
|
+
const to = endPath(b);
|
|
62515
|
+
if (from && to)
|
|
62516
|
+
pairs.push([from, to]);
|
|
62517
|
+
};
|
|
62518
|
+
push2(node.source, node.target);
|
|
62519
|
+
push2(node.left, node.right);
|
|
62520
|
+
return pairs;
|
|
62521
|
+
}
|
|
62522
|
+
function flowPayloadType(payload) {
|
|
62523
|
+
if (!payload)
|
|
62524
|
+
return void 0;
|
|
62525
|
+
const bare = payload.type?.$refText?.trim();
|
|
62526
|
+
if (bare)
|
|
62527
|
+
return { text: bare, simple: simpleTypeName(bare), conjugated: false };
|
|
62528
|
+
return soleDeclaredType(payload);
|
|
62529
|
+
}
|
|
62530
|
+
function isCompositeOrRefUsage(node) {
|
|
62531
|
+
return COMPOSITE_FEATURE_USAGE_TYPES.has(node.$type) && node.isDef !== true;
|
|
62532
|
+
}
|
|
62533
|
+
var USAGE_DEFINITION_DOMAINS = {
|
|
62534
|
+
PartDecl: { keyword: "part", expected: "a 'part def' (or the 'item def' / 'occurrence def' it specializes)", allowed: /* @__PURE__ */ new Set(["PartDecl", "ItemDecl", "OccurrenceDecl"]) },
|
|
62535
|
+
ItemDecl: { keyword: "item", expected: "an 'item def' (a 'part def' is one)", allowed: /* @__PURE__ */ new Set(["ItemDecl", "PartDecl", "OccurrenceDecl"]) },
|
|
62536
|
+
PortDecl: { keyword: "port", expected: "a 'port def'", allowed: /* @__PURE__ */ new Set(["PortDecl"]) },
|
|
62537
|
+
AttributeDecl: { keyword: "attribute", expected: "an 'attribute def' or an 'enum def'", allowed: /* @__PURE__ */ new Set(["AttributeDecl", "EnumDecl"]) },
|
|
62538
|
+
EnumDecl: { keyword: "enum", expected: "an 'enum def'", allowed: /* @__PURE__ */ new Set(["EnumDecl", "AttributeDecl"]) },
|
|
62539
|
+
OccurrenceDecl: { keyword: "occurrence", expected: "an 'occurrence def', 'part def' or 'item def'", allowed: /* @__PURE__ */ new Set(["OccurrenceDecl", "PartDecl", "ItemDecl"]) },
|
|
62540
|
+
ActionDecl: { keyword: "action", expected: "an 'action def' (or a 'calc def' / 'case def', which are ones)", allowed: /* @__PURE__ */ new Set(["ActionDecl", "CalcDecl", "CaseDecl", "UseCaseDecl", "AnalysisCaseDecl", "VerificationCaseDecl", "StateDecl"]) },
|
|
62541
|
+
StateDecl: { keyword: "state", expected: "a 'state def' (an 'action def' is one)", allowed: /* @__PURE__ */ new Set(["StateDecl", "ActionDecl"]) },
|
|
62542
|
+
CalcDecl: { keyword: "calc", expected: "a 'calc def' (an 'action def' is one)", allowed: /* @__PURE__ */ new Set(["CalcDecl", "ActionDecl", "CaseDecl", "AnalysisCaseDecl"]) },
|
|
62543
|
+
ConstraintDecl: { keyword: "constraint", expected: "a 'constraint def' (a 'requirement def' is one)", allowed: /* @__PURE__ */ new Set(["ConstraintDecl", "RequirementDecl"]) },
|
|
62544
|
+
RequirementDecl: { keyword: "requirement", expected: "a 'requirement def' (a 'constraint def' is one)", allowed: /* @__PURE__ */ new Set(["RequirementDecl", "ConstraintDecl", "ConcernDecl"]) },
|
|
62545
|
+
ConcernDecl: { keyword: "concern", expected: "a 'concern def' (a 'requirement def' is one)", allowed: /* @__PURE__ */ new Set(["ConcernDecl", "RequirementDecl", "ConstraintDecl"]) },
|
|
62546
|
+
ConnectionDecl: { keyword: "connection", expected: "a 'connection def' (an 'interface def' / 'allocation def' is one)", allowed: /* @__PURE__ */ new Set(["ConnectionDecl", "InterfaceDecl", "AllocationDecl", "PartDecl", "ItemDecl"]) },
|
|
62547
|
+
InterfaceDecl: { keyword: "interface", expected: "an 'interface def' (a 'connection def' is one)", allowed: /* @__PURE__ */ new Set(["InterfaceDecl", "ConnectionDecl"]) },
|
|
62548
|
+
AllocationDecl: { keyword: "allocation", expected: "an 'allocation def' (a 'connection def' is one)", allowed: /* @__PURE__ */ new Set(["AllocationDecl", "ConnectionDecl"]) },
|
|
62549
|
+
ViewDecl: { keyword: "view", expected: "a 'view def'", allowed: /* @__PURE__ */ new Set(["ViewDecl", "PartDecl"]) },
|
|
62550
|
+
ViewpointDecl: { keyword: "viewpoint", expected: "a 'viewpoint def' (a 'requirement def' is one)", allowed: /* @__PURE__ */ new Set(["ViewpointDecl", "RequirementDecl", "ConcernDecl"]) },
|
|
62551
|
+
RenderingDecl: { keyword: "rendering", expected: "a 'rendering def'", allowed: /* @__PURE__ */ new Set(["RenderingDecl", "PartDecl"]) },
|
|
62552
|
+
MetadataDecl: { keyword: "metadata", expected: "a 'metadata def'", allowed: /* @__PURE__ */ new Set(["MetadataDecl"]) }
|
|
62553
|
+
};
|
|
62554
|
+
var GUARD_CONSTRUCTS = {
|
|
62555
|
+
TransitionDecl: "transition",
|
|
62556
|
+
SuccessionStmt: "succession",
|
|
62557
|
+
TransitionStmt: "transition"
|
|
62558
|
+
};
|
|
62559
|
+
var PARAMETERIZED_USAGE_TYPES = /* @__PURE__ */ new Set([
|
|
62560
|
+
"ActionDecl",
|
|
62561
|
+
"CalcDecl",
|
|
62562
|
+
"CaseDecl",
|
|
62563
|
+
"UseCaseDecl",
|
|
62564
|
+
"AnalysisCaseDecl",
|
|
62565
|
+
"VerificationCaseDecl",
|
|
62566
|
+
"ConstraintDecl"
|
|
62567
|
+
]);
|
|
62568
|
+
var PARAMETER_DIRECTIONS = /* @__PURE__ */ new Set(["in", "out", "inout"]);
|
|
62569
|
+
function directionOf(node) {
|
|
62570
|
+
return (node.modifiers ?? []).find((modifier) => PARAMETER_DIRECTIONS.has(modifier));
|
|
62571
|
+
}
|
|
62572
|
+
function directedParameters(node) {
|
|
62573
|
+
const out = [];
|
|
62574
|
+
for (const member of node.members ?? []) {
|
|
62575
|
+
const direction = directionOf(member);
|
|
62576
|
+
if (direction)
|
|
62577
|
+
out.push({ node: member, direction });
|
|
62578
|
+
}
|
|
62579
|
+
return out;
|
|
62580
|
+
}
|
|
62581
|
+
function interfaceEndTypes(definition) {
|
|
62582
|
+
return (definition.members ?? []).filter((member) => member.$type === "EndDecl" || member.modifiers?.includes("end")).map((member) => soleDeclaredType(member));
|
|
62583
|
+
}
|
|
61824
62584
|
var NON_BOOLEAN_BIN_OPS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "^", ".."]);
|
|
61825
62585
|
function isDefinitelyNonBoolean(node) {
|
|
61826
62586
|
const type = node.$type;
|
|
@@ -62651,7 +63411,7 @@ function trailingBlockBody(node) {
|
|
|
62651
63411
|
}
|
|
62652
63412
|
|
|
62653
63413
|
// ../language-server/out/src/services/document-symbol-provider.js
|
|
62654
|
-
var
|
|
63414
|
+
var SPECIALIZATION_KINDS4 = /* @__PURE__ */ new Set([":>", "specializes"]);
|
|
62655
63415
|
var REDEFINITION_KINDS = /* @__PURE__ */ new Set([":>>", "redefines"]);
|
|
62656
63416
|
var INHERITABLE_FEATURE_TYPES = /* @__PURE__ */ new Set([
|
|
62657
63417
|
"ActionDecl",
|
|
@@ -62720,7 +63480,7 @@ function specializationTargets2(node) {
|
|
|
62720
63480
|
const n = node;
|
|
62721
63481
|
const out = [];
|
|
62722
63482
|
for (const rel of [...n.preRelationships ?? [], ...n.relationships ?? []]) {
|
|
62723
|
-
if (rel.kind &&
|
|
63483
|
+
if (rel.kind && SPECIALIZATION_KINDS4.has(rel.kind))
|
|
62724
63484
|
out.push(...rel.targets ?? []);
|
|
62725
63485
|
}
|
|
62726
63486
|
return out;
|
|
@@ -64341,24 +65101,46 @@ var MULTIPLICITY_TEMPLATES = [
|
|
|
64341
65101
|
insertText,
|
|
64342
65102
|
detail: "Multiplicity"
|
|
64343
65103
|
}));
|
|
65104
|
+
var ARROW_FUNCTION_LIBRARIES = /* @__PURE__ */ new Set([
|
|
65105
|
+
"ControlFunctions",
|
|
65106
|
+
"SequenceFunctions",
|
|
65107
|
+
"CollectionFunctions"
|
|
65108
|
+
]);
|
|
64344
65109
|
var ARROW_FUNCTIONS = [
|
|
65110
|
+
// ControlFunctions — take a body expression over each element.
|
|
65111
|
+
["collect", "collect { in ${1:x}; ${0:x} }"],
|
|
65112
|
+
["select", "select { in ${1:x}; ${0:true} }"],
|
|
65113
|
+
["selectOne", "selectOne { in ${1:x}; ${0:true} }"],
|
|
65114
|
+
["reject", "reject { in ${1:x}; ${0:false} }"],
|
|
65115
|
+
["reduce", "reduce ${0:'+'}"],
|
|
65116
|
+
["forAll", "forAll { in ${1:x}; ${0:true} }"],
|
|
65117
|
+
["exists", "exists { in ${1:x}; ${0:true} }"],
|
|
65118
|
+
["minimize", "minimize { in ${1:x}; ${0:x} }"],
|
|
65119
|
+
["maximize", "maximize { in ${1:x}; ${0:x} }"],
|
|
65120
|
+
["allTrue", "allTrue()"],
|
|
65121
|
+
["anyTrue", "anyTrue()"],
|
|
65122
|
+
// SequenceFunctions / CollectionFunctions — size and element access.
|
|
64345
65123
|
["size", "size()"],
|
|
64346
65124
|
["isEmpty", "isEmpty()"],
|
|
64347
65125
|
["notEmpty", "notEmpty()"],
|
|
64348
|
-
["at", "at(${1:index})"],
|
|
64349
65126
|
["head", "head()"],
|
|
64350
65127
|
["tail", "tail()"],
|
|
64351
|
-
["
|
|
64352
|
-
["
|
|
64353
|
-
|
|
64354
|
-
["
|
|
64355
|
-
["
|
|
64356
|
-
["
|
|
64357
|
-
["
|
|
64358
|
-
["
|
|
64359
|
-
["
|
|
64360
|
-
["
|
|
64361
|
-
["
|
|
65128
|
+
["last", "last()"],
|
|
65129
|
+
["subsequence", "subsequence(${1:startIndex}, ${0:endIndex})"],
|
|
65130
|
+
// Membership and set algebra.
|
|
65131
|
+
["includes", "includes(${0:item})"],
|
|
65132
|
+
["includesOnly", "includesOnly(${0:other})"],
|
|
65133
|
+
["excludes", "excludes(${0:item})"],
|
|
65134
|
+
["contains", "contains(${0:item})"],
|
|
65135
|
+
["containsAll", "containsAll(${0:other})"],
|
|
65136
|
+
["including", "including(${0:values})"],
|
|
65137
|
+
["includingAt", "includingAt(${1:values}, ${0:index})"],
|
|
65138
|
+
["excluding", "excluding(${0:values})"],
|
|
65139
|
+
["excludingAt", "excludingAt(${1:startIndex}, ${0:endIndex})"],
|
|
65140
|
+
["union", "union(${0:other})"],
|
|
65141
|
+
["intersection", "intersection(${0:other})"],
|
|
65142
|
+
["equals", "equals(${0:other})"],
|
|
65143
|
+
["same", "same(${0:other})"]
|
|
64362
65144
|
].map(([label, insertText]) => ({
|
|
64363
65145
|
label,
|
|
64364
65146
|
kind: import_vscode_languageserver16.CompletionItemKind.Function,
|
|
@@ -64551,6 +65333,10 @@ var SNIPPETS = [
|
|
|
64551
65333
|
];
|
|
64552
65334
|
var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
64553
65335
|
indexManager;
|
|
65336
|
+
// REQ-242 — issue #103: member completion resolves the written receiver with
|
|
65337
|
+
// the same service that answers go-to-definition, so `.` offers exactly the
|
|
65338
|
+
// members navigation can reach — including inherited and cross-file ones.
|
|
65339
|
+
featurePaths;
|
|
64554
65340
|
// REQ-245, REQ-268 — Qualified names of every indexed element, keyed by the
|
|
64555
65341
|
// element it names. Built once per workspace build and evicted with the rest
|
|
64556
65342
|
// of the workspace caches; see [[qualifiedNamesByElement]].
|
|
@@ -64561,6 +65347,7 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
|
64561
65347
|
constructor(services) {
|
|
64562
65348
|
super(services);
|
|
64563
65349
|
this.indexManager = services.shared.workspace.IndexManager;
|
|
65350
|
+
this.featurePaths = new FeaturePathResolver(services);
|
|
64564
65351
|
this.qualifiedNameCache = new WorkspaceCache(services.shared);
|
|
64565
65352
|
}
|
|
64566
65353
|
async getCompletion(document, params) {
|
|
@@ -64591,6 +65378,21 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
|
64591
65378
|
item.labelDetails = { description: categoryLabel(category), ...item.labelDetails ?? {} };
|
|
64592
65379
|
}
|
|
64593
65380
|
}
|
|
65381
|
+
// REQ-242 — issue #103: a `CompletionItem` keeps only a label and the AST
|
|
65382
|
+
// type name, so once Langium has produced a cross-reference item there is no
|
|
65383
|
+
// way back to the description that justified it. Record the two facts the
|
|
65384
|
+
// typing filter needs while the description is still in hand.
|
|
65385
|
+
createReferenceCompletionItem(nodeDescription) {
|
|
65386
|
+
const item = super.createReferenceCompletionItem(nodeDescription);
|
|
65387
|
+
return {
|
|
65388
|
+
...item,
|
|
65389
|
+
data: {
|
|
65390
|
+
...item.data,
|
|
65391
|
+
isDefinition: isDefinitionDescription(nodeDescription),
|
|
65392
|
+
isDottedPath: nodeDescription.name.includes(".")
|
|
65393
|
+
}
|
|
65394
|
+
};
|
|
65395
|
+
}
|
|
64594
65396
|
filterDefaultsForContext(items, context) {
|
|
64595
65397
|
if (context.kind === "package-body" || context.kind === "member-body")
|
|
64596
65398
|
return;
|
|
@@ -64604,11 +65406,15 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
|
64604
65406
|
allowedLabels.add("subsets");
|
|
64605
65407
|
allowedLabels.add("redefines");
|
|
64606
65408
|
}
|
|
65409
|
+
const definitionsOnly = context.kind === "typing";
|
|
65410
|
+
const rejectDottedPaths = definitionsOnly || context.kind === "specialization";
|
|
64607
65411
|
const allowedTypes = new Set(this.symbolTypesForContext(context));
|
|
64608
65412
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
64609
65413
|
const item = items[i];
|
|
64610
65414
|
const detail = typeof item.detail === "string" ? item.detail : void 0;
|
|
64611
|
-
if (allowedLabels.has(item.label)
|
|
65415
|
+
if (allowedLabels.has(item.label))
|
|
65416
|
+
continue;
|
|
65417
|
+
if (detail && allowedTypes.has(detail) && (!definitionsOnly || isDefinitionItem(item)) && (!rejectDottedPaths || !isDottedPathItem(item)))
|
|
64612
65418
|
continue;
|
|
64613
65419
|
items.splice(i, 1);
|
|
64614
65420
|
}
|
|
@@ -64647,14 +65453,17 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
|
64647
65453
|
detail: "Conjugated port type"
|
|
64648
65454
|
})));
|
|
64649
65455
|
}
|
|
65456
|
+
if (context.kind === "specialization") {
|
|
65457
|
+
addUnique(items, this.inheritedFeatureItems(document, offset, context));
|
|
65458
|
+
}
|
|
64650
65459
|
return;
|
|
64651
65460
|
}
|
|
64652
65461
|
case "member-access": {
|
|
64653
|
-
addUnique(items, this.memberAccessItems(document, context.receiver));
|
|
65462
|
+
addUnique(items, this.memberAccessItems(document, context.receiver, offset));
|
|
64654
65463
|
return;
|
|
64655
65464
|
}
|
|
64656
65465
|
case "arrow": {
|
|
64657
|
-
addUnique(items,
|
|
65466
|
+
addUnique(items, this.arrowFunctionItems());
|
|
64658
65467
|
return;
|
|
64659
65468
|
}
|
|
64660
65469
|
case "import": {
|
|
@@ -64786,24 +65595,54 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
|
|
|
64786
65595
|
}
|
|
64787
65596
|
return items;
|
|
64788
65597
|
}
|
|
64789
|
-
memberAccessItems(document, receiver) {
|
|
65598
|
+
memberAccessItems(document, receiver, offset) {
|
|
64790
65599
|
if (!receiver)
|
|
64791
65600
|
return [];
|
|
64792
65601
|
const root3 = document.parseResult.value;
|
|
64793
|
-
const
|
|
65602
|
+
const context = smallestNodeAtOffset(root3, offset) ?? root3;
|
|
65603
|
+
const members = this.featurePaths.membersForPath(context, receiverSteps(receiver));
|
|
64794
65604
|
return members.map((node) => this.itemForNode(node)).filter(isDefined);
|
|
64795
65605
|
}
|
|
64796
65606
|
connectPortItems(document, offset) {
|
|
64797
65607
|
const root3 = document.parseResult.value;
|
|
64798
65608
|
const enclosing = smallestNodeAtOffset(root3, offset);
|
|
64799
65609
|
const owner = nearestMemberOwner(enclosing) ?? root3;
|
|
64800
|
-
return collectReachablePorts(owner).map((path10) => ({
|
|
65610
|
+
return collectReachablePorts(owner, (node) => this.featurePaths.visibleMembers(node)).map((path10) => ({
|
|
64801
65611
|
label: path10,
|
|
64802
65612
|
kind: import_vscode_languageserver16.CompletionItemKind.Interface,
|
|
64803
65613
|
detail: "Reachable port",
|
|
64804
65614
|
sortText: "0"
|
|
64805
65615
|
}));
|
|
64806
65616
|
}
|
|
65617
|
+
// REQ-242 — issue #103: `subsets` and `redefines` name a FEATURE of the
|
|
65618
|
+
// enclosing declaration, and the ones worth offering are normally the
|
|
65619
|
+
// inherited ones — refining a feature the supertype introduced is what the
|
|
65620
|
+
// operators are for. Those features are declared in another namespace, so
|
|
65621
|
+
// no scope rooted at the current one reaches them; walk the enclosing
|
|
65622
|
+
// declaration's own supertypes instead. The declaration being written is
|
|
65623
|
+
// excluded, so `part frontWheels :>` never offers `frontWheels`.
|
|
65624
|
+
inheritedFeatureItems(document, offset, context) {
|
|
65625
|
+
const root3 = document.parseResult.value;
|
|
65626
|
+
const owner = nearestMemberOwner(smallestNodeAtOffset(root3, offset));
|
|
65627
|
+
if (!owner)
|
|
65628
|
+
return [];
|
|
65629
|
+
const allowed = new Set(this.symbolTypesForContext(context));
|
|
65630
|
+
return this.featurePaths.visibleMembers(owner).filter((node) => allowed.has(node.$type) && isUsage(node) && !coversOffset(node, offset)).map((node) => this.itemForNode(node)).filter(isDefined);
|
|
65631
|
+
}
|
|
65632
|
+
// REQ-242 — issue #103: the curated table carries the argument shapes, but
|
|
65633
|
+
// the vendored library is the authority on WHICH functions exist. Merge in
|
|
65634
|
+
// any collection-processing function the index knows and the table does not,
|
|
65635
|
+
// so a library revision does not silently stop being offered.
|
|
65636
|
+
arrowFunctionItems() {
|
|
65637
|
+
const items = [...ARROW_FUNCTIONS];
|
|
65638
|
+
addUnique(items, this.indexManager.allElements().filter((desc) => desc.type === "FunctionDecl" || desc.type === "PredicateDecl").map((desc) => desc.name.split("::")).filter((parts) => parts.length === 2 && ARROW_FUNCTION_LIBRARIES.has(parts[0]) && isArrowInvocableName(parts[1])).map((parts) => ({
|
|
65639
|
+
label: parts[1],
|
|
65640
|
+
kind: import_vscode_languageserver16.CompletionItemKind.Function,
|
|
65641
|
+
detail: "Kernel Function Library",
|
|
65642
|
+
sortText: "0"
|
|
65643
|
+
})).toArray());
|
|
65644
|
+
return items;
|
|
65645
|
+
}
|
|
64807
65646
|
unitSymbolItems() {
|
|
64808
65647
|
const symbols = getDimensionTable()?.unitSymbols ?? COMMON_UNIT_SYMBOLS;
|
|
64809
65648
|
return symbols.map((symbol) => ({
|
|
@@ -64959,9 +65798,21 @@ function isPackageBody(prefix) {
|
|
|
64959
65798
|
function elementKey(desc) {
|
|
64960
65799
|
return `${desc.documentUri.toString()}#${desc.path}#${desc.type}`;
|
|
64961
65800
|
}
|
|
65801
|
+
function isArrowInvocableName(name) {
|
|
65802
|
+
return /^[\p{L}_][\p{L}\p{N}_]*$/u.test(name);
|
|
65803
|
+
}
|
|
64962
65804
|
function isDefinitionDescription(desc) {
|
|
64963
65805
|
const node = desc.node;
|
|
64964
|
-
|
|
65806
|
+
if (node?.isDef !== void 0)
|
|
65807
|
+
return node.isDef === true;
|
|
65808
|
+
const usage = desc.isUsage;
|
|
65809
|
+
return usage !== true;
|
|
65810
|
+
}
|
|
65811
|
+
function isDefinitionItem(item) {
|
|
65812
|
+
return item.data?.isDefinition !== false;
|
|
65813
|
+
}
|
|
65814
|
+
function isDottedPathItem(item) {
|
|
65815
|
+
return item.data?.isDottedPath === true;
|
|
64965
65816
|
}
|
|
64966
65817
|
function addUnique(items, additions) {
|
|
64967
65818
|
const labels = new Map(items.map((item, index) => [item.label, index]));
|
|
@@ -65015,54 +65866,33 @@ function isUsage(node) {
|
|
|
65015
65866
|
const isDef = node.isDef;
|
|
65016
65867
|
return isDef === void 0 || isDef === false;
|
|
65017
65868
|
}
|
|
65018
|
-
function
|
|
65019
|
-
const
|
|
65020
|
-
|
|
65021
|
-
|
|
65022
|
-
|
|
65023
|
-
|
|
65024
|
-
|
|
65025
|
-
|
|
65026
|
-
|
|
65027
|
-
const refText = ref.$refText;
|
|
65028
|
-
if (typeof refText !== "string")
|
|
65029
|
-
return void 0;
|
|
65030
|
-
return findNamedNode(ast_utils_exports.getDocument(node).parseResult.value, simpleName(refText), { definitionsOnly: true });
|
|
65031
|
-
}
|
|
65032
|
-
function resolveReceiverMembers(root3, receiver) {
|
|
65033
|
-
let current2 = findNamedNode(root3, simpleName(receiver.split(/[.:]+/u)[0]));
|
|
65034
|
-
for (const segment of receiver.split(/(?:\.|::)/u).slice(1)) {
|
|
65035
|
-
current2 = collectMembersWithTyped(current2).find((member) => nodeName(member) === segment);
|
|
65036
|
-
if (!current2)
|
|
65037
|
-
return [];
|
|
65038
|
-
}
|
|
65039
|
-
return collectMembersWithTyped(current2);
|
|
65040
|
-
}
|
|
65041
|
-
function collectMembersWithTyped(node) {
|
|
65042
|
-
if (!node)
|
|
65043
|
-
return [];
|
|
65044
|
-
const members = [...nodeMembers(node)];
|
|
65045
|
-
const typed = typingTarget(node);
|
|
65046
|
-
if (typed && typed !== node) {
|
|
65047
|
-
members.push(...nodeMembers(typed));
|
|
65869
|
+
function receiverSteps(receiver) {
|
|
65870
|
+
const steps = [];
|
|
65871
|
+
const pattern = /(::|\.)?\s*([\p{L}_'][\p{L}\p{N}_']*)/gu;
|
|
65872
|
+
let match;
|
|
65873
|
+
while ((match = pattern.exec(receiver)) !== null) {
|
|
65874
|
+
steps.push({
|
|
65875
|
+
text: unquoteName2(match[2]),
|
|
65876
|
+
separator: steps.length === 0 ? void 0 : match[1]
|
|
65877
|
+
});
|
|
65048
65878
|
}
|
|
65049
|
-
return
|
|
65879
|
+
return steps;
|
|
65050
65880
|
}
|
|
65051
|
-
function collectReachablePorts(owner) {
|
|
65881
|
+
function collectReachablePorts(owner, members) {
|
|
65052
65882
|
const seenOwners = /* @__PURE__ */ new Set();
|
|
65053
65883
|
const paths = /* @__PURE__ */ new Set();
|
|
65054
65884
|
const visitOwner = (node, prefix) => {
|
|
65055
65885
|
if (!node || seenOwners.has(node))
|
|
65056
65886
|
return;
|
|
65057
65887
|
seenOwners.add(node);
|
|
65058
|
-
for (const member of
|
|
65888
|
+
for (const member of members(node)) {
|
|
65059
65889
|
const name = nodeName(member);
|
|
65060
65890
|
if (!name || !isUsage(member))
|
|
65061
65891
|
continue;
|
|
65062
65892
|
if (member.$type === "PortDecl") {
|
|
65063
65893
|
paths.add(`${prefix}${name}`);
|
|
65064
65894
|
} else if (member.$type === "PartDecl") {
|
|
65065
|
-
visitOwner(
|
|
65895
|
+
visitOwner(member, `${prefix}${name}.`);
|
|
65066
65896
|
}
|
|
65067
65897
|
}
|
|
65068
65898
|
seenOwners.delete(node);
|
|
@@ -65070,12 +65900,6 @@ function collectReachablePorts(owner) {
|
|
|
65070
65900
|
visitOwner(owner, "");
|
|
65071
65901
|
return [...paths].sort();
|
|
65072
65902
|
}
|
|
65073
|
-
function findNamedNode(root3, name, options = {}) {
|
|
65074
|
-
if (!name)
|
|
65075
|
-
return void 0;
|
|
65076
|
-
const matches = [root3, ...ast_utils_exports.streamAllContents(root3).toArray()].filter((node) => nodeName(node) === name).filter((node) => !options.definitionsOnly || node.isDef !== false);
|
|
65077
|
-
return matches.find((node) => node.isDef === true) ?? matches[0];
|
|
65078
|
-
}
|
|
65079
65903
|
function smallestNodeAtOffset(root3, offset) {
|
|
65080
65904
|
let best;
|
|
65081
65905
|
for (const node of [root3, ...ast_utils_exports.streamAllContents(root3).toArray()]) {
|
|
@@ -65088,6 +65912,10 @@ function smallestNodeAtOffset(root3, offset) {
|
|
|
65088
65912
|
}
|
|
65089
65913
|
return best;
|
|
65090
65914
|
}
|
|
65915
|
+
function coversOffset(node, offset) {
|
|
65916
|
+
const cst = node.$cstNode;
|
|
65917
|
+
return cst !== void 0 && cst.offset <= offset && cst.end >= offset;
|
|
65918
|
+
}
|
|
65091
65919
|
function nearestMemberOwner(node) {
|
|
65092
65920
|
let current2 = node;
|
|
65093
65921
|
while (current2) {
|
|
@@ -65097,9 +65925,6 @@ function nearestMemberOwner(node) {
|
|
|
65097
65925
|
}
|
|
65098
65926
|
return void 0;
|
|
65099
65927
|
}
|
|
65100
|
-
function uniqueNodes(nodes) {
|
|
65101
|
-
return [...new Set(nodes)];
|
|
65102
|
-
}
|
|
65103
65928
|
function simpleName(name) {
|
|
65104
65929
|
if (!name)
|
|
65105
65930
|
return void 0;
|
|
@@ -65519,12 +66344,12 @@ function importSignature(imp) {
|
|
|
65519
66344
|
const segments = imp.segs.map((seg) => `${seg.name ?? ""}${seg.star ? "*" : ""}${seg.recursive ? "**" : ""}`);
|
|
65520
66345
|
return `${importVisibility(imp)} ${imp.head}::${segments.join("::")}${imp.alias ? ` as ${imp.alias}` : ""}`;
|
|
65521
66346
|
}
|
|
65522
|
-
var
|
|
66347
|
+
var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
65523
66348
|
function specializationTargets3(node) {
|
|
65524
66349
|
const n = node;
|
|
65525
66350
|
const out = [];
|
|
65526
66351
|
for (const rel of [...n.preRelationships ?? [], ...n.relationships ?? []]) {
|
|
65527
|
-
if (rel.kind &&
|
|
66352
|
+
if (rel.kind && SPECIALIZATION_KINDS5.has(rel.kind))
|
|
65528
66353
|
out.push(...rel.targets ?? []);
|
|
65529
66354
|
}
|
|
65530
66355
|
return out;
|
|
@@ -65729,7 +66554,11 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
|
|
|
65729
66554
|
...base,
|
|
65730
66555
|
...visibility ? { visibility } : {},
|
|
65731
66556
|
...visibility === "private" ? { isPrivate: true } : {},
|
|
65732
|
-
...alias.derived ? { isDerivedAlias: true } : {}
|
|
66557
|
+
...alias.derived ? { isDerivedAlias: true } : {},
|
|
66558
|
+
// REQ-242 — issue #103 — mirrors what the precomputed library index
|
|
66559
|
+
// records, so consumers read def-ness the same way for workspace and
|
|
66560
|
+
// library symbols.
|
|
66561
|
+
...node.isDef === false ? { isUsage: true } : {}
|
|
65733
66562
|
};
|
|
65734
66563
|
if (!alias.cstNode)
|
|
65735
66564
|
return description;
|
|
@@ -65801,12 +66630,12 @@ function directImportEntries(imp, descriptions) {
|
|
|
65801
66630
|
}
|
|
65802
66631
|
return entries;
|
|
65803
66632
|
}
|
|
65804
|
-
var
|
|
66633
|
+
var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
|
|
65805
66634
|
function specializationTargets4(node) {
|
|
65806
66635
|
const value = node;
|
|
65807
66636
|
const targets = [];
|
|
65808
66637
|
for (const relationship of [...value.preRelationships ?? [], ...value.relationships ?? []]) {
|
|
65809
|
-
if (relationship.kind &&
|
|
66638
|
+
if (relationship.kind && SPECIALIZATION_KINDS6.has(relationship.kind)) {
|
|
65810
66639
|
targets.push(...relationship.targets ?? []);
|
|
65811
66640
|
}
|
|
65812
66641
|
}
|
|
@@ -69183,7 +70012,7 @@ async function runValidation(command) {
|
|
|
69183
70012
|
}
|
|
69184
70013
|
|
|
69185
70014
|
// src/main.ts
|
|
69186
|
-
var VERSION2 = true ? "0.15.
|
|
70015
|
+
var VERSION2 = true ? "0.15.7" : "dev";
|
|
69187
70016
|
async function main(argv) {
|
|
69188
70017
|
const command = parseArgs(argv);
|
|
69189
70018
|
if (command.kind === "help") {
|