sysml-v2-lsp 0.33.0 → 0.35.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.
@@ -121638,6 +121638,10 @@ var SYSML_KEYWORDS = new Set(SYSML_KEYWORDS_ARRAY);
121638
121638
  function canonicalUri(uri) {
121639
121639
  return uri.replace(/^file:\/\/\/([A-Za-z])(?::|%3[Aa])(?=\/|$)/, (_m, drive) => `file:///${drive.toLowerCase()}:`);
121640
121640
  }
121641
+ function isInFolder(uri, folderUri) {
121642
+ const folder = canonicalUri(folderUri);
121643
+ return canonicalUri(uri).startsWith(folder.endsWith("/") ? folder : `${folder}/`);
121644
+ }
121641
121645
  function isSameDocumentUri(a, b) {
121642
121646
  return a === b || canonicalUri(a) === canonicalUri(b);
121643
121647
  }
@@ -121740,6 +121744,7 @@ var v5_default = v5;
121740
121744
  var NAMESPACE_URL = v5_default.URL;
121741
121745
  var DEFAULT_URL_PREFIX = "https://github.com/daltskin/sysml-v2-lsp/";
121742
121746
  var urlPrefix = DEFAULT_URL_PREFIX;
121747
+ var folderPrefixes = [];
121743
121748
  function setProjectId(projectId) {
121744
121749
  if (projectId === void 0) {
121745
121750
  urlPrefix = DEFAULT_URL_PREFIX;
@@ -121749,8 +121754,14 @@ function setProjectId(projectId) {
121749
121754
  urlPrefix = `urn:uuid:${projectId.toLowerCase()}/`;
121750
121755
  return true;
121751
121756
  }
121752
- function getUrlPrefix() {
121753
- return urlPrefix;
121757
+ function setFolderProjectIds(projectIds) {
121758
+ const rejected = projectIds.filter((p) => !validate_default(p.projectId));
121759
+ folderPrefixes = projectIds.filter((p) => validate_default(p.projectId)).map((p) => ({ folderUri: p.folderUri, prefix: `urn:uuid:${p.projectId.toLowerCase()}/` })).sort((a, b) => b.folderUri.length - a.folderUri.length);
121760
+ return rejected;
121761
+ }
121762
+ function getUrlPrefix(uri) {
121763
+ const match = uri === void 0 ? void 0 : folderPrefixes.find((f) => isInFolder(uri, f.folderUri));
121764
+ return match?.prefix ?? urlPrefix;
121754
121765
  }
121755
121766
  function uuidV5(namespace, name) {
121756
121767
  return v5_default(name, namespace);
@@ -121832,6 +121843,10 @@ function toMetaclassName(kind) {
121832
121843
  return "RequirementDefinition";
121833
121844
  case "requirement" /* RequirementUsage */:
121834
121845
  return "RequirementUsage";
121846
+ case "concern def" /* ConcernDef */:
121847
+ return "ConcernDefinition";
121848
+ case "concern" /* ConcernUsage */:
121849
+ return "ConcernUsage";
121835
121850
  case "constraint def" /* ConstraintDef */:
121836
121851
  return "ConstraintDefinition";
121837
121852
  case "constraint" /* ConstraintUsage */:
@@ -121954,7 +121969,7 @@ var IdRegistry = class {
121954
121969
  declaration.parentId = owner?.symbolId;
121955
121970
  const path3 = declaration.qualifiedName !== void 0 ? this.qualifiedNameAsWritten(declaration) : owner ? `${this.paths.get(owner)}/${segmentOf(declaration)}` : segmentOf(declaration);
121956
121971
  const namespace = owner ? this.topLevelOf(owner).symbolId : NAMESPACE_URL;
121957
- const key = owner ? path3 : getUrlPrefix() + encodeURIComponent(path3);
121972
+ const key = owner ? path3 : getUrlPrefix(declaration.uri) + encodeURIComponent(path3);
121958
121973
  const groupId = this.uuidOf(namespace, key);
121959
121974
  this.groupKeys.set(groupId, { namespace, key, path: path3 });
121960
121975
  this.groupOf.set(declaration, groupId);
@@ -122139,6 +122154,12 @@ var RULE_INDEX_TO_KIND = /* @__PURE__ */ new Map([
122139
122154
  // 343
122140
122155
  [SysMLv2Parser.RULE_requirementDefinition, "requirement def" /* RequirementDef */],
122141
122156
  // 384
122157
+ [SysMLv2Parser.RULE_concernDefinition, "concern def" /* ConcernDef */],
122158
+ // 405
122159
+ [SysMLv2Parser.RULE_concernUsage, "concern" /* ConcernUsage */],
122160
+ // 406
122161
+ [SysMLv2Parser.RULE_framedConcernUsage, "concern" /* ConcernUsage */],
122162
+ // 394
122142
122163
  [SysMLv2Parser.RULE_constraintDefinition, "constraint def" /* ConstraintDef */],
122143
122164
  // 380
122144
122165
  [SysMLv2Parser.RULE_itemDefinition, "item def" /* ItemDef */],
@@ -122211,6 +122232,10 @@ var RULE_INDEX_TO_KIND = /* @__PURE__ */ new Map([
122211
122232
  // 268
122212
122233
  [SysMLv2Parser.RULE_performActionUsage, "perform action" /* PerformActionUsage */],
122213
122234
  // 298
122235
+ // A state's `entry`/`do`/`exit` action (`exit action a : A;`, `exit a;`): the
122236
+ // StatePerformActionUsage production, a PerformActionUsage without `perform`.
122237
+ [SysMLv2Parser.RULE_statePerformActionUsage, "perform action" /* PerformActionUsage */],
122238
+ // 352
122214
122239
  [SysMLv2Parser.RULE_exhibitStateUsage, "exhibit state" /* ExhibitStateUsage */],
122215
122240
  // 359
122216
122241
  [SysMLv2Parser.RULE_transitionUsage, "transition" /* TransitionUsage */],
@@ -122334,8 +122359,10 @@ var TYPE_RECURSE_RULE_INDICES = /* @__PURE__ */ new Set([
122334
122359
  // 210
122335
122360
  SysMLv2Parser.RULE_definition,
122336
122361
  // 192
122337
- SysMLv2Parser.RULE_usage
122362
+ SysMLv2Parser.RULE_usage,
122338
122363
  // 208
122364
+ SysMLv2Parser.RULE_payloadFeatureSpecializationPart
122365
+ // 157
122339
122366
  ]);
122340
122367
  var DOC_RULE_INDICES = /* @__PURE__ */ new Set([
122341
122368
  SysMLv2Parser.RULE_comment,
@@ -122960,7 +122987,7 @@ var SymbolTable = class {
122960
122987
  const shortName = transition || isFlowUsage(kind) && !declaredName ? void 0 : this.extractShortName(ctx);
122961
122988
  const qualifiedName = anonymous || owner && owner.qualifiedName === void 0 ? void 0 : owner ? `${owner.qualifiedName}::${name}` : name;
122962
122989
  const selectionRange = anonymous ? ctx.start ? tokenToRange(ctx.start) : range : this.extractNameRange(ctx) ?? range;
122963
- const typeNames = isFlowUsage(kind) ? this.extractFlowTypeNames(ctx) : this.extractTypeNames(ctx);
122990
+ const typeNames = isFlowUsage(kind) ? this.extractFlowTypeNames(ctx) : transition ? this.extractTransitionTypeNames(ctx) : this.extractTypeNames(ctx);
122964
122991
  const specializationNames = this.extractSpecializationNames(ctx);
122965
122992
  const typeName = typeNames[0];
122966
122993
  const documentation = this.extractDocumentation(ctx);
@@ -123075,6 +123102,25 @@ var SymbolTable = class {
123075
123102
  const typeDeclaration = declaration && (this.findOwnHeaderRule(declaration, SysMLv2Parser.RULE_featureDeclaration) ?? this.findOwnHeaderRule(declaration, SysMLv2Parser.RULE_usageDeclaration));
123076
123103
  return typeDeclaration ? this.extractTypeNames(typeDeclaration) : [];
123077
123104
  }
123105
+ /**
123106
+ * A transition's own typing, then the types of the payload its trigger
123107
+ * accepts (`accept cmd : Command`, `accept Command`; TriggerAction ->
123108
+ * AcceptParameterPart -> PayloadParameter). Read from the parse tree only:
123109
+ * the regex fallback of `extractTypeNames` runs on whitespace-free text, where
123110
+ * the payload type runs into the guard, effect or target that follows it
123111
+ * (`Commandifcmd`, `Commandthenbusy`).
123112
+ */
123113
+ extractTransitionTypeNames(ctx) {
123114
+ const names = [];
123115
+ this.collectTypeNamesFromTree(ctx, names, 0);
123116
+ const trigger = this.findOwnHeaderRule(ctx, SysMLv2Parser.RULE_triggerActionMember);
123117
+ const parameter = trigger && this.findRuleContext(trigger, SysMLv2Parser.RULE_payloadParameter);
123118
+ if (parameter) {
123119
+ const payload = this.findRuleContext(parameter, SysMLv2Parser.RULE_payloadFeature) ?? parameter;
123120
+ this.collectTypeNamesFromTree(payload, names, 0);
123121
+ }
123122
+ return names;
123123
+ }
123078
123124
  /** Find the first descendant of `ctx` with rule `ruleIndex`, in source order. */
123079
123125
  findRuleContext(ctx, ruleIndex) {
123080
123126
  const matches = [];
@@ -123168,7 +123214,7 @@ var SymbolTable = class {
123168
123214
  const child = ctx.getChild(i);
123169
123215
  if (child instanceof TerminalNode) {
123170
123216
  const token = child.symbol;
123171
- if (this.isIdentifierToken(token)) {
123217
+ if (this.isNameTerminal(child)) {
123172
123218
  return this.unquoteName(token.text ?? "");
123173
123219
  }
123174
123220
  }
@@ -123200,7 +123246,7 @@ var SymbolTable = class {
123200
123246
  */
123201
123247
  anonymousDeclaration(ctx, kind, transition) {
123202
123248
  if (!isDefinition(kind) && !isUsage(kind)) return void 0;
123203
- if (transition && !(transition.source && transition.target) && this.extractTypeNames(ctx).length === 0) return void 0;
123249
+ if (transition && !(transition.source && transition.target) && this.extractTransitionTypeNames(ctx).length === 0) return void 0;
123204
123250
  return this.declarationText(ctx);
123205
123251
  }
123206
123252
  /**
@@ -123220,14 +123266,15 @@ var SymbolTable = class {
123220
123266
  /**
123221
123267
  * The first node of rule `ruleIndex` in `ctx`'s own declaration: never
123222
123268
  * inside a nested element, its body, its value, a flow's payload or ends,
123223
- * or a prefix such as `#metadata`.
123269
+ * a connector end's own multiplicity (`connect [2] a to b`), or a prefix
123270
+ * such as `#metadata`.
123224
123271
  */
123225
123272
  findOwnHeaderRule(ctx, ruleIndex) {
123226
123273
  for (let i = 0; i < ctx.getChildCount(); i++) {
123227
123274
  const child = ctx.getChild(i);
123228
123275
  if (!(child instanceof ParserRuleContext)) continue;
123229
123276
  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;
123277
+ 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
123278
  const found = this.findOwnHeaderRule(child, ruleIndex);
123232
123279
  if (found) return found;
123233
123280
  }
@@ -123391,7 +123438,7 @@ var SymbolTable = class {
123391
123438
  extractNameRange(ctx) {
123392
123439
  for (let i = 0; i < ctx.getChildCount(); i++) {
123393
123440
  const child = ctx.getChild(i);
123394
- if (child instanceof TerminalNode && this.isIdentifierToken(child.symbol)) {
123441
+ if (child instanceof TerminalNode && this.isNameTerminal(child)) {
123395
123442
  return tokenToRange(child.symbol);
123396
123443
  }
123397
123444
  if (child instanceof ParserRuleContext) {
@@ -123576,12 +123623,12 @@ var SymbolTable = class {
123576
123623
  return lines.join("\n").trim();
123577
123624
  }
123578
123625
  /**
123579
- * Extract multiplicity from a context.
123580
- * Looks for MultiplicityBoundsContext in the subtree.
123626
+ * Extract multiplicity from a context's own declaration, never from a
123627
+ * nested element or its body.
123581
123628
  * Returns { multiplicity: "1..5", multiplicityRange: { lower: 1, upper: 5 } }
123582
123629
  */
123583
123630
  extractMultiplicity(ctx) {
123584
- const multCtx = this.findMultiplicityBounds(ctx);
123631
+ const multCtx = this.findOwnHeaderRule(ctx, SysMLv2Parser.RULE_multiplicityBounds);
123585
123632
  if (!multCtx) {
123586
123633
  return {};
123587
123634
  }
@@ -123635,24 +123682,6 @@ var SymbolTable = class {
123635
123682
  multiplicityRange: { lower, upper }
123636
123683
  };
123637
123684
  }
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
123685
  /**
123657
123686
  * Whether a context is a prefix metadata or definition/usage prefix rule.
123658
123687
  * These contain annotation identifiers (e.g. from `#product`) that should
@@ -123694,6 +123723,14 @@ var SymbolTable = class {
123694
123723
  if (this.isQuotedName(text)) return true;
123695
123724
  return /^[a-zA-Z_]/.test(text) && !this.isKeyword(text);
123696
123725
  }
123726
+ /**
123727
+ * Whether a terminal is (part of) a name: an identifier, a quoted name, or
123728
+ * a KerML keyword such as `step` or `function` that the grammar parsed as a
123729
+ * name (`name : IDENTIFIER | STRING | unreservedKeyword`).
123730
+ */
123731
+ isNameTerminal(node) {
123732
+ return this.isIdentifierToken(node.symbol) || node.parent?.ruleIndex === SysMLv2Parser.RULE_unreservedKeyword;
123733
+ }
123697
123734
  /**
123698
123735
  * Check if text is a SysML quoted name (single-quoted string).
123699
123736
  */
@@ -124063,7 +124100,7 @@ var SymbolTable = class {
124063
124100
  const child = ctx.getChild(i);
124064
124101
  if (child instanceof TerminalNode) {
124065
124102
  const text = child.symbol.text;
124066
- if (text && this.isIdentifierToken(child.symbol)) {
124103
+ if (text && this.isNameTerminal(child)) {
124067
124104
  parts.push(this.unquoteName(text));
124068
124105
  }
124069
124106
  } else if (child instanceof ParserRuleContext) {
@@ -124289,6 +124326,17 @@ var DocumentManager = class {
124289
124326
  }
124290
124327
  return this.wsSymbolTable;
124291
124328
  }
124329
+ /**
124330
+ * Rebuild the symbol tables of `uris` on next use, e.g. after their projectId
124331
+ * changed, which changes their symbol IDs (see `setFolderProjectIds`).
124332
+ */
124333
+ invalidateSymbols(uris) {
124334
+ for (const uri of uris) {
124335
+ const cached = this.cache.get(uri);
124336
+ if (cached) cached.symbolTable = void 0;
124337
+ this.wsBuiltVersions.delete(uri);
124338
+ }
124339
+ }
124292
124340
  /**
124293
124341
  * Cache semantic diagnostics for the current document version.
124294
124342
  */
@@ -126020,9 +126068,8 @@ var SysMLModelProvider = class {
126020
126068
  if (direction) {
126021
126069
  attributes["direction"] = direction;
126022
126070
  }
126023
- const multiplicity = this.extractMultiplicity(symbol, lines);
126024
- if (multiplicity) {
126025
- attributes["multiplicity"] = multiplicity;
126071
+ if (symbol.multiplicity) {
126072
+ attributes["multiplicity"] = symbol.multiplicity;
126026
126073
  }
126027
126074
  const modifier = this.extractModifier(symbol, lines);
126028
126075
  if (modifier) {
@@ -126640,7 +126687,7 @@ var SysMLModelProvider = class {
126640
126687
  name: c.name,
126641
126688
  kind: toMetaclassName(c.kind),
126642
126689
  type: c.typeNames.join(", ") || void 0,
126643
- multiplicity: c.multiplicity ?? this.extractMultiplicity(c, lines),
126690
+ multiplicity: c.multiplicity,
126644
126691
  direction,
126645
126692
  visibility: c.visibility,
126646
126693
  isDerived: modifier?.split(", ").includes("derived") ?? false,
@@ -126764,15 +126811,6 @@ var SysMLModelProvider = class {
126764
126811
  if (containsWord(elementText, "out")) return "out";
126765
126812
  return void 0;
126766
126813
  }
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
126814
  /** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
126777
126815
  extractModifier(symbol, lines) {
126778
126816
  const elementText = this.getElementText(symbol, lines);
@@ -128292,6 +128330,8 @@ function toSysMLSymbolKind(kind) {
128292
128330
  // Requirements → Object
128293
128331
  case "requirement def" /* RequirementDef */:
128294
128332
  case "requirement" /* RequirementUsage */:
128333
+ case "concern def" /* ConcernDef */:
128334
+ case "concern" /* ConcernUsage */:
128295
128335
  case "actor" /* ActorUsage */:
128296
128336
  case "subject" /* SubjectUsage */:
128297
128337
  case "stakeholder" /* StakeholderUsage */:
@@ -130685,6 +130725,10 @@ hoverProvider.setSemanticValidator(semanticValidator);
130685
130725
  var hasConfigurationCapability = false;
130686
130726
  var hasWorkspaceFolderCapability = false;
130687
130727
  var workspaceRoots = [];
130728
+ var workspaceFolderUris = [];
130729
+ function rootsOf(folderUris) {
130730
+ return folderUris.map((uri) => toFsPath(uri)).filter((p) => p !== void 0);
130731
+ }
130688
130732
  var isWorkspaceFile = false;
130689
130733
  var preloadOnOpen = "workspaceOnly";
130690
130734
  var disabledDiagnosticCodes = /* @__PURE__ */ new Set();
@@ -130696,6 +130740,10 @@ function publishDiagnostics(uri, diagnostics) {
130696
130740
  }
130697
130741
  var skipDirs = new Set(DEFAULT_SKIP_DIRS);
130698
130742
  var serverReady = false;
130743
+ var resolveInitialization;
130744
+ var initialization = new Promise((resolve2) => {
130745
+ resolveInitialization = resolve2;
130746
+ });
130699
130747
  var earlyOpenUris = /* @__PURE__ */ new Set();
130700
130748
  var workerRequestId = 0;
130701
130749
  var isBrowserServer = typeof __SYSML_BROWSER_SERVER__ !== "undefined" && __SYSML_BROWSER_SERVER__;
@@ -130809,7 +130857,8 @@ connection.onInitialize((params) => {
130809
130857
  connection.console.warn(`projectId is not a UUID: ${initOpts.projectId}; symbol IDs are unique only within this workspace`);
130810
130858
  }
130811
130859
  if (params.workspaceFolders) {
130812
- workspaceRoots = params.workspaceFolders.map((f) => toFsPath(f.uri)).filter((p) => p !== void 0);
130860
+ workspaceFolderUris = params.workspaceFolders.map((f) => f.uri);
130861
+ workspaceRoots = rootsOf(workspaceFolderUris);
130813
130862
  } else if (params.rootUri) {
130814
130863
  const root = toFsPath(params.rootUri);
130815
130864
  if (root) workspaceRoots = [root];
@@ -130859,7 +130908,8 @@ connection.onInitialize((params) => {
130859
130908
  if (hasWorkspaceFolderCapability) {
130860
130909
  result.capabilities.workspace = {
130861
130910
  workspaceFolders: {
130862
- supported: true
130911
+ supported: true,
130912
+ changeNotifications: true
130863
130913
  }
130864
130914
  };
130865
130915
  }
@@ -130871,8 +130921,17 @@ connection.onInitialized(async () => {
130871
130921
  import_node12.DidChangeConfigurationNotification.type,
130872
130922
  void 0
130873
130923
  );
130924
+ }
130925
+ if (hasWorkspaceFolderCapability) {
130926
+ connection.workspace.onDidChangeWorkspaceFolders((event) => {
130927
+ onWorkspaceFoldersChanged(event).catch((e) => connection.console.error(`Workspace folder change failed: ${e}`));
130928
+ });
130929
+ }
130930
+ if (hasConfigurationCapability) {
130874
130931
  await pullSettings().catch(() => {
130875
130932
  });
130933
+ await pullFolderProjectIds().catch(() => {
130934
+ });
130876
130935
  }
130877
130936
  const libCount = initLibraryIndex(__dirname);
130878
130937
  connection.console.log(`SysML v2 Language Server initialized (${libCount} library packages indexed)`);
@@ -130888,14 +130947,13 @@ connection.onInitialized(async () => {
130888
130947
  );
130889
130948
  }
130890
130949
  serverReady = true;
130950
+ resolveInitialization();
130891
130951
  spawnParseWorker();
130892
130952
  if (workspaceRoots.length > 0 && (preloadOnOpen === "always" || preloadOnOpen === "workspaceOnly" && isWorkspaceFile)) {
130893
- documentManager.setWorkspaceScanComplete(false);
130894
- scanWorkspaceFoldersAsync(workspaceRoots).then(({ fileCount, scanMs }) => {
130953
+ scanWorkspaceFolders(workspaceRoots).then(({ fileCount, scanMs }) => {
130895
130954
  connection.console.log(
130896
130955
  `Workspace scan: pre-parsed ${fileCount} .sysml files in ${scanMs} ms`
130897
130956
  );
130898
- documentManager.setWorkspaceScanComplete(true);
130899
130957
  revalidateOpenDocuments();
130900
130958
  });
130901
130959
  }
@@ -130930,9 +130988,79 @@ function applySettings(config) {
130930
130988
  }
130931
130989
  }
130932
130990
  connection.onDidChangeConfiguration((_change) => {
130933
- pullSettings().then(() => revalidateOpenDocuments()).catch(() => {
130991
+ pullSettings().then(() => pullFolderProjectIds()).then(() => revalidateOpenDocuments()).catch(() => {
130992
+ });
130993
+ });
130994
+ function latestWins(task) {
130995
+ let calls = 0;
130996
+ let latest = Promise.resolve();
130997
+ return () => {
130998
+ const call = ++calls;
130999
+ const isSuperseded = () => call !== calls;
131000
+ const run = task(isSuperseded).then(() => isSuperseded() ? latest : void 0);
131001
+ latest = run;
131002
+ return run;
131003
+ };
131004
+ }
131005
+ var pullFolderProjectIds = latestWins(async (isSuperseded) => {
131006
+ if (!hasConfigurationCapability) return;
131007
+ const folderUris = [...workspaceFolderUris];
131008
+ const answers = folderUris.length === 0 ? [] : await connection.workspace.getConfiguration(folderUris.map((scopeUri) => ({ scopeUri, section: "sysml.project" })));
131009
+ if (isSuperseded()) return;
131010
+ const projectIds = folderUris.flatMap((folderUri, i) => {
131011
+ const projectId = answers[i]?.projectId;
131012
+ return typeof projectId === "string" ? [{ folderUri, projectId }] : [];
130934
131013
  });
131014
+ const uris = documentManager.getUris();
131015
+ const prefixBefore = new Map(uris.map((uri) => [uri, getUrlPrefix(uri)]));
131016
+ const rejected = setFolderProjectIds(projectIds);
131017
+ for (const entry of rejected) {
131018
+ connection.console.warn(`projectId of ${entry.folderUri} is not a UUID: ${entry.projectId}; ignored, so its documents use the projectId of an enclosing folder, else initializationOptions.projectId, else the default prefix`);
131019
+ }
131020
+ documentManager.invalidateSymbols(uris.filter((uri) => getUrlPrefix(uri) !== prefixBefore.get(uri)));
131021
+ logFolderPrefixes(new Set(projectIds.filter((p) => !rejected.includes(p)).map((p) => p.folderUri)));
130935
131022
  });
131023
+ var loggedFolderPrefixes = /* @__PURE__ */ new Map();
131024
+ function logFolderPrefixes(ownProjectIds) {
131025
+ for (const folderUri of workspaceFolderUris) {
131026
+ const prefix = getUrlPrefix(`${folderUri.endsWith("/") ? folderUri : `${folderUri}/`}_.sysml`);
131027
+ if (loggedFolderPrefixes.get(folderUri) === prefix) continue;
131028
+ loggedFolderPrefixes.set(folderUri, prefix);
131029
+ const source = ownProjectIds.has(folderUri) ? "its projectId" : prefix === getUrlPrefix() ? prefix === DEFAULT_URL_PREFIX ? "the default prefix, no projectId" : "initializationOptions.projectId" : "an enclosing folder's projectId";
131030
+ connection.console.info(`Folder ${folderUri}: top-level elements' URLs start with ${prefix} (${source})`);
131031
+ }
131032
+ for (const folderUri of loggedFolderPrefixes.keys()) {
131033
+ if (!workspaceFolderUris.includes(folderUri)) loggedFolderPrefixes.delete(folderUri);
131034
+ }
131035
+ }
131036
+ async function onWorkspaceFoldersChanged(event) {
131037
+ const initialScanPending = !serverReady;
131038
+ const removed = new Set(event.removed.map((f) => f.uri));
131039
+ workspaceFolderUris = [...workspaceFolderUris.filter((uri) => !removed.has(uri)), ...event.added.map((f) => f.uri)];
131040
+ workspaceRoots = rootsOf(workspaceFolderUris);
131041
+ dropDocumentsOutsideWorkspace(event.removed.map((f) => f.uri));
131042
+ await pullFolderProjectIds().catch(() => {
131043
+ });
131044
+ if (initialScanPending) return;
131045
+ const addedRoots = rootsOf(event.added.map((f) => f.uri).filter((uri) => workspaceFolderUris.includes(uri)));
131046
+ if (addedRoots.length > 0 && (preloadOnOpen === "always" || preloadOnOpen === "workspaceOnly" && isWorkspaceFile)) {
131047
+ const { fileCount, scanMs } = await scanWorkspaceFolders(addedRoots);
131048
+ connection.console.log(`Workspace scan: pre-parsed ${fileCount} .sysml files of ${addedRoots.length} added folder(s) in ${scanMs} ms`);
131049
+ }
131050
+ revalidateOpenDocuments();
131051
+ }
131052
+ function dropDocumentsOutsideWorkspace(folderUris) {
131053
+ for (const uri of documentManager.getUris()) {
131054
+ if (openDocumentFor(uri)) continue;
131055
+ if (folderUris.some((f) => isInFolder(uri, f)) && !isInWorkspace(uri)) {
131056
+ documentManager.remove(uri);
131057
+ modelProvider.removeUri(uri);
131058
+ }
131059
+ }
131060
+ }
131061
+ function isInWorkspace(uri) {
131062
+ return workspaceRoots.some((root) => isInFolder(uri, (0, import_node_url2.pathToFileURL)(root).toString()));
131063
+ }
130936
131064
  function openDocumentFor(uri) {
130937
131065
  return documents.get(uri) ?? documents.all().find((d) => isSameDocumentUri(d.uri, uri));
130938
131066
  }
@@ -130957,6 +131085,16 @@ function parseWorkspaceFile(filePath, uri = (0, import_node_url2.pathToFileURL)(
130957
131085
  documentManager.parse(doc);
130958
131086
  return true;
130959
131087
  }
131088
+ var runningScans = 0;
131089
+ async function scanWorkspaceFolders(roots) {
131090
+ runningScans++;
131091
+ documentManager.setWorkspaceScanComplete(false);
131092
+ try {
131093
+ return await scanWorkspaceFoldersAsync(roots);
131094
+ } finally {
131095
+ if (--runningScans === 0) documentManager.setWorkspaceScanComplete(true);
131096
+ }
131097
+ }
130960
131098
  async function scanWorkspaceFoldersAsync(roots) {
130961
131099
  const scanT0 = Date.now();
130962
131100
  const fileArrays = await Promise.all(roots.map((r) => findSysMLFilesAsync(r, skipDirs)));
@@ -130968,6 +131106,7 @@ async function scanWorkspaceFoldersAsync(roots) {
130968
131106
  const filePath = allFiles[i];
130969
131107
  const uri = (0, import_node_url2.pathToFileURL)(filePath).toString();
130970
131108
  if (openDocumentFor(uri)) continue;
131109
+ if (!isInWorkspace(uri)) continue;
130971
131110
  const content = fileContents.get(filePath);
130972
131111
  if (content === void 0) continue;
130973
131112
  documentManager.parseBatch(uri, 0, content);
@@ -131180,14 +131319,16 @@ connection.onDocumentRangeFormatting(
131180
131319
  return formattingProvider.provideRangeFormatting(params);
131181
131320
  }
131182
131321
  );
131183
- connection.onRequest("sysml/model", (params) => {
131322
+ connection.onRequest("sysml/model", async (params) => {
131323
+ await initialization;
131184
131324
  return modelProvider.getModel(
131185
131325
  params.textDocument.uri,
131186
131326
  documentManager.getVersion(params.textDocument.uri),
131187
131327
  params.scope
131188
131328
  );
131189
131329
  });
131190
- connection.onRequest("sysml/elementLookup", (params) => {
131330
+ connection.onRequest("sysml/elementLookup", async (params) => {
131331
+ await initialization;
131191
131332
  return elementLookupProvider.elementLookup(params);
131192
131333
  });
131193
131334
  connection.onRequest("sysml/serverStats", () => {
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.33.0",
5
+ "version": "0.35.0",
6
6
  "publisher": "JamieD",
7
7
  "license": "MIT",
8
8
  "repository": {