sysml-v2-lsp 0.33.0 → 0.34.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/CHANGELOG.md +12 -0
- package/dist/server/browserServerMain.js +20 -39
- package/dist/server/mcpServer.js +20 -39
- package/dist/server/server.js +20 -39
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.34.0]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add `.github/copilot-instructions.md` requiring language-affecting changes to be validated against the latest OMG SysML and KerML specifications, with cited clauses or grammar productions and a regression test.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Report only an element's own multiplicity: a definition or usage no longer takes the multiplicity of a nested element (`part def Car { part : Engine[2]; }` gave `Car` the multiplicity `2`), and a unit in a default value (`default 0 [kg]`) is no longer reported as a multiplicity. SysML definitions cannot declare a multiplicity (`DefinitionDeclaration`); a usage's comes from its own `FeatureSpecializationPart`. `sysml/model` now reads multiplicity from the parse tree, so a usage whose multiplicity follows a specialization (`item :>> edges [3..4]`) reports it correctly.
|
|
14
|
+
- A connection or interface no longer reports the multiplicity of one of its ends (`connection c connect [2] a.p to [1] b.p;`): a `ConnectorEnd`'s cross multiplicity belongs to the end, not the connector.
|
|
15
|
+
- Elements named with an unreserved KerML keyword (`step`, `function`, `type`, `member`, `feature`, `behavior`, `var`, `multiplicity`, ...) keep their name, which the grammar allows (`name : IDENTIFIER | STRING | unreservedKeyword`). They were reported as anonymous, e.g. `perform action step[2];` was shown as `[2]`, and `alias multiplicity for degeneracy;` was named after its target.
|
|
16
|
+
|
|
5
17
|
## [0.33.0]
|
|
6
18
|
|
|
7
19
|
### Added
|
|
@@ -131838,7 +131838,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
131838
131838
|
const child = ctx.getChild(i);
|
|
131839
131839
|
if (child instanceof TerminalNode) {
|
|
131840
131840
|
const token = child.symbol;
|
|
131841
|
-
if (this.
|
|
131841
|
+
if (this.isNameTerminal(child)) {
|
|
131842
131842
|
return this.unquoteName(token.text ?? "");
|
|
131843
131843
|
}
|
|
131844
131844
|
}
|
|
@@ -131890,14 +131890,15 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
131890
131890
|
/**
|
|
131891
131891
|
* The first node of rule `ruleIndex` in `ctx`'s own declaration: never
|
|
131892
131892
|
* inside a nested element, its body, its value, a flow's payload or ends,
|
|
131893
|
-
*
|
|
131893
|
+
* a connector end's own multiplicity (`connect [2] a to b`), or a prefix
|
|
131894
|
+
* such as `#metadata`.
|
|
131894
131895
|
*/
|
|
131895
131896
|
findOwnHeaderRule(ctx, ruleIndex) {
|
|
131896
131897
|
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
131897
131898
|
const child = ctx.getChild(i);
|
|
131898
131899
|
if (!(child instanceof ParserRuleContext)) continue;
|
|
131899
131900
|
if (child.ruleIndex === ruleIndex) return child;
|
|
131900
|
-
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || this.isPrefixOrExtensionContext(child)) continue;
|
|
131901
|
+
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_ownedCrossMultiplicityMember || this.isPrefixOrExtensionContext(child)) continue;
|
|
131901
131902
|
const found = this.findOwnHeaderRule(child, ruleIndex);
|
|
131902
131903
|
if (found) return found;
|
|
131903
131904
|
}
|
|
@@ -132061,7 +132062,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
132061
132062
|
extractNameRange(ctx) {
|
|
132062
132063
|
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
132063
132064
|
const child = ctx.getChild(i);
|
|
132064
|
-
if (child instanceof TerminalNode && this.
|
|
132065
|
+
if (child instanceof TerminalNode && this.isNameTerminal(child)) {
|
|
132065
132066
|
return tokenToRange(child.symbol);
|
|
132066
132067
|
}
|
|
132067
132068
|
if (child instanceof ParserRuleContext) {
|
|
@@ -132246,12 +132247,12 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
132246
132247
|
return lines.join("\n").trim();
|
|
132247
132248
|
}
|
|
132248
132249
|
/**
|
|
132249
|
-
* Extract multiplicity from a context
|
|
132250
|
-
*
|
|
132250
|
+
* Extract multiplicity from a context's own declaration, never from a
|
|
132251
|
+
* nested element or its body.
|
|
132251
132252
|
* Returns { multiplicity: "1..5", multiplicityRange: { lower: 1, upper: 5 } }
|
|
132252
132253
|
*/
|
|
132253
132254
|
extractMultiplicity(ctx) {
|
|
132254
|
-
const multCtx = this.
|
|
132255
|
+
const multCtx = this.findOwnHeaderRule(ctx, SysMLv2Parser.RULE_multiplicityBounds);
|
|
132255
132256
|
if (!multCtx) {
|
|
132256
132257
|
return {};
|
|
132257
132258
|
}
|
|
@@ -132305,24 +132306,6 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
132305
132306
|
multiplicityRange: { lower, upper }
|
|
132306
132307
|
};
|
|
132307
132308
|
}
|
|
132308
|
-
/**
|
|
132309
|
-
* Recursively search for a MultiplicityBoundsContext in the subtree.
|
|
132310
|
-
*/
|
|
132311
|
-
findMultiplicityBounds(ctx) {
|
|
132312
|
-
if (ctx.ruleIndex === SysMLv2Parser.RULE_multiplicityBounds) {
|
|
132313
|
-
return ctx;
|
|
132314
|
-
}
|
|
132315
|
-
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
132316
|
-
const child = ctx.getChild(i);
|
|
132317
|
-
if (child instanceof ParserRuleContext) {
|
|
132318
|
-
const result = this.findMultiplicityBounds(child);
|
|
132319
|
-
if (result) {
|
|
132320
|
-
return result;
|
|
132321
|
-
}
|
|
132322
|
-
}
|
|
132323
|
-
}
|
|
132324
|
-
return void 0;
|
|
132325
|
-
}
|
|
132326
132309
|
/**
|
|
132327
132310
|
* Whether a context is a prefix metadata or definition/usage prefix rule.
|
|
132328
132311
|
* These contain annotation identifiers (e.g. from `#product`) that should
|
|
@@ -132364,6 +132347,14 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
132364
132347
|
if (this.isQuotedName(text)) return true;
|
|
132365
132348
|
return /^[a-zA-Z_]/.test(text) && !this.isKeyword(text);
|
|
132366
132349
|
}
|
|
132350
|
+
/**
|
|
132351
|
+
* Whether a terminal is (part of) a name: an identifier, a quoted name, or
|
|
132352
|
+
* a KerML keyword such as `step` or `function` that the grammar parsed as a
|
|
132353
|
+
* name (`name : IDENTIFIER | STRING | unreservedKeyword`).
|
|
132354
|
+
*/
|
|
132355
|
+
isNameTerminal(node) {
|
|
132356
|
+
return this.isIdentifierToken(node.symbol) || node.parent?.ruleIndex === SysMLv2Parser.RULE_unreservedKeyword;
|
|
132357
|
+
}
|
|
132367
132358
|
/**
|
|
132368
132359
|
* Check if text is a SysML quoted name (single-quoted string).
|
|
132369
132360
|
*/
|
|
@@ -132733,7 +132724,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
132733
132724
|
const child = ctx.getChild(i);
|
|
132734
132725
|
if (child instanceof TerminalNode) {
|
|
132735
132726
|
const text = child.symbol.text;
|
|
132736
|
-
if (text && this.
|
|
132727
|
+
if (text && this.isNameTerminal(child)) {
|
|
132737
132728
|
parts.push(this.unquoteName(text));
|
|
132738
132729
|
}
|
|
132739
132730
|
} else if (child instanceof ParserRuleContext) {
|
|
@@ -137049,9 +137040,8 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
137049
137040
|
if (direction) {
|
|
137050
137041
|
attributes["direction"] = direction;
|
|
137051
137042
|
}
|
|
137052
|
-
|
|
137053
|
-
|
|
137054
|
-
attributes["multiplicity"] = multiplicity;
|
|
137043
|
+
if (symbol.multiplicity) {
|
|
137044
|
+
attributes["multiplicity"] = symbol.multiplicity;
|
|
137055
137045
|
}
|
|
137056
137046
|
const modifier = this.extractModifier(symbol, lines);
|
|
137057
137047
|
if (modifier) {
|
|
@@ -137669,7 +137659,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
137669
137659
|
name: c.name,
|
|
137670
137660
|
kind: toMetaclassName(c.kind),
|
|
137671
137661
|
type: c.typeNames.join(", ") || void 0,
|
|
137672
|
-
multiplicity: c.multiplicity
|
|
137662
|
+
multiplicity: c.multiplicity,
|
|
137673
137663
|
direction,
|
|
137674
137664
|
visibility: c.visibility,
|
|
137675
137665
|
isDerived: modifier?.split(", ").includes("derived") ?? false,
|
|
@@ -137793,15 +137783,6 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
137793
137783
|
if (containsWord(elementText, "out")) return "out";
|
|
137794
137784
|
return void 0;
|
|
137795
137785
|
}
|
|
137796
|
-
/** Extract multiplicity (e.g., [4], [0..*]) from source text. */
|
|
137797
|
-
extractMultiplicity(symbol, lines) {
|
|
137798
|
-
const elementText = this.getElementText(symbol, lines);
|
|
137799
|
-
const open = elementText.indexOf("[");
|
|
137800
|
-
if (open < 0) return void 0;
|
|
137801
|
-
const close = elementText.indexOf("]", open + 1);
|
|
137802
|
-
if (close < 0) return void 0;
|
|
137803
|
-
return elementText.substring(open + 1, close);
|
|
137804
|
-
}
|
|
137805
137786
|
/** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
|
|
137806
137787
|
extractModifier(symbol, lines) {
|
|
137807
137788
|
const elementText = this.getElementText(symbol, lines);
|
package/dist/server/mcpServer.js
CHANGED
|
@@ -160758,7 +160758,7 @@ var SymbolTable = class {
|
|
|
160758
160758
|
const child = ctx2.getChild(i);
|
|
160759
160759
|
if (child instanceof TerminalNode) {
|
|
160760
160760
|
const token = child.symbol;
|
|
160761
|
-
if (this.
|
|
160761
|
+
if (this.isNameTerminal(child)) {
|
|
160762
160762
|
return this.unquoteName(token.text ?? "");
|
|
160763
160763
|
}
|
|
160764
160764
|
}
|
|
@@ -160810,14 +160810,15 @@ var SymbolTable = class {
|
|
|
160810
160810
|
/**
|
|
160811
160811
|
* The first node of rule `ruleIndex` in `ctx`'s own declaration: never
|
|
160812
160812
|
* inside a nested element, its body, its value, a flow's payload or ends,
|
|
160813
|
-
*
|
|
160813
|
+
* a connector end's own multiplicity (`connect [2] a to b`), or a prefix
|
|
160814
|
+
* such as `#metadata`.
|
|
160814
160815
|
*/
|
|
160815
160816
|
findOwnHeaderRule(ctx2, ruleIndex) {
|
|
160816
160817
|
for (let i = 0; i < ctx2.getChildCount(); i++) {
|
|
160817
160818
|
const child = ctx2.getChild(i);
|
|
160818
160819
|
if (!(child instanceof ParserRuleContext)) continue;
|
|
160819
160820
|
if (child.ruleIndex === ruleIndex) return child;
|
|
160820
|
-
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || this.isPrefixOrExtensionContext(child)) continue;
|
|
160821
|
+
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_ownedCrossMultiplicityMember || this.isPrefixOrExtensionContext(child)) continue;
|
|
160821
160822
|
const found = this.findOwnHeaderRule(child, ruleIndex);
|
|
160822
160823
|
if (found) return found;
|
|
160823
160824
|
}
|
|
@@ -160981,7 +160982,7 @@ var SymbolTable = class {
|
|
|
160981
160982
|
extractNameRange(ctx2) {
|
|
160982
160983
|
for (let i = 0; i < ctx2.getChildCount(); i++) {
|
|
160983
160984
|
const child = ctx2.getChild(i);
|
|
160984
|
-
if (child instanceof TerminalNode && this.
|
|
160985
|
+
if (child instanceof TerminalNode && this.isNameTerminal(child)) {
|
|
160985
160986
|
return tokenToRange(child.symbol);
|
|
160986
160987
|
}
|
|
160987
160988
|
if (child instanceof ParserRuleContext) {
|
|
@@ -161166,12 +161167,12 @@ var SymbolTable = class {
|
|
|
161166
161167
|
return lines.join("\n").trim();
|
|
161167
161168
|
}
|
|
161168
161169
|
/**
|
|
161169
|
-
* Extract multiplicity from a context
|
|
161170
|
-
*
|
|
161170
|
+
* Extract multiplicity from a context's own declaration, never from a
|
|
161171
|
+
* nested element or its body.
|
|
161171
161172
|
* Returns { multiplicity: "1..5", multiplicityRange: { lower: 1, upper: 5 } }
|
|
161172
161173
|
*/
|
|
161173
161174
|
extractMultiplicity(ctx2) {
|
|
161174
|
-
const multCtx = this.
|
|
161175
|
+
const multCtx = this.findOwnHeaderRule(ctx2, SysMLv2Parser.RULE_multiplicityBounds);
|
|
161175
161176
|
if (!multCtx) {
|
|
161176
161177
|
return {};
|
|
161177
161178
|
}
|
|
@@ -161225,24 +161226,6 @@ var SymbolTable = class {
|
|
|
161225
161226
|
multiplicityRange: { lower, upper }
|
|
161226
161227
|
};
|
|
161227
161228
|
}
|
|
161228
|
-
/**
|
|
161229
|
-
* Recursively search for a MultiplicityBoundsContext in the subtree.
|
|
161230
|
-
*/
|
|
161231
|
-
findMultiplicityBounds(ctx2) {
|
|
161232
|
-
if (ctx2.ruleIndex === SysMLv2Parser.RULE_multiplicityBounds) {
|
|
161233
|
-
return ctx2;
|
|
161234
|
-
}
|
|
161235
|
-
for (let i = 0; i < ctx2.getChildCount(); i++) {
|
|
161236
|
-
const child = ctx2.getChild(i);
|
|
161237
|
-
if (child instanceof ParserRuleContext) {
|
|
161238
|
-
const result = this.findMultiplicityBounds(child);
|
|
161239
|
-
if (result) {
|
|
161240
|
-
return result;
|
|
161241
|
-
}
|
|
161242
|
-
}
|
|
161243
|
-
}
|
|
161244
|
-
return void 0;
|
|
161245
|
-
}
|
|
161246
161229
|
/**
|
|
161247
161230
|
* Whether a context is a prefix metadata or definition/usage prefix rule.
|
|
161248
161231
|
* These contain annotation identifiers (e.g. from `#product`) that should
|
|
@@ -161284,6 +161267,14 @@ var SymbolTable = class {
|
|
|
161284
161267
|
if (this.isQuotedName(text)) return true;
|
|
161285
161268
|
return /^[a-zA-Z_]/.test(text) && !this.isKeyword(text);
|
|
161286
161269
|
}
|
|
161270
|
+
/**
|
|
161271
|
+
* Whether a terminal is (part of) a name: an identifier, a quoted name, or
|
|
161272
|
+
* a KerML keyword such as `step` or `function` that the grammar parsed as a
|
|
161273
|
+
* name (`name : IDENTIFIER | STRING | unreservedKeyword`).
|
|
161274
|
+
*/
|
|
161275
|
+
isNameTerminal(node2) {
|
|
161276
|
+
return this.isIdentifierToken(node2.symbol) || node2.parent?.ruleIndex === SysMLv2Parser.RULE_unreservedKeyword;
|
|
161277
|
+
}
|
|
161287
161278
|
/**
|
|
161288
161279
|
* Check if text is a SysML quoted name (single-quoted string).
|
|
161289
161280
|
*/
|
|
@@ -161653,7 +161644,7 @@ var SymbolTable = class {
|
|
|
161653
161644
|
const child = ctx2.getChild(i);
|
|
161654
161645
|
if (child instanceof TerminalNode) {
|
|
161655
161646
|
const text = child.symbol.text;
|
|
161656
|
-
if (text && this.
|
|
161647
|
+
if (text && this.isNameTerminal(child)) {
|
|
161657
161648
|
parts.push(this.unquoteName(text));
|
|
161658
161649
|
}
|
|
161659
161650
|
} else if (child instanceof ParserRuleContext) {
|
|
@@ -162080,9 +162071,8 @@ var SysMLModelProvider = class {
|
|
|
162080
162071
|
if (direction) {
|
|
162081
162072
|
attributes["direction"] = direction;
|
|
162082
162073
|
}
|
|
162083
|
-
|
|
162084
|
-
|
|
162085
|
-
attributes["multiplicity"] = multiplicity;
|
|
162074
|
+
if (symbol2.multiplicity) {
|
|
162075
|
+
attributes["multiplicity"] = symbol2.multiplicity;
|
|
162086
162076
|
}
|
|
162087
162077
|
const modifier = this.extractModifier(symbol2, lines);
|
|
162088
162078
|
if (modifier) {
|
|
@@ -162700,7 +162690,7 @@ var SysMLModelProvider = class {
|
|
|
162700
162690
|
name: c.name,
|
|
162701
162691
|
kind: toMetaclassName(c.kind),
|
|
162702
162692
|
type: c.typeNames.join(", ") || void 0,
|
|
162703
|
-
multiplicity: c.multiplicity
|
|
162693
|
+
multiplicity: c.multiplicity,
|
|
162704
162694
|
direction,
|
|
162705
162695
|
visibility: c.visibility,
|
|
162706
162696
|
isDerived: modifier?.split(", ").includes("derived") ?? false,
|
|
@@ -162824,15 +162814,6 @@ var SysMLModelProvider = class {
|
|
|
162824
162814
|
if (containsWord(elementText, "out")) return "out";
|
|
162825
162815
|
return void 0;
|
|
162826
162816
|
}
|
|
162827
|
-
/** Extract multiplicity (e.g., [4], [0..*]) from source text. */
|
|
162828
|
-
extractMultiplicity(symbol2, lines) {
|
|
162829
|
-
const elementText = this.getElementText(symbol2, lines);
|
|
162830
|
-
const open2 = elementText.indexOf("[");
|
|
162831
|
-
if (open2 < 0) return void 0;
|
|
162832
|
-
const close = elementText.indexOf("]", open2 + 1);
|
|
162833
|
-
if (close < 0) return void 0;
|
|
162834
|
-
return elementText.substring(open2 + 1, close);
|
|
162835
|
-
}
|
|
162836
162817
|
/** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
|
|
162837
162818
|
extractModifier(symbol2, lines) {
|
|
162838
162819
|
const elementText = this.getElementText(symbol2, lines);
|
package/dist/server/server.js
CHANGED
|
@@ -123168,7 +123168,7 @@ var SymbolTable = class {
|
|
|
123168
123168
|
const child = ctx.getChild(i);
|
|
123169
123169
|
if (child instanceof TerminalNode) {
|
|
123170
123170
|
const token = child.symbol;
|
|
123171
|
-
if (this.
|
|
123171
|
+
if (this.isNameTerminal(child)) {
|
|
123172
123172
|
return this.unquoteName(token.text ?? "");
|
|
123173
123173
|
}
|
|
123174
123174
|
}
|
|
@@ -123220,14 +123220,15 @@ var SymbolTable = class {
|
|
|
123220
123220
|
/**
|
|
123221
123221
|
* The first node of rule `ruleIndex` in `ctx`'s own declaration: never
|
|
123222
123222
|
* inside a nested element, its body, its value, a flow's payload or ends,
|
|
123223
|
-
*
|
|
123223
|
+
* a connector end's own multiplicity (`connect [2] a to b`), or a prefix
|
|
123224
|
+
* such as `#metadata`.
|
|
123224
123225
|
*/
|
|
123225
123226
|
findOwnHeaderRule(ctx, ruleIndex) {
|
|
123226
123227
|
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
123227
123228
|
const child = ctx.getChild(i);
|
|
123228
123229
|
if (!(child instanceof ParserRuleContext)) continue;
|
|
123229
123230
|
if (child.ruleIndex === ruleIndex) return child;
|
|
123230
|
-
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || this.isPrefixOrExtensionContext(child)) continue;
|
|
123231
|
+
if (RULE_INDEX_TO_KIND.has(child.ruleIndex) || BODY_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_valuePart || FLOW_PART_RULE_INDICES.has(child.ruleIndex) || child.ruleIndex === SysMLv2Parser.RULE_ownedCrossMultiplicityMember || this.isPrefixOrExtensionContext(child)) continue;
|
|
123231
123232
|
const found = this.findOwnHeaderRule(child, ruleIndex);
|
|
123232
123233
|
if (found) return found;
|
|
123233
123234
|
}
|
|
@@ -123391,7 +123392,7 @@ var SymbolTable = class {
|
|
|
123391
123392
|
extractNameRange(ctx) {
|
|
123392
123393
|
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
123393
123394
|
const child = ctx.getChild(i);
|
|
123394
|
-
if (child instanceof TerminalNode && this.
|
|
123395
|
+
if (child instanceof TerminalNode && this.isNameTerminal(child)) {
|
|
123395
123396
|
return tokenToRange(child.symbol);
|
|
123396
123397
|
}
|
|
123397
123398
|
if (child instanceof ParserRuleContext) {
|
|
@@ -123576,12 +123577,12 @@ var SymbolTable = class {
|
|
|
123576
123577
|
return lines.join("\n").trim();
|
|
123577
123578
|
}
|
|
123578
123579
|
/**
|
|
123579
|
-
* Extract multiplicity from a context
|
|
123580
|
-
*
|
|
123580
|
+
* Extract multiplicity from a context's own declaration, never from a
|
|
123581
|
+
* nested element or its body.
|
|
123581
123582
|
* Returns { multiplicity: "1..5", multiplicityRange: { lower: 1, upper: 5 } }
|
|
123582
123583
|
*/
|
|
123583
123584
|
extractMultiplicity(ctx) {
|
|
123584
|
-
const multCtx = this.
|
|
123585
|
+
const multCtx = this.findOwnHeaderRule(ctx, SysMLv2Parser.RULE_multiplicityBounds);
|
|
123585
123586
|
if (!multCtx) {
|
|
123586
123587
|
return {};
|
|
123587
123588
|
}
|
|
@@ -123635,24 +123636,6 @@ var SymbolTable = class {
|
|
|
123635
123636
|
multiplicityRange: { lower, upper }
|
|
123636
123637
|
};
|
|
123637
123638
|
}
|
|
123638
|
-
/**
|
|
123639
|
-
* Recursively search for a MultiplicityBoundsContext in the subtree.
|
|
123640
|
-
*/
|
|
123641
|
-
findMultiplicityBounds(ctx) {
|
|
123642
|
-
if (ctx.ruleIndex === SysMLv2Parser.RULE_multiplicityBounds) {
|
|
123643
|
-
return ctx;
|
|
123644
|
-
}
|
|
123645
|
-
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
123646
|
-
const child = ctx.getChild(i);
|
|
123647
|
-
if (child instanceof ParserRuleContext) {
|
|
123648
|
-
const result = this.findMultiplicityBounds(child);
|
|
123649
|
-
if (result) {
|
|
123650
|
-
return result;
|
|
123651
|
-
}
|
|
123652
|
-
}
|
|
123653
|
-
}
|
|
123654
|
-
return void 0;
|
|
123655
|
-
}
|
|
123656
123639
|
/**
|
|
123657
123640
|
* Whether a context is a prefix metadata or definition/usage prefix rule.
|
|
123658
123641
|
* These contain annotation identifiers (e.g. from `#product`) that should
|
|
@@ -123694,6 +123677,14 @@ var SymbolTable = class {
|
|
|
123694
123677
|
if (this.isQuotedName(text)) return true;
|
|
123695
123678
|
return /^[a-zA-Z_]/.test(text) && !this.isKeyword(text);
|
|
123696
123679
|
}
|
|
123680
|
+
/**
|
|
123681
|
+
* Whether a terminal is (part of) a name: an identifier, a quoted name, or
|
|
123682
|
+
* a KerML keyword such as `step` or `function` that the grammar parsed as a
|
|
123683
|
+
* name (`name : IDENTIFIER | STRING | unreservedKeyword`).
|
|
123684
|
+
*/
|
|
123685
|
+
isNameTerminal(node) {
|
|
123686
|
+
return this.isIdentifierToken(node.symbol) || node.parent?.ruleIndex === SysMLv2Parser.RULE_unreservedKeyword;
|
|
123687
|
+
}
|
|
123697
123688
|
/**
|
|
123698
123689
|
* Check if text is a SysML quoted name (single-quoted string).
|
|
123699
123690
|
*/
|
|
@@ -124063,7 +124054,7 @@ var SymbolTable = class {
|
|
|
124063
124054
|
const child = ctx.getChild(i);
|
|
124064
124055
|
if (child instanceof TerminalNode) {
|
|
124065
124056
|
const text = child.symbol.text;
|
|
124066
|
-
if (text && this.
|
|
124057
|
+
if (text && this.isNameTerminal(child)) {
|
|
124067
124058
|
parts.push(this.unquoteName(text));
|
|
124068
124059
|
}
|
|
124069
124060
|
} else if (child instanceof ParserRuleContext) {
|
|
@@ -126020,9 +126011,8 @@ var SysMLModelProvider = class {
|
|
|
126020
126011
|
if (direction) {
|
|
126021
126012
|
attributes["direction"] = direction;
|
|
126022
126013
|
}
|
|
126023
|
-
|
|
126024
|
-
|
|
126025
|
-
attributes["multiplicity"] = multiplicity;
|
|
126014
|
+
if (symbol.multiplicity) {
|
|
126015
|
+
attributes["multiplicity"] = symbol.multiplicity;
|
|
126026
126016
|
}
|
|
126027
126017
|
const modifier = this.extractModifier(symbol, lines);
|
|
126028
126018
|
if (modifier) {
|
|
@@ -126640,7 +126630,7 @@ var SysMLModelProvider = class {
|
|
|
126640
126630
|
name: c.name,
|
|
126641
126631
|
kind: toMetaclassName(c.kind),
|
|
126642
126632
|
type: c.typeNames.join(", ") || void 0,
|
|
126643
|
-
multiplicity: c.multiplicity
|
|
126633
|
+
multiplicity: c.multiplicity,
|
|
126644
126634
|
direction,
|
|
126645
126635
|
visibility: c.visibility,
|
|
126646
126636
|
isDerived: modifier?.split(", ").includes("derived") ?? false,
|
|
@@ -126764,15 +126754,6 @@ var SysMLModelProvider = class {
|
|
|
126764
126754
|
if (containsWord(elementText, "out")) return "out";
|
|
126765
126755
|
return void 0;
|
|
126766
126756
|
}
|
|
126767
|
-
/** Extract multiplicity (e.g., [4], [0..*]) from source text. */
|
|
126768
|
-
extractMultiplicity(symbol, lines) {
|
|
126769
|
-
const elementText = this.getElementText(symbol, lines);
|
|
126770
|
-
const open = elementText.indexOf("[");
|
|
126771
|
-
if (open < 0) return void 0;
|
|
126772
|
-
const close = elementText.indexOf("]", open + 1);
|
|
126773
|
-
if (close < 0) return void 0;
|
|
126774
|
-
return elementText.substring(open + 1, close);
|
|
126775
|
-
}
|
|
126776
126757
|
/** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
|
|
126777
126758
|
extractModifier(symbol, lines) {
|
|
126778
126759
|
const elementText = this.getElementText(symbol, lines);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "sysml-v2-lsp",
|
|
3
3
|
"displayName": "SysML v2 Language Server",
|
|
4
4
|
"description": "Language Server Protocol implementation for SysML v2, powered by ANTLR4",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.34.0",
|
|
6
6
|
"publisher": "JamieD",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|