sysml-v2-lsp 0.35.0 → 0.36.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 CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.36.0]
6
+
7
+ ### Fixed
8
+
9
+ - `incompatible-port-types` resolves each end of a `connect` through the features its path names (`a.p.q`), not by the port's name alone. Feature types and their supertypes are resolved in their declaring namespace, so unrelated same-named definitions cannot hide a real mismatch. When two parts each had a port of the same name, the first one declared stood in for both, causing false warnings or missed mismatches. An unresolved path still falls back to the name when only one port has it (#135).
10
+ - A colon, `:>`, `{` or keyword inside a quoted name is no longer read as part of a declaration: `package 'Structure: System Context'` was typed `System` and reported as `unresolved-type`, and `part def 'Unit: Main'` was typed `Main`. Type and specialization fallback extraction masks the declaration's lexer `STRING` tokens, without scanning documentation or nested members, avoiding quadratic regex backtracking on quote-heavy comments (#134).
11
+ - Visit each specialization ancestor only once when resolving inherited constraint features, preventing exponential queue growth through layered diamond inheritance (#127).
12
+ - Hide implicitly redefined requirement subjects according to the declaring requirement's specialization ancestors, including redundant direct bases in multiple inheritance, while preserving subjects from unrelated branches.
13
+ - Display decoded filesystem paths in workspace-folder logs and clarify that
14
+ element ID namespaces are used locally, without network access. Emit this
15
+ internal namespace information at debug level instead of info.
16
+
5
17
  ## [0.35.0]
6
18
 
7
19
  ### Added
@@ -3362,7 +3362,7 @@ ${JSON.stringify(message, null, 4)}`);
3362
3362
  }
3363
3363
  uinteger3.is = is;
3364
3364
  })(uinteger || (uinteger = {}));
3365
- (function(Position4) {
3365
+ (function(Position5) {
3366
3366
  function create(line, character) {
3367
3367
  if (line === Number.MAX_VALUE) {
3368
3368
  line = uinteger.MAX_VALUE;
@@ -3372,14 +3372,14 @@ ${JSON.stringify(message, null, 4)}`);
3372
3372
  }
3373
3373
  return { line, character };
3374
3374
  }
3375
- Position4.create = create;
3375
+ Position5.create = create;
3376
3376
  function is(value) {
3377
3377
  const candidate = value;
3378
3378
  return Is.objectLiteral(candidate) && Is.uinteger(candidate.line) && Is.uinteger(candidate.character);
3379
3379
  }
3380
- Position4.is = is;
3380
+ Position5.is = is;
3381
3381
  })(Position || (Position = {}));
3382
- (function(Range4) {
3382
+ (function(Range5) {
3383
3383
  function create(one, two, three, four) {
3384
3384
  if (Is.uinteger(one) && Is.uinteger(two) && Is.uinteger(three) && Is.uinteger(four)) {
3385
3385
  return { start: Position.create(one, two), end: Position.create(three, four) };
@@ -3389,12 +3389,12 @@ ${JSON.stringify(message, null, 4)}`);
3389
3389
  throw new Error(`Range#create called with invalid arguments[${one}, ${two}, ${three}, ${four}]`);
3390
3390
  }
3391
3391
  }
3392
- Range4.create = create;
3392
+ Range5.create = create;
3393
3393
  function is(value) {
3394
3394
  const candidate = value;
3395
3395
  return Is.objectLiteral(candidate) && Position.is(candidate.start) && Position.is(candidate.end);
3396
3396
  }
3397
- Range4.is = is;
3397
+ Range5.is = is;
3398
3398
  })(Range || (Range = {}));
3399
3399
  (function(Location4) {
3400
3400
  function create(uri, range) {
@@ -12435,7 +12435,7 @@ ${JSON.stringify(message, null, 4)}`);
12435
12435
  }
12436
12436
  uinteger3.is = is;
12437
12437
  })(uinteger2 || (uinteger2 = {}));
12438
- (function(Position4) {
12438
+ (function(Position5) {
12439
12439
  function create(line, character) {
12440
12440
  if (line === Number.MAX_VALUE) {
12441
12441
  line = uinteger2.MAX_VALUE;
@@ -12445,14 +12445,14 @@ ${JSON.stringify(message, null, 4)}`);
12445
12445
  }
12446
12446
  return { line, character };
12447
12447
  }
12448
- Position4.create = create;
12448
+ Position5.create = create;
12449
12449
  function is(value) {
12450
12450
  let candidate = value;
12451
12451
  return Is2.objectLiteral(candidate) && Is2.uinteger(candidate.line) && Is2.uinteger(candidate.character);
12452
12452
  }
12453
- Position4.is = is;
12453
+ Position5.is = is;
12454
12454
  })(Position2 || (Position2 = {}));
12455
- (function(Range4) {
12455
+ (function(Range5) {
12456
12456
  function create(one, two, three, four) {
12457
12457
  if (Is2.uinteger(one) && Is2.uinteger(two) && Is2.uinteger(three) && Is2.uinteger(four)) {
12458
12458
  return { start: Position2.create(one, two), end: Position2.create(three, four) };
@@ -12462,12 +12462,12 @@ ${JSON.stringify(message, null, 4)}`);
12462
12462
  throw new Error(`Range#create called with invalid arguments[${one}, ${two}, ${three}, ${four}]`);
12463
12463
  }
12464
12464
  }
12465
- Range4.create = create;
12465
+ Range5.create = create;
12466
12466
  function is(value) {
12467
12467
  let candidate = value;
12468
12468
  return Is2.objectLiteral(candidate) && Position2.is(candidate.start) && Position2.is(candidate.end);
12469
12469
  }
12470
- Range4.is = is;
12470
+ Range5.is = is;
12471
12471
  })(Range2 || (Range2 = {}));
12472
12472
  (function(Location4) {
12473
12473
  function create(uri, range) {
@@ -131659,6 +131659,7 @@ ${JSON.stringify(message, null, 4)}`);
131659
131659
  const selectionRange = anonymous ? ctx.start ? tokenToRange(ctx.start) : range : this.extractNameRange(ctx) ?? range;
131660
131660
  const typeNames = isFlowUsage(kind) ? this.extractFlowTypeNames(ctx) : transition ? this.extractTransitionTypeNames(ctx) : this.extractTypeNames(ctx);
131661
131661
  const specializationNames = this.extractSpecializationNames(ctx);
131662
+ const redefinedFeatureTargets = this.extractRedefinedFeatureTargets(ctx);
131662
131663
  const typeName = typeNames[0];
131663
131664
  const documentation = this.extractDocumentation(ctx);
131664
131665
  const visibility = this.extractVisibility(ctx);
@@ -131689,6 +131690,7 @@ ${JSON.stringify(message, null, 4)}`);
131689
131690
  typeName,
131690
131691
  typeNames,
131691
131692
  specializationNames,
131693
+ redefinedFeatureTargets: redefinedFeatureTargets.length > 0 ? redefinedFeatureTargets : void 0,
131692
131694
  documentation,
131693
131695
  visibility,
131694
131696
  source: transition?.source,
@@ -131940,15 +131942,28 @@ ${JSON.stringify(message, null, 4)}`);
131940
131942
  * such as `#metadata`.
131941
131943
  */
131942
131944
  findOwnHeaderRule(ctx, ruleIndex) {
131945
+ const matches = [];
131946
+ this.findOwnHeaderRules(ctx, ruleIndex, matches, true);
131947
+ return matches[0];
131948
+ }
131949
+ findOwnHeaderRules(ctx, ruleIndex, matches, firstOnly = false) {
131943
131950
  for (let i = 0; i < ctx.getChildCount(); i++) {
131944
131951
  const child = ctx.getChild(i);
131945
131952
  if (!(child instanceof ParserRuleContext)) continue;
131946
- if (child.ruleIndex === ruleIndex) return child;
131953
+ if (child.ruleIndex === ruleIndex) {
131954
+ matches.push(child);
131955
+ if (firstOnly) return;
131956
+ continue;
131957
+ }
131947
131958
  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;
131948
- const found = this.findOwnHeaderRule(child, ruleIndex);
131949
- if (found) return found;
131959
+ this.findOwnHeaderRules(child, ruleIndex, matches, firstOnly);
131960
+ if (firstOnly && matches.length > 0) return;
131950
131961
  }
131951
- return void 0;
131962
+ }
131963
+ extractRedefinedFeatureTargets(ctx) {
131964
+ const targets = [];
131965
+ this.findOwnHeaderRules(ctx, SysMLv2Parser.RULE_ownedRedefinition, targets);
131966
+ return targets.map((target) => target.getText());
131952
131967
  }
131953
131968
  /**
131954
131969
  * A connection, interface or allocation usage's end reference paths, in
@@ -131976,13 +131991,7 @@ ${JSON.stringify(message, null, 4)}`);
131976
131991
  const segment = reference.getText().split(/::|\./).pop();
131977
131992
  return segment ? this.unquoteName(segment) : void 0;
131978
131993
  }
131979
- /**
131980
- * An element's declaration as written, without its body: its tokens up to
131981
- * its body or closing `;`, each exactly as written (a quoted name keeps its
131982
- * spaces), with one space wherever the source has whitespace or a comment
131983
- * between two of them (`connect a.p to b.p`, `connection : Conn`).
131984
- */
131985
- declarationText(ctx) {
131994
+ declarationTokens(ctx) {
131986
131995
  const tokens = [];
131987
131996
  const visit = (node) => {
131988
131997
  for (let i = 0; i < node.getChildCount(); i++) {
@@ -131997,6 +132006,16 @@ ${JSON.stringify(message, null, 4)}`);
131997
132006
  return false;
131998
132007
  };
131999
132008
  visit(ctx);
132009
+ return tokens;
132010
+ }
132011
+ /**
132012
+ * An element's declaration as written, without its body: its tokens up to
132013
+ * its body or closing `;`, each exactly as written (a quoted name keeps its
132014
+ * spaces), with one space wherever the source has whitespace or a comment
132015
+ * between two of them (`connect a.p to b.p`, `connection : Conn`).
132016
+ */
132017
+ declarationText(ctx) {
132018
+ const tokens = this.declarationTokens(ctx);
132000
132019
  let text = "";
132001
132020
  tokens.forEach((token, i) => {
132002
132021
  if (i > 0 && token.start > tokens[i - 1].stop + 1) text += " ";
@@ -132137,17 +132156,16 @@ ${JSON.stringify(message, null, 4)}`);
132137
132156
  const names = [];
132138
132157
  this.collectTypeNamesFromTree(ctx, names, 0);
132139
132158
  if (names.length > 0) return names;
132140
- const fullText = ctx.getText();
132141
- const braceIdx = fullText.indexOf("{");
132142
- let text = braceIdx >= 0 ? fullText.substring(0, braceIdx) : fullText;
132159
+ const { text: declarationText, quotedName } = this.maskedDeclaration(ctx);
132160
+ let text = declarationText;
132143
132161
  text = text.replace(RE_KEYWORD_TRUNCATE, "");
132144
132162
  const specMatch = text.match(RE_SPEC);
132145
132163
  if (specMatch) {
132146
132164
  const specStr = text.substring(text.indexOf(specMatch[0]) + specMatch[0].indexOf(specMatch[1]));
132147
132165
  for (const part of specStr.split(",")) {
132148
- const qm = part.match(RE_QUOTED_NAME);
132149
- if (qm) {
132150
- names.push(qm[1]);
132166
+ const quoted = quotedName(part);
132167
+ if (quoted !== void 0) {
132168
+ names.push(quoted);
132151
132169
  continue;
132152
132170
  }
132153
132171
  const m2 = part.trim().match(RE_IDENT_START);
@@ -132168,9 +132186,9 @@ ${JSON.stringify(message, null, 4)}`);
132168
132186
  const fullMatchIdx = text.indexOf(typingMatch[0]);
132169
132187
  const afterColon = text.substring(fullMatchIdx + 1).trim();
132170
132188
  for (const part of afterColon.split(",")) {
132171
- const qm = part.match(RE_QUOTED_NAME);
132172
- if (qm) {
132173
- names.push(qm[1]);
132189
+ const quoted = quotedName(part);
132190
+ if (quoted !== void 0) {
132191
+ names.push(quoted);
132174
132192
  continue;
132175
132193
  }
132176
132194
  const m2 = part.trim().match(RE_IDENT_START);
@@ -132180,6 +132198,28 @@ ${JSON.stringify(message, null, 4)}`);
132180
132198
  }
132181
132199
  return names;
132182
132200
  }
132201
+ /**
132202
+ * The declaration tokens before the body, with each lexer STRING token
132203
+ * replaced by a numbered placeholder (`'0'`, `'1'`, ...), and
132204
+ * `quotedName`, which turns a placeholder in a part of that text back into
132205
+ * the name. SysML 2.0 section 7.2.2 permits punctuation in unrestricted
132206
+ * names (the STRING lexer production), so fallback regexes must never see
132207
+ * their `:`, `:>`, `{` or keywords. Documentation is not a name token.
132208
+ */
132209
+ maskedDeclaration(ctx) {
132210
+ const quoted = [];
132211
+ const masked = this.declarationTokens(ctx).map((token) => {
132212
+ const text = token.text ?? "";
132213
+ return token.type === SysMLv2Lexer.STRING ? `'${quoted.push(text.slice(1, -1)) - 1}'` : text;
132214
+ }).join("");
132215
+ return {
132216
+ text: masked,
132217
+ quotedName: (part) => {
132218
+ const qm = part.match(RE_QUOTED_NAME);
132219
+ return qm ? quoted[Number(qm[1])] : void 0;
132220
+ }
132221
+ };
132222
+ }
132183
132223
  /**
132184
132224
  * Extract only the specialization names (:> / specializes / subsets) from a context.
132185
132225
  * Uses the same tree-walk as extractTypeNames but restricted to
@@ -132190,17 +132230,15 @@ ${JSON.stringify(message, null, 4)}`);
132190
132230
  const names = [];
132191
132231
  this.collectNamesFromTree(ctx, names, 0, TYPE_SPECIALIZATION_RULE_INDICES);
132192
132232
  if (names.length > 0) return names;
132193
- const fullText = ctx.getText();
132194
- const braceIdx = fullText.indexOf("{");
132195
- let text = braceIdx >= 0 ? fullText.substring(0, braceIdx) : fullText;
132196
- text = text.replace(RE_KEYWORD_TRUNCATE_SPEC, "");
132233
+ const { text: declarationText, quotedName } = this.maskedDeclaration(ctx);
132234
+ const text = declarationText.replace(RE_KEYWORD_TRUNCATE_SPEC, "");
132197
132235
  const specMatch = text.match(RE_SPEC_WITH_SUBSETS);
132198
132236
  if (specMatch) {
132199
132237
  const specStr = text.substring(text.indexOf(specMatch[0]) + specMatch[0].indexOf(specMatch[1]));
132200
132238
  for (const part of specStr.split(",")) {
132201
- const qm = part.match(RE_QUOTED_NAME);
132202
- if (qm) {
132203
- names.push(qm[1]);
132239
+ const quoted = quotedName(part);
132240
+ if (quoted !== void 0) {
132241
+ names.push(quoted);
132204
132242
  continue;
132205
132243
  }
132206
132244
  const m2 = part.trim().match(RE_IDENT_START);
@@ -136405,14 +136443,21 @@ ${JSON.stringify(message, null, 4)}`);
136405
136443
  * namespace.
136406
136444
  */
136407
136445
  isLocallyVisible(symbol, name, indexes) {
136408
- return this.resolveQualifiedNameFrom(ownerKeyOf(symbol, indexes.byId), name, indexes) !== void 0;
136446
+ return this.resolveNameFrom(symbol, name, indexes) !== void 0;
136447
+ }
136448
+ /**
136449
+ * Resolve a (possibly qualified) name from the namespace containing
136450
+ * `symbol`, respecting namespace membership and visibility.
136451
+ */
136452
+ resolveNameFrom(symbol, name, indexes) {
136453
+ return this.resolveQualifiedNameFrom(ownerKeyOf(symbol, indexes.byId), name, indexes);
136409
136454
  }
136410
136455
  /**
136411
136456
  * Resolve a (possibly qualified) name to its symbol per §7.5.1, searching
136412
136457
  * outward from namespace `start` and its enclosing namespaces (its own resolved
136413
136458
  * members first, then its parent's, ...). Shared by `isLocallyVisible` (an
136414
- * ordinary reference resolving relative to its own enclosing namespace) and
136415
- * import-target resolution (an `import` declaration's target is itself a
136459
+ * ordinary reference resolving relative to its own enclosing namespace),
136460
+ * `resolveNameFrom`, and import-target resolution (an `import` declaration's target is itself a
136416
136461
  * qualifiedName, resolved the same relative way -- not as an absolute/global
136417
136462
  * name -- so a bare `import C;` inside a nested package can pick up a `C`
136418
136463
  * its own enclosing package already imported, per §7.5.1/§7.5.3).
@@ -140622,6 +140667,13 @@ ${info.documentation}`);
140622
140667
  "assert",
140623
140668
  "assume"
140624
140669
  ]);
140670
+ var CONNECTOR_KINDS = /* @__PURE__ */ new Set([
140671
+ "connection" /* ConnectionUsage */,
140672
+ "interface" /* InterfaceUsage */,
140673
+ "allocation" /* AllocationUsage */,
140674
+ "flow" /* FlowUsage */,
140675
+ "succession flow" /* SuccessionFlowUsage */
140676
+ ]);
140625
140677
  var SemanticValidator = class _SemanticValidator {
140626
140678
  constructor(documentManager2) {
140627
140679
  this.documentManager = documentManager2;
@@ -140698,7 +140750,7 @@ ${info.documentation}`);
140698
140750
  diagnostics.push(...this.checkAmbiguousNamespaceName(symbols, allSymbols));
140699
140751
  diagnostics.push(...this.checkUnusedDefinitions(allSymbols, uri));
140700
140752
  diagnostics.push(...this.checkRedefinitionMultiplicity(symbols, indexes, text));
140701
- diagnostics.push(...this.checkPortCompatibility(text, uri, indexes));
140753
+ diagnostics.push(...this.checkPortCompatibility(text, uri, symbols, indexes));
140702
140754
  diagnostics.push(...this.checkConstraintBodyReferences(text, uri, symbols, indexes));
140703
140755
  diagnostics.push(...this.checkCircularSpecialization(symbols, indexes));
140704
140756
  diagnostics.push(...this.checkUnsatisfiedRequirements(symbols, indexes));
@@ -140919,7 +140971,7 @@ ${info.documentation}`);
140919
140971
  opts?.text ? [opts.text] : []
140920
140972
  ));
140921
140973
  if (opts?.text && opts.uri) {
140922
- diagnostics.push(...instance.checkPortCompatibility(opts.text, opts.uri, indexes));
140974
+ diagnostics.push(...instance.checkPortCompatibility(opts.text, opts.uri, symbolsInUri, indexes));
140923
140975
  diagnostics.push(...instance.checkConstraintBodyReferences(opts.text, opts.uri, symbolsInUri, indexes));
140924
140976
  }
140925
140977
  return instance.dedupeDiagnostics(diagnostics);
@@ -141282,17 +141334,20 @@ ${info.documentation}`);
141282
141334
  * - The connection is within an interface usage
141283
141335
  * - Both ports are untyped (empty port defs with no features)
141284
141336
  */
141285
- checkPortCompatibility(text, uri, indexes) {
141337
+ checkPortCompatibility(text, uri, symbolsInUri, indexes) {
141286
141338
  if (!text) return [];
141287
141339
  const diagnostics = [];
141288
141340
  const lines = text.split("\n");
141289
141341
  const re = /\bconnect\s+([A-Za-z_][\w.]*)\s+to\s+([A-Za-z_][\w.]*)/g;
141290
141342
  let m2;
141291
141343
  while ((m2 = re.exec(text)) !== null) {
141292
- const left = m2[1].split(".").pop();
141293
- const right = m2[2].split(".").pop();
141294
- const lSym = (indexes.portsByName.get(left) ?? [])[0];
141295
- const rSym = (indexes.portsByName.get(right) ?? [])[0];
141344
+ const leftPath = m2[1].split(".");
141345
+ const rightPath = m2[2].split(".");
141346
+ const left = leftPath[leftPath.length - 1];
141347
+ const right = rightPath[rightPath.length - 1];
141348
+ const scope = this.connectorScope(symbolsInUri, this.indexToRange(text, m2.index, 0).start, indexes);
141349
+ const lSym = this.resolveConnectorEnd(leftPath, scope, indexes);
141350
+ const rSym = this.resolveConnectorEnd(rightPath, scope, indexes);
141296
141351
  if (!lSym || !rSym) continue;
141297
141352
  const lType = lSym.typeNames[0] ?? lSym.typeName;
141298
141353
  const rType = rSym.typeNames[0] ?? rSym.typeName;
@@ -141342,6 +141397,55 @@ ${info.documentation}`);
141342
141397
  }
141343
141398
  return diagnostics;
141344
141399
  }
141400
+ /**
141401
+ * The innermost element around `position` that owns a connector declared
141402
+ * there: the connector's own symbol, when it has one, is skipped.
141403
+ */
141404
+ connectorScope(symbols, position, indexes) {
141405
+ const before = (a, b) => a.line < b.line || a.line === b.line && a.character <= b.character;
141406
+ const size = (r) => (r.end.line - r.start.line) * 1e6 + (r.end.character - r.start.character);
141407
+ let scope;
141408
+ for (const s of symbols) {
141409
+ if (!before(s.range.start, position) || !before(position, s.range.end)) continue;
141410
+ if (!scope || size(s.range) < size(scope.range)) scope = s;
141411
+ }
141412
+ while (scope && CONNECTOR_KINDS.has(scope.kind)) scope = ownerOf(scope, indexes);
141413
+ return scope;
141414
+ }
141415
+ /**
141416
+ * The port that a connector end (`a.p`, `a.p.q`) names, resolved from
141417
+ * `scope` outward: its first segment is a feature of `scope` or of one of
141418
+ * its owners, each next one a feature of the one before. Two parts can each
141419
+ * have a port of the same name, so an end is never matched by its last
141420
+ * segment alone, except when the path does not resolve and the workspace
141421
+ * has only one port of that name.
141422
+ */
141423
+ resolveConnectorEnd(path, scope, indexes) {
141424
+ let feature;
141425
+ for (let namespace = scope; namespace && !feature; namespace = ownerOf(namespace, indexes)) {
141426
+ feature = this.findFeature(namespace, path[0], indexes);
141427
+ }
141428
+ for (const name of path.slice(1)) {
141429
+ feature = feature && this.findFeature(feature, name, indexes);
141430
+ }
141431
+ if (feature) return feature.kind === "port" /* PortUsage */ ? feature : void 0;
141432
+ const sameName = indexes.portsByName.get(path[path.length - 1]) ?? [];
141433
+ return sameName.length === 1 ? sameName[0] : void 0;
141434
+ }
141435
+ /** The feature `name` of `owner`: its own member, else a member of one of its types or their supertypes. */
141436
+ findFeature(owner, name, indexes) {
141437
+ const own = (indexes.byParent.get(namespaceKeyOf(owner)) ?? []).find((s) => s.name === name);
141438
+ if (own) return own;
141439
+ for (const typeName of owner.typeNames) {
141440
+ const type = this.namespaceResolver.resolveNameFrom(owner, typeName, indexes);
141441
+ if (!type || !isDefinition(type.kind)) continue;
141442
+ for (const definition of this.getSpecializationHierarchy(type, indexes).flat()) {
141443
+ const member = (indexes.byParent.get(namespaceKeyOf(definition)) ?? []).find((s) => s.name === name);
141444
+ if (member) return member;
141445
+ }
141446
+ }
141447
+ return void 0;
141448
+ }
141345
141449
  /**
141346
141450
  * Resolve the full type hierarchy for a type name by following
141347
141451
  * specialization chains transitively (max depth 10).
@@ -141389,7 +141493,7 @@ ${info.documentation}`);
141389
141493
  }
141390
141494
  const parent = this.findConstraintScopeSymbol(symbolsInUri, indexes, b.startLine);
141391
141495
  if (!parent) continue;
141392
- const parentMembers = indexes.byParent.get(namespaceKeyOf(parent)) ?? [];
141496
+ const parentMembers = this.getConstraintScopeMembers(parent, indexes);
141393
141497
  if (parentMembers.length === 0) continue;
141394
141498
  const ignoredRanges = this.getIgnoredBodyRanges(b.body);
141395
141499
  const idRe = /\b([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*)\b/g;
@@ -141448,18 +141552,135 @@ ${info.documentation}`);
141448
141552
  const root = parentMembers.find((s) => s.name === path[0]);
141449
141553
  if (!root) return false;
141450
141554
  if (path.length === 1) return true;
141451
- let typeName = root.typeNames[0] ?? root.typeName;
141555
+ let current = root;
141452
141556
  for (let i = 1; i < path.length; i++) {
141557
+ const typeName = current.typeNames[0] ?? current.typeName;
141453
141558
  if (!typeName) return false;
141454
- const typeDefs = indexes.definitionsByName.get(typeName) ?? [];
141455
- const typeDef = typeDefs[0];
141456
- if (!typeDef) return false;
141457
- const member = (indexes.byParent.get(namespaceKeyOf(typeDef)) ?? []).find((s) => s.name === path[i]);
141559
+ const typeDef = this.namespaceResolver.resolveNameFrom(current, typeName, indexes);
141560
+ if (!typeDef || !isDefinition(typeDef.kind)) return false;
141561
+ const member = this.getConstraintScopeMembers(typeDef, indexes, true).find((s) => s.name === path[i]);
141458
141562
  if (!member) return false;
141459
- typeName = member.typeNames[0] ?? member.typeName;
141563
+ current = member;
141460
141564
  }
141461
141565
  return true;
141462
141566
  }
141567
+ getConstraintScopeMembers(scope, indexes, publicOnly = false) {
141568
+ const hierarchy = [[scope]];
141569
+ const visited = /* @__PURE__ */ new Set([scope]);
141570
+ let frontier = [scope];
141571
+ while (frontier.length > 0) {
141572
+ const next = [];
141573
+ for (const current of frontier) {
141574
+ for (const typeName of current.typeNames) {
141575
+ const supertype = this.namespaceResolver.resolveNameFrom(current, typeName, indexes);
141576
+ if (!supertype || !isDefinition(supertype.kind) || visited.has(supertype)) continue;
141577
+ visited.add(supertype);
141578
+ next.push(supertype);
141579
+ }
141580
+ }
141581
+ if (next.length > 0) hierarchy.push(next);
141582
+ frontier = next;
141583
+ }
141584
+ const membersByLevel = hierarchy.map((level) => level.flatMap((namespace) => indexes.byParent.get(namespaceKeyOf(namespace)) ?? []));
141585
+ const hiddenMembers = /* @__PURE__ */ new Set();
141586
+ for (let level = membersByLevel.length - 1; level >= 0; level--) {
141587
+ for (const redefining of membersByLevel[level]) {
141588
+ for (const target of redefining.redefinedFeatureTargets ?? []) {
141589
+ const owner = ownerOf(redefining, indexes);
141590
+ if (!owner) continue;
141591
+ for (const candidate of this.resolveInheritedRedefinitionTarget(owner, target, hiddenMembers, indexes)) {
141592
+ hiddenMembers.add(candidate.symbolId);
141593
+ }
141594
+ }
141595
+ if (redefining.kind === "subject" /* SubjectUsage */) {
141596
+ const owner = ownerOf(redefining, indexes);
141597
+ if (!owner) continue;
141598
+ for (const ancestor of this.getSpecializationHierarchy(owner, indexes).slice(1).flat()) {
141599
+ for (const candidate of indexes.byParent.get(namespaceKeyOf(ancestor)) ?? []) {
141600
+ if (candidate.kind === "subject" /* SubjectUsage */) hiddenMembers.add(candidate.symbolId);
141601
+ }
141602
+ }
141603
+ }
141604
+ }
141605
+ }
141606
+ const membersByName = /* @__PURE__ */ new Map();
141607
+ for (let level = 0; level < membersByLevel.length; level++) {
141608
+ for (const member of membersByLevel[level]) {
141609
+ if (level > 0 && member.visibility === "private") continue;
141610
+ if (publicOnly && member.visibility !== void 0 && member.visibility !== "public") continue;
141611
+ if (hiddenMembers.has(member.symbolId) || membersByName.has(member.name)) continue;
141612
+ membersByName.set(member.name, member);
141613
+ }
141614
+ }
141615
+ return [...membersByName.values()];
141616
+ }
141617
+ resolveInheritedRedefinitionTarget(owner, target, alreadyRedefined, indexes) {
141618
+ if (target.includes(".")) return [];
141619
+ const segments = target.split("::");
141620
+ const targetName = segments.pop()?.replace(/^'|'$/g, "");
141621
+ if (!targetName) return [];
141622
+ const qualifier = segments.join("::").replace(/^'|'$/g, "");
141623
+ const matches = /* @__PURE__ */ new Map();
141624
+ for (const supertype of this.resolveDirectSupertypes(owner, indexes)) {
141625
+ const branch = this.getSpecializationHierarchy(supertype, indexes);
141626
+ const anchors = qualifier ? branch.flat().filter((type) => this.matchesSpecializationQualifier(type, qualifier)) : [supertype];
141627
+ for (const anchor of anchors) {
141628
+ let frontier = [anchor];
141629
+ const visited = new Set(frontier);
141630
+ const candidates = [];
141631
+ while (frontier.length > 0 && candidates.length === 0) {
141632
+ for (const type of frontier) {
141633
+ for (const member of indexes.byParent.get(namespaceKeyOf(type)) ?? []) {
141634
+ if (member.name === targetName && member.visibility !== "private" && !alreadyRedefined.has(member.symbolId)) {
141635
+ candidates.push(member);
141636
+ }
141637
+ }
141638
+ }
141639
+ if (candidates.length > 0) break;
141640
+ const next = /* @__PURE__ */ new Map();
141641
+ for (const type of frontier) {
141642
+ for (const parent of this.resolveDirectSupertypes(type, indexes)) {
141643
+ if (visited.has(parent)) continue;
141644
+ visited.add(parent);
141645
+ next.set(parent.symbolId, parent);
141646
+ }
141647
+ }
141648
+ frontier = [...next.values()];
141649
+ }
141650
+ for (const candidate of candidates) matches.set(candidate.symbolId, candidate);
141651
+ }
141652
+ }
141653
+ return matches.size === 1 ? [...matches.values()] : [];
141654
+ }
141655
+ resolveDirectSupertypes(scope, indexes) {
141656
+ const supertypes = /* @__PURE__ */ new Map();
141657
+ for (const typeName of scope.typeNames) {
141658
+ const supertype = this.namespaceResolver.resolveNameFrom(scope, typeName, indexes);
141659
+ if (supertype && isDefinition(supertype.kind)) supertypes.set(supertype.symbolId, supertype);
141660
+ }
141661
+ return [...supertypes.values()];
141662
+ }
141663
+ getSpecializationHierarchy(scope, indexes) {
141664
+ const levels = [[scope]];
141665
+ const visited = /* @__PURE__ */ new Set([scope]);
141666
+ let frontier = [scope];
141667
+ while (frontier.length > 0) {
141668
+ const next = [];
141669
+ for (const type of frontier) {
141670
+ for (const parent of this.resolveDirectSupertypes(type, indexes)) {
141671
+ if (visited.has(parent)) continue;
141672
+ visited.add(parent);
141673
+ next.push(parent);
141674
+ }
141675
+ }
141676
+ if (next.length > 0) levels.push(next);
141677
+ frontier = next;
141678
+ }
141679
+ return levels;
141680
+ }
141681
+ matchesSpecializationQualifier(type, qualifier) {
141682
+ return type.name === qualifier || type.qualifiedName === qualifier || type.qualifiedName?.endsWith(`::${qualifier}`) === true;
141683
+ }
141463
141684
  findContainingSymbolByLine(symbols, line) {
141464
141685
  return symbols.filter((s) => s.range.start.line <= line && s.range.end.line >= line).sort((a, b) => {
141465
141686
  const ar = (a.range.end.line - a.range.start.line) * 1e3 + (a.range.end.character - a.range.start.character);
@@ -141470,7 +141691,7 @@ ${info.documentation}`);
141470
141691
  findConstraintScopeSymbol(symbolsInUri, indexes, line) {
141471
141692
  let scope = this.findContainingSymbolByLine(symbolsInUri, line);
141472
141693
  while (scope) {
141473
- const members = indexes.byParent.get(namespaceKeyOf(scope)) ?? [];
141694
+ const members = this.getConstraintScopeMembers(scope, indexes);
141474
141695
  if (members.length > 0) return scope;
141475
141696
  if (!scope.parentId) return scope;
141476
141697
  scope = ownerOf(scope, indexes);
@@ -142065,7 +142286,8 @@ ${info.documentation}`);
142065
142286
  if (loggedFolderPrefixes.get(folderUri) === prefix) continue;
142066
142287
  loggedFolderPrefixes.set(folderUri, prefix);
142067
142288
  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";
142068
- connection.console.info(`Folder ${folderUri}: top-level elements' URLs start with ${prefix} (${source})`);
142289
+ const folderPath = toFsPath(folderUri) ?? folderUri;
142290
+ connection.console.debug(`Folder ${folderPath}: element ID namespace ${prefix} (${source}; ID namespace only, no network access)`);
142069
142291
  }
142070
142292
  for (const folderUri of loggedFolderPrefixes.keys()) {
142071
142293
  if (!workspaceFolderUris.includes(folderUri)) loggedFolderPrefixes.delete(folderUri);