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.
@@ -42741,6 +42741,9 @@ var Protocol = class {
42741
42741
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
42742
42742
  const handleTaskResult = async () => {
42743
42743
  const taskId = request.params.taskId;
42744
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
42745
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
42746
+ }
42744
42747
  if (this._taskMessageQueue) {
42745
42748
  let queuedMessage;
42746
42749
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -42771,12 +42774,12 @@ var Protocol = class {
42771
42774
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
42772
42775
  }
42773
42776
  if (!isTerminal(task.status)) {
42774
- await this._waitForTaskUpdate(taskId, extra.signal);
42777
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
42775
42778
  return await handleTaskResult();
42776
42779
  }
42777
42780
  if (isTerminal(task.status)) {
42778
42781
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
42779
- this._clearTaskQueue(taskId);
42782
+ this._clearTaskQueue(taskId, extra.sessionId);
42780
42783
  return {
42781
42784
  ...result,
42782
42785
  _meta: {
@@ -42813,7 +42816,7 @@ var Protocol = class {
42813
42816
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
42814
42817
  }
42815
42818
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
42816
- this._clearTaskQueue(request.params.taskId);
42819
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
42817
42820
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
42818
42821
  if (!cancelledTask) {
42819
42822
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -42941,6 +42944,19 @@ var Protocol = class {
42941
42944
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
42942
42945
  const capturedTransport = this._transport;
42943
42946
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
42947
+ const sessionId = capturedTransport?.sessionId;
42948
+ const store = this._taskStore;
42949
+ let relatedTaskFound = true;
42950
+ let relatedTaskLookup;
42951
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
42952
+ relatedTaskFound = false;
42953
+ relatedTaskLookup = (async () => {
42954
+ if (!await store.getTask(relatedTaskId, sessionId)) {
42955
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
42956
+ }
42957
+ relatedTaskFound = true;
42958
+ })();
42959
+ }
42944
42960
  if (handler === void 0) {
42945
42961
  const errorResponse = {
42946
42962
  jsonrpc: "2.0",
@@ -42950,7 +42966,10 @@ var Protocol = class {
42950
42966
  message: "Method not found"
42951
42967
  }
42952
42968
  };
42953
- if (relatedTaskId && this._taskMessageQueue) {
42969
+ if (relatedTaskId && relatedTaskLookup) {
42970
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
42971
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error62) => this._onerror(new Error(`Failed to send an error response: ${error62}`)));
42972
+ } else if (relatedTaskId && this._taskMessageQueue) {
42954
42973
  this._enqueueTaskMessage(relatedTaskId, {
42955
42974
  type: "error",
42956
42975
  message: errorResponse,
@@ -43001,7 +43020,10 @@ var Protocol = class {
43001
43020
  closeSSEStream: extra?.closeSSEStream,
43002
43021
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
43003
43022
  };
43004
- Promise.resolve().then(() => {
43023
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
43024
+ if (relatedTaskLookup && abortController.signal.aborted) {
43025
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
43026
+ }
43005
43027
  if (taskCreationParams) {
43006
43028
  this.assertTaskHandlerCapability(request.method);
43007
43029
  }
@@ -43036,7 +43058,7 @@ var Protocol = class {
43036
43058
  ...error62["data"] !== void 0 && { data: error62["data"] }
43037
43059
  }
43038
43060
  };
43039
- if (relatedTaskId && this._taskMessageQueue) {
43061
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
43040
43062
  await this._enqueueTaskMessage(relatedTaskId, {
43041
43063
  type: "error",
43042
43064
  message: errorResponse,
@@ -43516,7 +43538,7 @@ var Protocol = class {
43516
43538
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
43517
43539
  }
43518
43540
  const maxQueueSize = this._options?.maxTaskQueueSize;
43519
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
43541
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
43520
43542
  }
43521
43543
  /**
43522
43544
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -43545,12 +43567,13 @@ var Protocol = class {
43545
43567
  * Uses polling to check for updates at the task's configured poll interval.
43546
43568
  * @param taskId The task ID to wait for
43547
43569
  * @param signal Abort signal to cancel the wait
43570
+ * @param sessionId Session of the request that waits, passed to the task store
43548
43571
  * @returns Promise that resolves when an update occurs or rejects if aborted
43549
43572
  */
43550
- async _waitForTaskUpdate(taskId, signal) {
43573
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
43551
43574
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
43552
43575
  try {
43553
- const task = await this._taskStore?.getTask(taskId);
43576
+ const task = await this._taskStore?.getTask(taskId, sessionId);
43554
43577
  if (task?.pollInterval) {
43555
43578
  interval = task.pollInterval;
43556
43579
  }
@@ -44429,6 +44452,42 @@ var ExperimentalMcpServerTasks = class {
44429
44452
  };
44430
44453
 
44431
44454
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
44455
+ function toolInputElementCount(value, max) {
44456
+ let count = 0;
44457
+ const stack = [value];
44458
+ while (stack.length > 0) {
44459
+ const node2 = stack.pop();
44460
+ if (node2 === null || typeof node2 !== "object")
44461
+ continue;
44462
+ if (Array.isArray(node2)) {
44463
+ for (const child of node2) {
44464
+ if (++count > max)
44465
+ return count;
44466
+ if (child !== null && typeof child === "object")
44467
+ stack.push(child);
44468
+ }
44469
+ } else {
44470
+ for (const key in node2) {
44471
+ if (!Object.prototype.hasOwnProperty.call(node2, key))
44472
+ continue;
44473
+ if (++count > max)
44474
+ return count;
44475
+ const child = node2[key];
44476
+ if (child !== null && typeof child === "object")
44477
+ stack.push(child);
44478
+ }
44479
+ }
44480
+ }
44481
+ return count;
44482
+ }
44483
+ function resolveMaxToolInputElements(value) {
44484
+ if (value === void 0 || value === Infinity)
44485
+ return void 0;
44486
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
44487
+ throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
44488
+ }
44489
+ return value;
44490
+ }
44432
44491
  var McpServer = class {
44433
44492
  constructor(serverInfo, options) {
44434
44493
  this._registeredResources = {};
@@ -44440,6 +44499,7 @@ var McpServer = class {
44440
44499
  this._resourceHandlersInitialized = false;
44441
44500
  this._promptHandlersInitialized = false;
44442
44501
  this.server = new Server(serverInfo, options);
44502
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
44443
44503
  }
44444
44504
  /**
44445
44505
  * Access experimental features.
@@ -44570,12 +44630,15 @@ var McpServer = class {
44570
44630
  * Validates tool input arguments against the tool's input schema.
44571
44631
  */
44572
44632
  async validateToolInput(tool, args, toolName) {
44633
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
44634
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
44635
+ }
44573
44636
  if (!tool.inputSchema) {
44574
44637
  return void 0;
44575
44638
  }
44576
44639
  const inputObj = normalizeObjectSchema(tool.inputSchema);
44577
44640
  const schemaToParse = inputObj ?? tool.inputSchema;
44578
- const parseResult = await safeParseAsync2(schemaToParse, args);
44641
+ const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
44579
44642
  if (!parseResult.success) {
44580
44643
  const error62 = "error" in parseResult ? parseResult.error : "Unknown error";
44581
44644
  const errorMessage = getParseErrorMessage(error62);
@@ -44813,7 +44876,7 @@ var McpServer = class {
44813
44876
  }
44814
44877
  if (prompt.argsSchema) {
44815
44878
  const argsObj = normalizeObjectSchema(prompt.argsSchema);
44816
- const parseResult = await safeParseAsync2(argsObj, request.params.arguments);
44879
+ const parseResult = await safeParseAsync2(argsObj, request.params.arguments ?? {});
44817
44880
  if (!parseResult.success) {
44818
44881
  const error62 = "error" in parseResult ? parseResult.error : "Unknown error";
44819
44882
  const errorMessage = getParseErrorMessage(error62);
@@ -45355,6 +45418,8 @@ var SysMLElementKind = /* @__PURE__ */ ((SysMLElementKind2) => {
45355
45418
  SysMLElementKind2["TransitionUsage"] = "transition";
45356
45419
  SysMLElementKind2["RequirementDef"] = "requirement def";
45357
45420
  SysMLElementKind2["RequirementUsage"] = "requirement";
45421
+ SysMLElementKind2["ConcernDef"] = "concern def";
45422
+ SysMLElementKind2["ConcernUsage"] = "concern";
45358
45423
  SysMLElementKind2["ConstraintDef"] = "constraint def";
45359
45424
  SysMLElementKind2["ConstraintUsage"] = "constraint";
45360
45425
  SysMLElementKind2["ItemDef"] = "item def";
@@ -45466,6 +45531,10 @@ function toMetaclassName(kind) {
45466
45531
  return "RequirementDefinition";
45467
45532
  case "requirement" /* RequirementUsage */:
45468
45533
  return "RequirementUsage";
45534
+ case "concern def" /* ConcernDef */:
45535
+ return "ConcernDefinition";
45536
+ case "concern" /* ConcernUsage */:
45537
+ return "ConcernUsage";
45469
45538
  case "constraint def" /* ConstraintDef */:
45470
45539
  return "ConstraintDefinition";
45471
45540
  case "constraint" /* ConstraintUsage */:
@@ -158884,6 +158953,10 @@ function getLibraryPackageNames() {
158884
158953
  function canonicalUri(uri) {
158885
158954
  return uri.replace(/^file:\/\/\/([A-Za-z])(?::|%3[Aa])(?=\/|$)/, (_m, drive) => `file:///${drive.toLowerCase()}:`);
158886
158955
  }
158956
+ function isInFolder(uri, folderUri) {
158957
+ const folder = canonicalUri(folderUri);
158958
+ return canonicalUri(uri).startsWith(folder.endsWith("/") ? folder : `${folder}/`);
158959
+ }
158887
158960
  function isSameDocumentUri(a, b) {
158888
158961
  return a === b || canonicalUri(a) === canonicalUri(b);
158889
158962
  }
@@ -159474,6 +159547,7 @@ var NAMESPACE_URL = v5_default.URL;
159474
159547
  var DEFAULT_URL_PREFIX = "https://github.com/daltskin/sysml-v2-lsp/";
159475
159548
  var PROJECT_ID_ENV_VAR = "SYSML_PROJECT_ID";
159476
159549
  var urlPrefix = DEFAULT_URL_PREFIX;
159550
+ var folderPrefixes = [];
159477
159551
  function setProjectId(projectId2) {
159478
159552
  if (projectId2 === void 0) {
159479
159553
  urlPrefix = DEFAULT_URL_PREFIX;
@@ -159483,8 +159557,9 @@ function setProjectId(projectId2) {
159483
159557
  urlPrefix = `urn:uuid:${projectId2.toLowerCase()}/`;
159484
159558
  return true;
159485
159559
  }
159486
- function getUrlPrefix() {
159487
- return urlPrefix;
159560
+ function getUrlPrefix(uri) {
159561
+ const match = uri === void 0 ? void 0 : folderPrefixes.find((f) => isInFolder(uri, f.folderUri));
159562
+ return match?.prefix ?? urlPrefix;
159488
159563
  }
159489
159564
  function uuidV5(namespace, name) {
159490
159565
  return v5_default(name, namespace);
@@ -159544,7 +159619,7 @@ var IdRegistry = class {
159544
159619
  declaration.parentId = owner?.symbolId;
159545
159620
  const path = declaration.qualifiedName !== void 0 ? this.qualifiedNameAsWritten(declaration) : owner ? `${this.paths.get(owner)}/${segmentOf(declaration)}` : segmentOf(declaration);
159546
159621
  const namespace = owner ? this.topLevelOf(owner).symbolId : NAMESPACE_URL;
159547
- const key = owner ? path : getUrlPrefix() + encodeURIComponent(path);
159622
+ const key = owner ? path : getUrlPrefix(declaration.uri) + encodeURIComponent(path);
159548
159623
  const groupId = this.uuidOf(namespace, key);
159549
159624
  this.groupKeys.set(groupId, { namespace, key, path });
159550
159625
  this.groupOf.set(declaration, groupId);
@@ -159729,6 +159804,12 @@ var RULE_INDEX_TO_KIND = /* @__PURE__ */ new Map([
159729
159804
  // 343
159730
159805
  [SysMLv2Parser.RULE_requirementDefinition, "requirement def" /* RequirementDef */],
159731
159806
  // 384
159807
+ [SysMLv2Parser.RULE_concernDefinition, "concern def" /* ConcernDef */],
159808
+ // 405
159809
+ [SysMLv2Parser.RULE_concernUsage, "concern" /* ConcernUsage */],
159810
+ // 406
159811
+ [SysMLv2Parser.RULE_framedConcernUsage, "concern" /* ConcernUsage */],
159812
+ // 394
159732
159813
  [SysMLv2Parser.RULE_constraintDefinition, "constraint def" /* ConstraintDef */],
159733
159814
  // 380
159734
159815
  [SysMLv2Parser.RULE_itemDefinition, "item def" /* ItemDef */],
@@ -159801,6 +159882,10 @@ var RULE_INDEX_TO_KIND = /* @__PURE__ */ new Map([
159801
159882
  // 268
159802
159883
  [SysMLv2Parser.RULE_performActionUsage, "perform action" /* PerformActionUsage */],
159803
159884
  // 298
159885
+ // A state's `entry`/`do`/`exit` action (`exit action a : A;`, `exit a;`): the
159886
+ // StatePerformActionUsage production, a PerformActionUsage without `perform`.
159887
+ [SysMLv2Parser.RULE_statePerformActionUsage, "perform action" /* PerformActionUsage */],
159888
+ // 352
159804
159889
  [SysMLv2Parser.RULE_exhibitStateUsage, "exhibit state" /* ExhibitStateUsage */],
159805
159890
  // 359
159806
159891
  [SysMLv2Parser.RULE_transitionUsage, "transition" /* TransitionUsage */],
@@ -159924,8 +160009,10 @@ var TYPE_RECURSE_RULE_INDICES = /* @__PURE__ */ new Set([
159924
160009
  // 210
159925
160010
  SysMLv2Parser.RULE_definition,
159926
160011
  // 192
159927
- SysMLv2Parser.RULE_usage
160012
+ SysMLv2Parser.RULE_usage,
159928
160013
  // 208
160014
+ SysMLv2Parser.RULE_payloadFeatureSpecializationPart
160015
+ // 157
159929
160016
  ]);
159930
160017
  var DOC_RULE_INDICES = /* @__PURE__ */ new Set([
159931
160018
  SysMLv2Parser.RULE_comment,
@@ -160550,7 +160637,7 @@ var SymbolTable = class {
160550
160637
  const shortName = transition || isFlowUsage(kind) && !declaredName ? void 0 : this.extractShortName(ctx2);
160551
160638
  const qualifiedName = anonymous || owner && owner.qualifiedName === void 0 ? void 0 : owner ? `${owner.qualifiedName}::${name}` : name;
160552
160639
  const selectionRange = anonymous ? ctx2.start ? tokenToRange(ctx2.start) : range : this.extractNameRange(ctx2) ?? range;
160553
- const typeNames = isFlowUsage(kind) ? this.extractFlowTypeNames(ctx2) : this.extractTypeNames(ctx2);
160640
+ const typeNames = isFlowUsage(kind) ? this.extractFlowTypeNames(ctx2) : transition ? this.extractTransitionTypeNames(ctx2) : this.extractTypeNames(ctx2);
160554
160641
  const specializationNames = this.extractSpecializationNames(ctx2);
160555
160642
  const typeName = typeNames[0];
160556
160643
  const documentation = this.extractDocumentation(ctx2);
@@ -160665,6 +160752,25 @@ var SymbolTable = class {
160665
160752
  const typeDeclaration = declaration && (this.findOwnHeaderRule(declaration, SysMLv2Parser.RULE_featureDeclaration) ?? this.findOwnHeaderRule(declaration, SysMLv2Parser.RULE_usageDeclaration));
160666
160753
  return typeDeclaration ? this.extractTypeNames(typeDeclaration) : [];
160667
160754
  }
160755
+ /**
160756
+ * A transition's own typing, then the types of the payload its trigger
160757
+ * accepts (`accept cmd : Command`, `accept Command`; TriggerAction ->
160758
+ * AcceptParameterPart -> PayloadParameter). Read from the parse tree only:
160759
+ * the regex fallback of `extractTypeNames` runs on whitespace-free text, where
160760
+ * the payload type runs into the guard, effect or target that follows it
160761
+ * (`Commandifcmd`, `Commandthenbusy`).
160762
+ */
160763
+ extractTransitionTypeNames(ctx2) {
160764
+ const names = [];
160765
+ this.collectTypeNamesFromTree(ctx2, names, 0);
160766
+ const trigger = this.findOwnHeaderRule(ctx2, SysMLv2Parser.RULE_triggerActionMember);
160767
+ const parameter = trigger && this.findRuleContext(trigger, SysMLv2Parser.RULE_payloadParameter);
160768
+ if (parameter) {
160769
+ const payload = this.findRuleContext(parameter, SysMLv2Parser.RULE_payloadFeature) ?? parameter;
160770
+ this.collectTypeNamesFromTree(payload, names, 0);
160771
+ }
160772
+ return names;
160773
+ }
160668
160774
  /** Find the first descendant of `ctx` with rule `ruleIndex`, in source order. */
160669
160775
  findRuleContext(ctx2, ruleIndex) {
160670
160776
  const matches = [];
@@ -160758,7 +160864,7 @@ var SymbolTable = class {
160758
160864
  const child = ctx2.getChild(i);
160759
160865
  if (child instanceof TerminalNode) {
160760
160866
  const token = child.symbol;
160761
- if (this.isIdentifierToken(token)) {
160867
+ if (this.isNameTerminal(child)) {
160762
160868
  return this.unquoteName(token.text ?? "");
160763
160869
  }
160764
160870
  }
@@ -160790,7 +160896,7 @@ var SymbolTable = class {
160790
160896
  */
160791
160897
  anonymousDeclaration(ctx2, kind, transition) {
160792
160898
  if (!isDefinition(kind) && !isUsage(kind)) return void 0;
160793
- if (transition && !(transition.source && transition.target) && this.extractTypeNames(ctx2).length === 0) return void 0;
160899
+ if (transition && !(transition.source && transition.target) && this.extractTransitionTypeNames(ctx2).length === 0) return void 0;
160794
160900
  return this.declarationText(ctx2);
160795
160901
  }
160796
160902
  /**
@@ -160810,14 +160916,15 @@ var SymbolTable = class {
160810
160916
  /**
160811
160917
  * The first node of rule `ruleIndex` in `ctx`'s own declaration: never
160812
160918
  * inside a nested element, its body, its value, a flow's payload or ends,
160813
- * or a prefix such as `#metadata`.
160919
+ * a connector end's own multiplicity (`connect [2] a to b`), or a prefix
160920
+ * such as `#metadata`.
160814
160921
  */
160815
160922
  findOwnHeaderRule(ctx2, ruleIndex) {
160816
160923
  for (let i = 0; i < ctx2.getChildCount(); i++) {
160817
160924
  const child = ctx2.getChild(i);
160818
160925
  if (!(child instanceof ParserRuleContext)) continue;
160819
160926
  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;
160927
+ 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
160928
  const found = this.findOwnHeaderRule(child, ruleIndex);
160822
160929
  if (found) return found;
160823
160930
  }
@@ -160981,7 +161088,7 @@ var SymbolTable = class {
160981
161088
  extractNameRange(ctx2) {
160982
161089
  for (let i = 0; i < ctx2.getChildCount(); i++) {
160983
161090
  const child = ctx2.getChild(i);
160984
- if (child instanceof TerminalNode && this.isIdentifierToken(child.symbol)) {
161091
+ if (child instanceof TerminalNode && this.isNameTerminal(child)) {
160985
161092
  return tokenToRange(child.symbol);
160986
161093
  }
160987
161094
  if (child instanceof ParserRuleContext) {
@@ -161166,12 +161273,12 @@ var SymbolTable = class {
161166
161273
  return lines.join("\n").trim();
161167
161274
  }
161168
161275
  /**
161169
- * Extract multiplicity from a context.
161170
- * Looks for MultiplicityBoundsContext in the subtree.
161276
+ * Extract multiplicity from a context's own declaration, never from a
161277
+ * nested element or its body.
161171
161278
  * Returns { multiplicity: "1..5", multiplicityRange: { lower: 1, upper: 5 } }
161172
161279
  */
161173
161280
  extractMultiplicity(ctx2) {
161174
- const multCtx = this.findMultiplicityBounds(ctx2);
161281
+ const multCtx = this.findOwnHeaderRule(ctx2, SysMLv2Parser.RULE_multiplicityBounds);
161175
161282
  if (!multCtx) {
161176
161283
  return {};
161177
161284
  }
@@ -161225,24 +161332,6 @@ var SymbolTable = class {
161225
161332
  multiplicityRange: { lower, upper }
161226
161333
  };
161227
161334
  }
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
161335
  /**
161247
161336
  * Whether a context is a prefix metadata or definition/usage prefix rule.
161248
161337
  * These contain annotation identifiers (e.g. from `#product`) that should
@@ -161284,6 +161373,14 @@ var SymbolTable = class {
161284
161373
  if (this.isQuotedName(text)) return true;
161285
161374
  return /^[a-zA-Z_]/.test(text) && !this.isKeyword(text);
161286
161375
  }
161376
+ /**
161377
+ * Whether a terminal is (part of) a name: an identifier, a quoted name, or
161378
+ * a KerML keyword such as `step` or `function` that the grammar parsed as a
161379
+ * name (`name : IDENTIFIER | STRING | unreservedKeyword`).
161380
+ */
161381
+ isNameTerminal(node2) {
161382
+ return this.isIdentifierToken(node2.symbol) || node2.parent?.ruleIndex === SysMLv2Parser.RULE_unreservedKeyword;
161383
+ }
161287
161384
  /**
161288
161385
  * Check if text is a SysML quoted name (single-quoted string).
161289
161386
  */
@@ -161653,7 +161750,7 @@ var SymbolTable = class {
161653
161750
  const child = ctx2.getChild(i);
161654
161751
  if (child instanceof TerminalNode) {
161655
161752
  const text = child.symbol.text;
161656
- if (text && this.isIdentifierToken(child.symbol)) {
161753
+ if (text && this.isNameTerminal(child)) {
161657
161754
  parts.push(this.unquoteName(text));
161658
161755
  }
161659
161756
  } else if (child instanceof ParserRuleContext) {
@@ -162080,9 +162177,8 @@ var SysMLModelProvider = class {
162080
162177
  if (direction) {
162081
162178
  attributes["direction"] = direction;
162082
162179
  }
162083
- const multiplicity = this.extractMultiplicity(symbol2, lines);
162084
- if (multiplicity) {
162085
- attributes["multiplicity"] = multiplicity;
162180
+ if (symbol2.multiplicity) {
162181
+ attributes["multiplicity"] = symbol2.multiplicity;
162086
162182
  }
162087
162183
  const modifier = this.extractModifier(symbol2, lines);
162088
162184
  if (modifier) {
@@ -162700,7 +162796,7 @@ var SysMLModelProvider = class {
162700
162796
  name: c.name,
162701
162797
  kind: toMetaclassName(c.kind),
162702
162798
  type: c.typeNames.join(", ") || void 0,
162703
- multiplicity: c.multiplicity ?? this.extractMultiplicity(c, lines),
162799
+ multiplicity: c.multiplicity,
162704
162800
  direction,
162705
162801
  visibility: c.visibility,
162706
162802
  isDerived: modifier?.split(", ").includes("derived") ?? false,
@@ -162824,15 +162920,6 @@ var SysMLModelProvider = class {
162824
162920
  if (containsWord(elementText, "out")) return "out";
162825
162921
  return void 0;
162826
162922
  }
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
162923
  /** Extract modifiers (abstract, readonly, derived, etc.) from source text. */
162837
162924
  extractModifier(symbol2, lines) {
162838
162925
  const elementText = this.getElementText(symbol2, lines);