sysml-v2-lsp 0.40.0 → 0.41.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.
@@ -121790,7 +121790,10 @@ function splitQualifiedName(text) {
121790
121790
  return parts;
121791
121791
  }
121792
121792
  function joinQualifiedName(parts) {
121793
- return parts.map((part) => /::|['\\\r\n\t\b\f]|^\s|\s$/.test(part) ? quoteName(part) : part).join("::");
121793
+ return parts.map((part) => /::|^:|:$|['\\\r\n\t\b\f]|^\s|\s$|^\$?$/.test(part) ? quoteName(part) : part).join("::");
121794
+ }
121795
+ function joinReference(chain, conjugated = false) {
121796
+ return (conjugated ? "~" : "") + chain.map(({ global, names }) => (global ? "$::" : "") + names.map((name) => /\.|^~/.test(name) ? quoteName(name) : joinQualifiedName([name])).join("::")).join(".");
121794
121797
  }
121795
121798
  function readNameAt(text, start, allowIncomplete = false) {
121796
121799
  if (text[start] === "'") {
@@ -123160,12 +123163,44 @@ var RULE_INDEX_TO_KIND = /* @__PURE__ */ new Map([
123160
123163
  var BODY_RULE_INDICES = new Set(
123161
123164
  SysMLv2Parser.ruleNames.flatMap((ruleName, index2) => ruleName.endsWith("Body") ? [index2] : [])
123162
123165
  );
123166
+ var VALUE_DECLARATION_RULE_INDICES = /* @__PURE__ */ new Set([
123167
+ SysMLv2Parser.RULE_usage,
123168
+ SysMLv2Parser.RULE_usageCompletion,
123169
+ SysMLv2Parser.RULE_actionUsageDeclaration,
123170
+ SysMLv2Parser.RULE_performActionUsageDeclaration,
123171
+ SysMLv2Parser.RULE_constraintUsageDeclaration,
123172
+ SysMLv2Parser.RULE_interfaceUsageDeclaration,
123173
+ SysMLv2Parser.RULE_flowDeclaration,
123174
+ SysMLv2Parser.RULE_messageDeclaration
123175
+ ]);
123163
123176
  var FLOW_PART_RULE_INDICES = /* @__PURE__ */ new Set([
123164
123177
  SysMLv2Parser.RULE_payloadFeatureMember,
123165
123178
  SysMLv2Parser.RULE_flowPayloadFeatureMember,
123166
123179
  SysMLv2Parser.RULE_flowEndMember,
123167
123180
  SysMLv2Parser.RULE_messageEventMember
123168
123181
  ]);
123182
+ var SPECIALIZATION_DECLARATION_RULE_INDICES = /* @__PURE__ */ new Set([
123183
+ SysMLv2Parser.RULE_definition,
123184
+ SysMLv2Parser.RULE_definitionDeclaration,
123185
+ SysMLv2Parser.RULE_usage,
123186
+ SysMLv2Parser.RULE_usageDeclaration,
123187
+ SysMLv2Parser.RULE_featureDeclaration,
123188
+ SysMLv2Parser.RULE_featureSpecializationPart,
123189
+ SysMLv2Parser.RULE_actionUsageDeclaration,
123190
+ SysMLv2Parser.RULE_performActionUsageDeclaration,
123191
+ SysMLv2Parser.RULE_constraintUsageDeclaration,
123192
+ SysMLv2Parser.RULE_interfaceUsageDeclaration,
123193
+ SysMLv2Parser.RULE_allocationUsageDeclaration,
123194
+ SysMLv2Parser.RULE_flowDeclaration,
123195
+ SysMLv2Parser.RULE_messageDeclaration
123196
+ ]);
123197
+ var REFERENCE_SHORTHAND_RULE_INDICES = /* @__PURE__ */ new Set([
123198
+ SysMLv2Parser.RULE_variantReference,
123199
+ SysMLv2Parser.RULE_performActionUsageDeclaration,
123200
+ SysMLv2Parser.RULE_exhibitStateUsage,
123201
+ SysMLv2Parser.RULE_framedConcernUsage,
123202
+ SysMLv2Parser.RULE_includeUseCaseUsage
123203
+ ]);
123169
123204
  var FLOW_DECLARATION_RULE_INDICES = [
123170
123205
  SysMLv2Parser.RULE_flowDeclaration,
123171
123206
  SysMLv2Parser.RULE_messageDeclaration
@@ -123271,6 +123306,50 @@ var PREFIX_EXTENSION_RULE_INDICES = /* @__PURE__ */ new Set([
123271
123306
  SysMLv2Parser.RULE_endFeaturePrefix
123272
123307
  // 86
123273
123308
  ]);
123309
+ var PREFIX_KEYWORD_TOKENS = /* @__PURE__ */ new Set([
123310
+ SysMLv2Lexer.IN,
123311
+ SysMLv2Lexer.OUT,
123312
+ SysMLv2Lexer.INOUT,
123313
+ SysMLv2Lexer.ABSTRACT,
123314
+ SysMLv2Lexer.VARIATION,
123315
+ SysMLv2Lexer.INDIVIDUAL,
123316
+ SysMLv2Lexer.DERIVED,
123317
+ SysMLv2Lexer.CONSTANT,
123318
+ SysMLv2Lexer.REF,
123319
+ SysMLv2Lexer.END,
123320
+ SysMLv2Lexer.ORDERED,
123321
+ SysMLv2Lexer.NONUNIQUE
123322
+ ]);
123323
+ var PREFIX_PATH_RULE_INDICES = /* @__PURE__ */ new Set([
123324
+ SysMLv2Parser.RULE_usagePrefix,
123325
+ SysMLv2Parser.RULE_unextendedUsagePrefix,
123326
+ SysMLv2Parser.RULE_basicUsagePrefix,
123327
+ SysMLv2Parser.RULE_endUsagePrefix,
123328
+ SysMLv2Parser.RULE_refPrefix,
123329
+ SysMLv2Parser.RULE_featureDirection,
123330
+ SysMLv2Parser.RULE_occurrenceUsagePrefix,
123331
+ SysMLv2Parser.RULE_controlNodePrefix,
123332
+ SysMLv2Parser.RULE_definitionPrefix,
123333
+ SysMLv2Parser.RULE_basicDefinitionPrefix,
123334
+ SysMLv2Parser.RULE_occurrenceDefinitionPrefix,
123335
+ SysMLv2Parser.RULE_usage,
123336
+ SysMLv2Parser.RULE_usageDeclaration,
123337
+ SysMLv2Parser.RULE_featureDeclaration,
123338
+ SysMLv2Parser.RULE_featureSpecializationPart,
123339
+ SysMLv2Parser.RULE_multiplicityPart,
123340
+ SysMLv2Parser.RULE_actionUsageDeclaration,
123341
+ SysMLv2Parser.RULE_performActionUsageDeclaration,
123342
+ SysMLv2Parser.RULE_constraintUsageDeclaration,
123343
+ SysMLv2Parser.RULE_interfaceUsageDeclaration,
123344
+ SysMLv2Parser.RULE_allocationUsageDeclaration,
123345
+ SysMLv2Parser.RULE_flowDeclaration,
123346
+ SysMLv2Parser.RULE_messageDeclaration
123347
+ ]);
123348
+ var OCCURRENCE_USAGE_ELEMENT_RULE_INDICES = /* @__PURE__ */ new Set([
123349
+ SysMLv2Parser.RULE_occurrenceUsageElement,
123350
+ SysMLv2Parser.RULE_structureUsageElement,
123351
+ SysMLv2Parser.RULE_behaviorUsageElement
123352
+ ]);
123274
123353
  var TYPE_SPECIALIZATION_RULE_INDICES = /* @__PURE__ */ new Set([
123275
123354
  SysMLv2Parser.RULE_specialization,
123276
123355
  // 66
@@ -124105,6 +124184,9 @@ var SymbolTable = class {
124105
124184
  const typeName = typeNames[0];
124106
124185
  const documentation = this.extractDocumentation(ctx);
124107
124186
  const visibility = this.extractVisibility(ctx);
124187
+ const featureValue = this.extractFeatureValue(ctx);
124188
+ const prefixKeywords = this.extractPrefixKeywords(ctx);
124189
+ const ownedSpecializations = this.extractOwnedSpecializations(ctx);
124108
124190
  const { multiplicity, multiplicityRange } = isUsage(kind) ? this.extractMultiplicity(ctx) : {};
124109
124191
  const metadataAnnotations = this.extractPrefixMetadataAnnotations(ctx);
124110
124192
  const isView = kind === "view" /* ViewUsage */ || kind === "view def" /* ViewDef */;
@@ -124137,6 +124219,9 @@ var SymbolTable = class {
124137
124219
  namingReference,
124138
124220
  documentation,
124139
124221
  visibility,
124222
+ featureValue,
124223
+ prefixKeywords: prefixKeywords.length > 0 ? prefixKeywords : void 0,
124224
+ ownedSpecializations: ownedSpecializations.length > 0 ? ownedSpecializations : void 0,
124140
124225
  source: transition?.source,
124141
124226
  target: transition?.target,
124142
124227
  flowDetails,
@@ -124520,7 +124605,23 @@ var SymbolTable = class {
124520
124605
  * between two of them (`connect a.p to b.p`, `connection : Conn`).
124521
124606
  */
124522
124607
  declarationText(ctx) {
124523
- const tokens = this.declarationTokens(ctx);
124608
+ return this.tokensText(this.declarationTokens(ctx));
124609
+ }
124610
+ /** Every token of `ctx`, in source order: a whole expression, bodies and `;` included. */
124611
+ subtreeTokens(ctx, tokens = []) {
124612
+ for (let i = 0; i < ctx.getChildCount(); i++) {
124613
+ const child = ctx.getChild(i);
124614
+ if (child instanceof TerminalNode) {
124615
+ if (child.symbol.tokenIndex >= 0) tokens.push(child.symbol);
124616
+ } else if (child instanceof ParserRuleContext) this.subtreeTokens(child, tokens);
124617
+ }
124618
+ return tokens;
124619
+ }
124620
+ /**
124621
+ * Tokens joined as written, with one space wherever the source has
124622
+ * whitespace or a comment between two of them.
124623
+ */
124624
+ tokensText(tokens) {
124524
124625
  let text = "";
124525
124626
  tokens.forEach((token, i) => {
124526
124627
  if (i > 0 && token.start > tokens[i - 1].stop + 1) text += " ";
@@ -124626,6 +124727,139 @@ var SymbolTable = class {
124626
124727
  }
124627
124728
  return void 0;
124628
124729
  }
124730
+ /**
124731
+ * `ctx`'s own feature value (SysML 7.13.4, 8.2.2.6.2 `ValuePart`, `FeatureValue`):
124732
+ * its expression as written, and whether it is a default (`default`) and an
124733
+ * initial (`:=`) value. Never a nested element's value; a cross subsetting
124734
+ * (`=> x`) is not a value. The expression is the whole `OwnedExpression`,
124735
+ * expression bodies included, with whitespace and comments as one space.
124736
+ */
124737
+ extractFeatureValue(ctx) {
124738
+ const featureValueCtx = this.findOwnValuePart(ctx)?.getRuleContext(0, FeatureValueContext);
124739
+ const expression = featureValueCtx?.ownedExpression();
124740
+ const text = expression && this.tokensText(this.subtreeTokens(expression));
124741
+ if (!featureValueCtx || !text) return void 0;
124742
+ return {
124743
+ expression: text,
124744
+ isDefault: featureValueCtx.DEFAULT() !== null,
124745
+ isInitial: featureValueCtx.COLON_EQ() !== null
124746
+ };
124747
+ }
124748
+ /**
124749
+ * `ctx`'s own `ValuePart`: a direct child of its element rule, or of one of
124750
+ * its declaration rules (`VALUE_DECLARATION_RULE_INDICES`). Never one of an
124751
+ * inline-owned element, e.g. a transition's accept payload or effect action.
124752
+ */
124753
+ findOwnValuePart(ctx) {
124754
+ for (let i = 0; i < ctx.getChildCount(); i++) {
124755
+ const child = ctx.getChild(i);
124756
+ if (!(child instanceof ParserRuleContext)) continue;
124757
+ if (child.ruleIndex === SysMLv2Parser.RULE_valuePart) return child;
124758
+ if (!VALUE_DECLARATION_RULE_INDICES.has(child.ruleIndex)) continue;
124759
+ const valuePart = this.findOwnValuePart(child);
124760
+ if (valuePart) return valuePart;
124761
+ }
124762
+ return void 0;
124763
+ }
124764
+ /**
124765
+ * The specializations of `ctx`'s own declaration, one per target in written
124766
+ * order, read only from its `FeatureSpecialization`s (SysML v2 8.2.2.6.2),
124767
+ * `SubclassificationPart` (8.2.2.6.1) and a shorthand's reference
124768
+ * (`perform a`, `REFERENCE_SHORTHAND_RULE_INDICES`), reached through
124769
+ * `SPECIALIZATION_DECLARATION_RULE_INDICES`.
124770
+ */
124771
+ extractOwnedSpecializations(ctx) {
124772
+ const specializations = [];
124773
+ const add = (kind, targets, notation) => {
124774
+ for (const targetCtx of targets) {
124775
+ const target = targetCtx && this.specializationTarget(targetCtx);
124776
+ if (target) specializations.push(notation ? { kind, target, notation: notation.getText() } : { kind, target });
124777
+ }
124778
+ };
124779
+ const visit = (node) => {
124780
+ for (let i = 0; i < node.getChildCount(); i++) {
124781
+ const child = node.getChild(i);
124782
+ if (child instanceof FeatureSpecializationContext) {
124783
+ const typings = child.typings();
124784
+ const subsettings = child.subsettings();
124785
+ const references = child.references();
124786
+ const crosses = child.crosses();
124787
+ const redefinitions = child.redefinitions();
124788
+ if (typings) {
124789
+ const typedBy = typings.typedBy();
124790
+ add("typing", [typedBy?.featureTyping(), ...typings.featureTyping()].map((typing) => typing && (typing.ownedFeatureTyping() ?? typing.conjugatedPortTyping())));
124791
+ } else if (subsettings) {
124792
+ const subsets = subsettings.subsets();
124793
+ add("subsetting", [subsets?.ownedSubsetting(), ...subsettings.ownedSubsetting()], subsets && (subsets.COLON_GT() ?? subsets.SUBSETS()));
124794
+ } else if (references) {
124795
+ add("referenceSubsetting", [references.ownedReferenceSubsetting()], references.COLON_COLON_GT() ?? references.REFERENCES());
124796
+ } else if (crosses) {
124797
+ add("crossSubsetting", [crosses.ownedCrossSubsetting()], crosses.FAT_ARROW() ?? crosses.CROSSES());
124798
+ } else if (redefinitions) {
124799
+ const redefines = redefinitions.redefines();
124800
+ add("redefinition", [redefines?.ownedRedefinition(), ...redefinitions.ownedRedefinition()], redefines && (redefines.COLON_GT_GT() ?? redefines.REDEFINES()));
124801
+ }
124802
+ } else if (child instanceof OwnedReferenceSubsettingContext && REFERENCE_SHORTHAND_RULE_INDICES.has(node.ruleIndex)) {
124803
+ add("referenceSubsetting", [child]);
124804
+ } else if (child instanceof SubclassificationPartContext) {
124805
+ add("specializes", child.ownedSubclassification(), child.COLON_GT() ?? child.SPECIALIZES());
124806
+ } else if (child instanceof ParserRuleContext && SPECIALIZATION_DECLARATION_RULE_INDICES.has(child.ruleIndex)) {
124807
+ visit(child);
124808
+ }
124809
+ }
124810
+ };
124811
+ visit(ctx);
124812
+ return specializations;
124813
+ }
124814
+ /**
124815
+ * The general type or feature a specialization's target rule names: its
124816
+ * qualified name, or its feature chain (`v.engine`), with a global `$::`
124817
+ * (KerML 7.2.2) and a conjugated port typing's `~` (`~P`, SysML 8.3.12.3).
124818
+ * Its names are quoted as everywhere in the server (`joinReference`).
124819
+ * Undefined for a target missing after a syntax error.
124820
+ */
124821
+ specializationTarget(ctx) {
124822
+ const chain = ctx.getRuleContexts(QualifiedNameContext).map((qualifiedName) => ({
124823
+ global: qualifiedName.DOLLAR() !== null,
124824
+ names: qualifiedName.getRuleContexts(NameContext).map((name) => name.getText())
124825
+ }));
124826
+ if (chain.length === 0 || chain.some(({ names }) => names.length === 0 || names.some((name) => !name))) return void 0;
124827
+ return joinReference(
124828
+ chain.map(({ global, names }) => ({ global, names: names.map(unquoteName) })),
124829
+ ctx instanceof ConjugatedPortTypingContext
124830
+ );
124831
+ }
124832
+ /**
124833
+ * The keywords of `ctx`'s own prefix and multiplicity part, in written
124834
+ * order (`in`, `abstract`, `constant`, `ref`, `end`, `ordered`, ...),
124835
+ * read only from the rules in `PREFIX_PATH_RULE_INDICES`.
124836
+ */
124837
+ extractPrefixKeywords(ctx) {
124838
+ const keywords = [];
124839
+ const visit = (node) => {
124840
+ for (let i = 0; i < node.getChildCount(); i++) {
124841
+ const child = node.getChild(i);
124842
+ if (child instanceof TerminalNode) {
124843
+ if (PREFIX_KEYWORD_TOKENS.has(child.symbol.type)) keywords.push(child.getText());
124844
+ continue;
124845
+ }
124846
+ if (child instanceof ParserRuleContext && PREFIX_PATH_RULE_INDICES.has(child.ruleIndex)) visit(child);
124847
+ }
124848
+ };
124849
+ visit(ctx);
124850
+ return this.isEndOccurrence(ctx) ? ["end", ...keywords] : keywords;
124851
+ }
124852
+ /**
124853
+ * Whether `ctx` is the occurrence usage of an `endOccurrenceUsageElement`
124854
+ * (`end part a`), whose `end` precedes the usage's own rule.
124855
+ */
124856
+ isEndOccurrence(ctx) {
124857
+ let current = ctx.parent;
124858
+ while (current instanceof ParserRuleContext && OCCURRENCE_USAGE_ELEMENT_RULE_INDICES.has(current.ruleIndex)) {
124859
+ current = current.parent;
124860
+ }
124861
+ return current !== ctx.parent && current instanceof ParserRuleContext && current.ruleIndex === SysMLv2Parser.RULE_endOccurrenceUsageElement;
124862
+ }
124629
124863
  /**
124630
124864
  * Extract the range of just the name token.
124631
124865
  */
@@ -126604,22 +126838,6 @@ function readWordAfterKeyword(text, afterPos, allowDots = false) {
126604
126838
  const start = skipWS(text, afterPos);
126605
126839
  return readIdent(text, start, allowDots);
126606
126840
  }
126607
- function readCommaSeparatedIdents(text, pos) {
126608
- const names = [];
126609
- let p = skipWS(text, pos);
126610
- while (p < text.length) {
126611
- const [name, end] = readIdent(text, p);
126612
- if (!name) break;
126613
- names.push(name);
126614
- p = skipWS(text, end);
126615
- if (p < text.length && text[p] === ",") {
126616
- p = skipWS(text, p + 1);
126617
- } else {
126618
- break;
126619
- }
126620
- }
126621
- return names;
126622
- }
126623
126841
  function symbolsById(symbols) {
126624
126842
  return new Map(symbols.map((s) => [s.symbolId, s]));
126625
126843
  }
@@ -126665,7 +126883,7 @@ var SysMLModelProvider = class {
126665
126883
  result.activityDiagrams = this.extractActivityDiagrams(symbolTable, uri, lines);
126666
126884
  }
126667
126885
  if (scopeSet.has("resolvedTypes")) {
126668
- result.resolvedTypes = this.extractResolvedTypes(symbolTable, uri, lines);
126886
+ result.resolvedTypes = this.extractResolvedTypes(symbolTable, uri);
126669
126887
  }
126670
126888
  if (scopeSet.has("diagnostics")) {
126671
126889
  result.diagnostics = this.extractSemanticDiagnostics(symbolTable, uri);
@@ -126764,44 +126982,34 @@ var SysMLModelProvider = class {
126764
126982
  if (symbol.viewRendering) {
126765
126983
  attributes["viewRendering"] = symbol.viewRendering;
126766
126984
  }
126767
- const direction = this.extractDirection(symbol, lines);
126768
- if (direction) {
126769
- attributes["direction"] = direction;
126985
+ const prefix = prefixAttributesOf(symbol);
126986
+ if (prefix.direction) {
126987
+ attributes["direction"] = prefix.direction;
126770
126988
  }
126771
126989
  if (symbol.multiplicity) {
126772
126990
  attributes["multiplicity"] = symbol.multiplicity;
126773
126991
  }
126774
- const modifier = this.extractModifier(symbol, lines);
126775
- if (modifier) {
126776
- attributes["modifier"] = modifier;
126992
+ if (prefix.modifier) {
126993
+ attributes["modifier"] = prefix.modifier;
126994
+ }
126995
+ if (prefix.ordered) {
126996
+ attributes["ordered"] = true;
126997
+ }
126998
+ if (prefix.nonunique) {
126999
+ attributes["nonunique"] = true;
126777
127000
  }
126778
127001
  if (symbol.visibility) {
126779
127002
  attributes["visibility"] = symbol.visibility;
126780
127003
  }
126781
- const value = this.extractValue(symbol, lines);
126782
- if (value) {
126783
- attributes["value"] = value;
127004
+ if (symbol.featureValue) {
127005
+ attributes["value"] = symbol.featureValue.expression;
127006
+ if (symbol.featureValue.isDefault) attributes["isDefault"] = true;
127007
+ if (symbol.featureValue.isInitial) attributes["isInitial"] = true;
126784
127008
  }
126785
127009
  const relationships = [];
126786
- for (const tn of symbol.typeNames) {
126787
- relationships.push({
126788
- type: "typing",
126789
- source: symbol.name,
126790
- sourceId: symbol.symbolId,
126791
- target: tn
126792
- });
126793
- }
127010
+ relationships.push(...this.specializationRelationships(symbol));
126794
127011
  const flowRelationship = this.flowRelationship(symbol);
126795
127012
  if (flowRelationship) relationships.push(flowRelationship);
126796
- const specializations = this.extractSpecializations(symbol, lines);
126797
- for (const spec of specializations) {
126798
- relationships.push({
126799
- type: "specializes",
126800
- source: symbol.name,
126801
- sourceId: symbol.symbolId,
126802
- target: spec
126803
- });
126804
- }
126805
127013
  return {
126806
127014
  type: symbol.kind,
126807
127015
  name: symbol.name,
@@ -126813,6 +127021,20 @@ var SysMLModelProvider = class {
126813
127021
  relationships
126814
127022
  };
126815
127023
  }
127024
+ /**
127025
+ * The typings, subclassifications, subsettings and redefinitions of the
127026
+ * element's own declaration, one per target in written order (SysML v2
127027
+ * 8.2.2.6.1, 8.2.2.6.2).
127028
+ */
127029
+ specializationRelationships(symbol) {
127030
+ return (symbol.ownedSpecializations ?? []).map(({ kind, target, notation }) => ({
127031
+ type: kind,
127032
+ source: symbol.name,
127033
+ sourceId: symbol.symbolId,
127034
+ target,
127035
+ ...notation ? { notation } : {}
127036
+ }));
127037
+ }
126816
127038
  flowRelationship(symbol) {
126817
127039
  const details = symbol.flowDetails;
126818
127040
  if (!isFlowUsage(symbol.kind) || !details?.source || !details.target) return void 0;
@@ -126846,25 +127068,7 @@ var SysMLModelProvider = class {
126846
127068
  if (symbol.kind === "package" /* Package */ || symbol.kind === "import" /* Import */ || symbol.kind === "comment" /* Comment */ || symbol.kind === "doc" /* Doc */) {
126847
127069
  continue;
126848
127070
  }
126849
- if (symbol.typeNames.length > 0 && isUsage(symbol.kind)) {
126850
- for (const tn of symbol.typeNames) {
126851
- relationships.push({
126852
- type: "typing",
126853
- source: symbol.name,
126854
- sourceId: symbol.symbolId,
126855
- target: tn
126856
- });
126857
- }
126858
- }
126859
- const specializations = this.extractSpecializations(symbol, lines);
126860
- for (const spec of specializations) {
126861
- relationships.push({
126862
- type: "specializes",
126863
- source: symbol.name,
126864
- sourceId: symbol.symbolId,
126865
- target: spec
126866
- });
126867
- }
127071
+ relationships.push(...this.specializationRelationships(symbol));
126868
127072
  if (symbol.kind === "connection" /* ConnectionUsage */) {
126869
127073
  const connectionTargets = this.extractConnectionEndpoints(symbol, lines);
126870
127074
  if (connectionTargets.length === 2) {
@@ -127357,41 +127561,30 @@ var SysMLModelProvider = class {
127357
127561
  * Because the LSP server doesn't yet have a full type resolver or library
127358
127562
  * index, we provide what's available from the parse tree.
127359
127563
  */
127360
- extractResolvedTypes(symbolTable, uri, lines) {
127564
+ extractResolvedTypes(symbolTable, uri) {
127361
127565
  const symbols = symbolTable.getSymbolsForUri(uri);
127362
127566
  const result = {};
127363
127567
  for (const symbol of symbols) {
127364
127568
  const qualifiedName = symbol.qualifiedName;
127365
127569
  if (qualifiedName === void 0) continue;
127366
- if (!isDefinition(symbol.kind) && symbol.typeNames.length === 0) {
127570
+ if (!isDefinition(symbol.kind) && !symbol.ownedSpecializations) {
127367
127571
  continue;
127368
127572
  }
127369
- const specializes = [];
127370
- const specList = this.extractSpecializations(symbol, lines);
127371
- for (const s of specList) {
127372
- if (!specializes.includes(s)) {
127373
- specializes.push(s);
127374
- }
127375
- }
127376
- for (const tn of symbol.typeNames) {
127377
- if (!specializes.includes(tn)) {
127378
- specializes.push(tn);
127379
- }
127380
- }
127573
+ const specializes = [...new Set((symbol.ownedSpecializations ?? []).map(({ target }) => target))];
127381
127574
  const specializationChain = [...specializes];
127382
127575
  const children = this.getChildSymbols(symbol, symbolTable);
127383
127576
  const features = children.filter((c) => isUsage(c.kind)).map((c) => {
127384
- const modifier = this.extractModifier(c, lines);
127385
- const direction = this.extractDirection(c, lines);
127577
+ const prefix = prefixAttributesOf(c);
127386
127578
  return {
127387
127579
  name: c.name,
127388
127580
  kind: toMetaclassName(c.kind),
127389
127581
  type: c.typeNames.join(", ") || void 0,
127390
127582
  multiplicity: c.multiplicity,
127391
- direction,
127583
+ direction: prefix.direction,
127392
127584
  visibility: c.visibility,
127393
- isDerived: modifier?.split(", ").includes("derived") ?? false,
127394
- isReadonly: modifier?.split(", ").includes("readonly") ?? false
127585
+ isDerived: prefix.keywords.includes("derived"),
127586
+ isConstant: prefix.isConstant,
127587
+ isReadonly: prefix.isConstant
127395
127588
  };
127396
127589
  });
127397
127590
  result[qualifiedName] = {
@@ -127508,67 +127701,6 @@ var SysMLModelProvider = class {
127508
127701
  const endLine = Math.min(symbol.range.end.line, lines.length - 1);
127509
127702
  return lines.slice(startLine, endLine + 1).join("\n");
127510
127703
  }
127511
- /** Extract port direction (in | out | inout) from source text. */
127512
- extractDirection(symbol, lines) {
127513
- if (symbol.kind !== "port" /* PortUsage */ && symbol.kind !== "port def" /* PortDef */) {
127514
- return void 0;
127515
- }
127516
- const elementText = this.getElementText(symbol, lines);
127517
- if (containsWord(elementText, "inout")) return "inout";
127518
- if (containsWord(elementText, "in")) return "in";
127519
- if (containsWord(elementText, "out")) return "out";
127520
- return void 0;
127521
- }
127522
- /** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
127523
- extractModifier(symbol, lines) {
127524
- const elementText = this.getElementText(symbol, lines);
127525
- const modifiers = [];
127526
- if (containsWord(elementText, "abstract")) modifiers.push("abstract");
127527
- if (containsWord(elementText, "readonly")) modifiers.push("readonly");
127528
- if (containsWord(elementText, "derived")) modifiers.push("derived");
127529
- if (containsWord(elementText, "variation")) modifiers.push("variation");
127530
- if (containsWord(elementText, "individual")) modifiers.push("individual");
127531
- return modifiers.length > 0 ? modifiers.join(", ") : void 0;
127532
- }
127533
- /** Extract default/assigned value from source text. */
127534
- extractValue(symbol, lines) {
127535
- if (symbol.kind !== "attribute" /* AttributeUsage */) {
127536
- return void 0;
127537
- }
127538
- const elementText = this.getElementText(symbol, lines);
127539
- const eqIdx = elementText.indexOf("=");
127540
- if (eqIdx < 0) return void 0;
127541
- let start = eqIdx + 1;
127542
- if (start < elementText.length && elementText[start] === "=") return void 0;
127543
- start = skipWS(elementText, start);
127544
- let end = start;
127545
- while (end < elementText.length) {
127546
- const ch = elementText[end];
127547
- if (ch === ";" || ch === "{" || ch === "}" || ch === "\n") break;
127548
- end++;
127549
- }
127550
- const val = elementText.substring(start, end).trim();
127551
- if (val && !val.includes("def") && val.length < 100) {
127552
- return val;
127553
- }
127554
- return void 0;
127555
- }
127556
- /** Extract all specialization targets from `:>` or `specializes` syntax. */
127557
- extractSpecializations(symbol, lines) {
127558
- const elementText = this.getElementText(symbol, lines);
127559
- const colonGtIdx = elementText.indexOf(":>");
127560
- if (colonGtIdx >= 0) {
127561
- if (colonGtIdx + 2 < elementText.length && elementText[colonGtIdx + 2] === ">") {
127562
- } else {
127563
- return readCommaSeparatedIdents(elementText, colonGtIdx + 2);
127564
- }
127565
- }
127566
- const specPositions = findWordPositions(elementText, "specializes");
127567
- if (specPositions.length > 0) {
127568
- return readCommaSeparatedIdents(elementText, specPositions[0].afterPos);
127569
- }
127570
- return [];
127571
- }
127572
127704
  /** Extract connection endpoints from `connect` syntax. */
127573
127705
  extractConnectionEndpoints(symbol, lines) {
127574
127706
  const elementText = this.getElementText(symbol, lines);
@@ -127632,16 +127764,6 @@ var SysMLModelProvider = class {
127632
127764
  const fromElement = { source: elementName, sourceId: element.symbolId };
127633
127765
  elementText = stripComments(elementText);
127634
127766
  const rels = [];
127635
- const subsetsPositions = findWordPositions(elementText, "subsets");
127636
- if (subsetsPositions.length > 0) {
127637
- const [target] = readWordAfterKeyword(elementText, subsetsPositions[0].afterPos);
127638
- if (target) rels.push({ type: "subsetting", ...fromElement, target });
127639
- }
127640
- const redefPositions = findWordPositions(elementText, "redefines");
127641
- if (redefPositions.length > 0) {
127642
- const [target] = readWordAfterKeyword(elementText, redefPositions[0].afterPos);
127643
- if (target) rels.push({ type: "redefinition", ...fromElement, target });
127644
- }
127645
127767
  const satisfyPositions = findWordPositions(elementText, "satisfy");
127646
127768
  if (satisfyPositions.length > 0) {
127647
127769
  let pos = skipWS(elementText, satisfyPositions[0].afterPos);
@@ -127935,6 +128057,21 @@ ${this.followingBranchStatements(symbol, lines)}`;
127935
128057
  };
127936
128058
  }
127937
128059
  };
128060
+ var DIRECTIONS = /* @__PURE__ */ new Set(["in", "out", "inout"]);
128061
+ var MULTIPLICITY_KEYWORDS = /* @__PURE__ */ new Set(["ordered", "nonunique"]);
128062
+ function prefixAttributesOf(symbol) {
128063
+ const keywords = symbol.prefixKeywords ?? [];
128064
+ const direction = keywords.find((keyword) => DIRECTIONS.has(keyword));
128065
+ const modifiers = keywords.filter((keyword) => !DIRECTIONS.has(keyword) && !MULTIPLICITY_KEYWORDS.has(keyword));
128066
+ return {
128067
+ keywords,
128068
+ direction,
128069
+ modifier: modifiers.length > 0 ? modifiers.join(", ") : void 0,
128070
+ isConstant: keywords.includes("constant"),
128071
+ ordered: keywords.includes("ordered"),
128072
+ nonunique: keywords.includes("nonunique")
128073
+ };
128074
+ }
127938
128075
 
127939
128076
  // server/src/platform/connection.ts
127940
128077
  var import_node = __toESM(require_node3());
@@ -128608,7 +128745,7 @@ var SYSML_KEYWORDS2 = [
128608
128745
  { label: "satisfy", kind: import_node3.CompletionItemKind.Operator, detail: "Satisfaction", documentation: "Indicates requirement satisfaction", insertText: "satisfy ${1:requirement} by ${2:element};", insertTextFormat: import_node3.InsertTextFormat.Snippet },
128609
128746
  // Modifiers
128610
128747
  { label: "abstract", kind: import_node3.CompletionItemKind.Keyword, detail: "Abstract modifier", documentation: "Makes element abstract" },
128611
- { label: "readonly", kind: import_node3.CompletionItemKind.Keyword, detail: "Readonly modifier", documentation: "Makes attribute readonly" },
128748
+ { label: "constant", kind: import_node3.CompletionItemKind.Keyword, detail: "Constant modifier", documentation: "Makes feature constant" },
128612
128749
  { label: "derived", kind: import_node3.CompletionItemKind.Keyword, detail: "Derived modifier", documentation: "Indicates value is derived/calculated" },
128613
128750
  { label: "in", kind: import_node3.CompletionItemKind.Keyword, detail: "Input direction", documentation: "Port/parameter receives input" },
128614
128751
  { label: "out", kind: import_node3.CompletionItemKind.Keyword, detail: "Output direction", documentation: "Port/parameter provides output" },
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.40.0",
5
+ "version": "0.41.0",
6
6
  "publisher": "JamieD",
7
7
  "license": "MIT",
8
8
  "repository": {