@neocompose/cli 0.31.5 → 0.31.7

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/dist/neo.mjs CHANGED
@@ -2484,14 +2484,19 @@ function signatureHelp(snapshot, position) {
2484
2484
  function inlayHints(snapshot, range2) {
2485
2485
  const hints = [];
2486
2486
  for (const call of snapshot.parsed.calls) {
2487
- if (call.kind !== "constructor") continue;
2488
- const type = snapshot.project.typeByName.get(call.name);
2489
- const parameterNames = constructorParameterNames(type);
2487
+ const reference2 = snapshot.parsed.references.find(
2488
+ (candidate) => candidate.range.start.line === call.nameRange.start.line && candidate.range.start.character === call.nameRange.start.character
2489
+ );
2490
+ const resolution = reference2 ? resolveReference(snapshot, reference2) : null;
2491
+ const parameterNames = call.kind === "constructor" ? constructorParameterNames(resolution?.staticType) : resolution?.symbol?.parameters?.map((parameter4) => parameter4.name);
2490
2492
  if (!parameterNames) continue;
2491
2493
  for (let index = 0; index < call.argumentRanges.length; index++) {
2492
2494
  const argumentRange = call.argumentRanges[index];
2493
2495
  const parameterName = parameterNames[index];
2494
2496
  if (!argumentRange || !parameterName) continue;
2497
+ if (obviousParameterName(snapshot, argumentRange, parameterName)) {
2498
+ continue;
2499
+ }
2495
2500
  const position = firstNonWhitespacePosition(snapshot, argumentRange);
2496
2501
  if (range2 && !positionInRange(position, range2)) continue;
2497
2502
  hints.push({
@@ -2502,8 +2507,59 @@ function inlayHints(snapshot, range2) {
2502
2507
  });
2503
2508
  }
2504
2509
  }
2510
+ for (const local of snapshot.parsed.locals) {
2511
+ if (!local.inferred || !local.contextualKeywordRange) continue;
2512
+ const type = resolveDeclaredType(local, snapshot);
2513
+ if (type.kind === "primitive" && type.name === "unknown") continue;
2514
+ const position = local.nameRange.end;
2515
+ if (range2 && !positionInRange(position, range2)) continue;
2516
+ hints.push({
2517
+ position,
2518
+ label: `: ${formatType(type, snapshot.project)}`,
2519
+ kind: "type",
2520
+ paddingLeft: false
2521
+ });
2522
+ }
2505
2523
  return hints;
2506
2524
  }
2525
+ function obviousParameterName(snapshot, argumentRange, parameterName) {
2526
+ const start = snapshot.source.offsetAt(argumentRange.start);
2527
+ const end = snapshot.source.offsetAt(argumentRange.end);
2528
+ const argument2 = snapshot.source.text.slice(start, end).trim();
2529
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(argument2) && normalizeHintName(argument2) === normalizeHintName(parameterName);
2530
+ }
2531
+ function normalizeHintName(name) {
2532
+ return name.replaceAll("_", "").toLocaleLowerCase();
2533
+ }
2534
+ function inferredTypeRefactorings(snapshot, range2) {
2535
+ return snapshot.parsed.locals.flatMap((local) => {
2536
+ if (!local.inferred || !local.contextualKeywordRange || !rangesIntersect(local.declarationRange, range2)) {
2537
+ return [];
2538
+ }
2539
+ const type = resolveDeclaredType(local, snapshot);
2540
+ if (type.kind === "primitive" && type.name === "unknown") return [];
2541
+ const formatted = formatType(type, snapshot.project);
2542
+ return [
2543
+ {
2544
+ title: `Use explicit type '${formatted}'`,
2545
+ kind: "refactor.rewrite",
2546
+ edit: {
2547
+ changes: {
2548
+ [snapshot.uri]: [
2549
+ { range: local.contextualKeywordRange, newText: formatted }
2550
+ ]
2551
+ }
2552
+ }
2553
+ }
2554
+ ];
2555
+ });
2556
+ }
2557
+ function rangesIntersect(left, right) {
2558
+ return positionCompare(left.start, right.end) <= 0 && positionCompare(right.start, left.end) <= 0;
2559
+ }
2560
+ function positionCompare(left, right) {
2561
+ return left.line - right.line || left.character - right.character;
2562
+ }
2507
2563
  function constructorParameterNames(type) {
2508
2564
  const declared = type?.declaredConstructors ?? [];
2509
2565
  if (declared.length > 0) {
@@ -17489,7 +17545,7 @@ var init_project_source_parser = __esm({
17489
17545
 
17490
17546
  // ../packages/neoscript-language/src/project-source-tokens.ts
17491
17547
  function rangeContains(range2, position) {
17492
- return positionCompare(range2.start, position) <= 0 && positionCompare(position, range2.end) <= 0;
17548
+ return positionCompare2(range2.start, position) <= 0 && positionCompare2(position, range2.end) <= 0;
17493
17549
  }
17494
17550
  function rangeSize(range2) {
17495
17551
  return (range2.end.line - range2.start.line) * 1e6 + range2.end.character - range2.start.character;
@@ -17617,9 +17673,9 @@ function tripleInterpolationEnd(text, start, limit) {
17617
17673
  return null;
17618
17674
  }
17619
17675
  function rangesEqual(left, right) {
17620
- return positionCompare(left.start, right.start) === 0 && positionCompare(left.end, right.end) === 0;
17676
+ return positionCompare2(left.start, right.start) === 0 && positionCompare2(left.end, right.end) === 0;
17621
17677
  }
17622
- function positionCompare(left, right) {
17678
+ function positionCompare2(left, right) {
17623
17679
  return left.line === right.line ? left.character - right.character : left.line - right.line;
17624
17680
  }
17625
17681
  var PROJECT_TOKEN_CACHE;
@@ -17724,7 +17780,7 @@ function scanAnnotation(tokens, atIndex) {
17724
17780
  };
17725
17781
  }
17726
17782
  function rangeWithin(outer, inner) {
17727
- return positionCompare(outer.start, inner.start) <= 0 && positionCompare(inner.end, outer.end) <= 0;
17783
+ return positionCompare2(outer.start, inner.start) <= 0 && positionCompare2(inner.end, outer.end) <= 0;
17728
17784
  }
17729
17785
  var init_project_source_registry = __esm({
17730
17786
  "../packages/neoscript-language/src/project-source-registry.ts"() {
@@ -17740,7 +17796,7 @@ var init_project_schema_contract_generated = __esm({
17740
17796
  "../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
17741
17797
  "use strict";
17742
17798
  PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
17743
- PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.12";
17799
+ PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.13";
17744
17800
  PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
17745
17801
  NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
17746
17802
  "recordFields": {
@@ -26473,7 +26529,8 @@ function collectDeclarationSymbols(uri, document, declaration, symbols, diagnost
26473
26529
  void 0,
26474
26530
  member.type.name,
26475
26531
  member.kind === "function",
26476
- member.docsText
26532
+ member.docsText,
26533
+ member.modifiers.includes("static")
26477
26534
  );
26478
26535
  if (member.kind === "function") {
26479
26536
  for (const parameter4 of member.parameters) {
@@ -26563,7 +26620,7 @@ function collectFlowSymbols(uri, content, ownerName, scopeRange, symbols, diagno
26563
26620
  }
26564
26621
  }
26565
26622
  }
26566
- function collectSymbol(uri, kind, name, range2, annotations, ownerName, symbols, diagnostics, scopeRange, detail, callable2, documentation) {
26623
+ function collectSymbol(uri, kind, name, range2, annotations, ownerName, symbols, diagnostics, scopeRange, detail, callable2, documentation, staticMember) {
26567
26624
  if (RESERVED_NAMES3.has(name)) {
26568
26625
  diagnostics.push({
26569
26626
  uri,
@@ -26593,6 +26650,7 @@ function collectSymbol(uri, kind, name, range2, annotations, ownerName, symbols,
26593
26650
  ...scopeRange ? { scopeRange } : {},
26594
26651
  ...detail ? { detail } : {},
26595
26652
  ...callable2 ? { callable: callable2 } : {},
26653
+ ...staticMember ? { static: true } : {},
26596
26654
  ...documentation ? { documentation } : {},
26597
26655
  location: { uri, range: range2 }
26598
26656
  });
@@ -27377,16 +27435,16 @@ function projectAnnotationNamesAt(analysis, document, position) {
27377
27435
  const containing = declarationContaining(source, position);
27378
27436
  if (containing?.kind === "enum") return ["id"];
27379
27437
  if (containing?.kind === "class" || containing?.kind === "interface") {
27380
- if (positionCompare(position, containing.nameRange.start) < 0) {
27438
+ if (positionCompare2(position, containing.nameRange.start) < 0) {
27381
27439
  return projectDeclarationAnnotationNames(containing);
27382
27440
  }
27383
27441
  const member = containing.members.find(
27384
- (candidate) => rangeContains(candidate.range, position) || positionCompare(position, candidate.range.start) <= 0
27442
+ (candidate) => rangeContains(candidate.range, position) || positionCompare2(position, candidate.range.start) <= 0
27385
27443
  );
27386
27444
  return projectMemberAnnotationNames(member);
27387
27445
  }
27388
27446
  const following = source.declarations.find(
27389
- (declaration) => positionCompare(position, declaration.range.start) <= 0
27447
+ (declaration) => positionCompare2(position, declaration.range.start) <= 0
27390
27448
  );
27391
27449
  if (following) return projectDeclarationAnnotationNames(following);
27392
27450
  return ["id"];
@@ -27728,7 +27786,10 @@ function sourceTypeAt(document, position) {
27728
27786
  }
27729
27787
  function projectMemberCompletions(analysis, document, position) {
27730
27788
  const tokens = projectTokens(document).filter(
27731
- (token) => token.kind !== "eof" && token.kind !== "comment" && positionCompare(token.range.start, position) <= 0
27789
+ (token) => token.kind !== "eof" && token.kind !== "comment" && // Auto-inserted/future punctuation at the cursor has not been authored
27790
+ // yet for completion purposes. Including a semicolon that starts at the
27791
+ // cursor makes `Device.|;` lose the dot it is completing.
27792
+ positionCompare2(token.range.start, position) < 0
27732
27793
  );
27733
27794
  let cursor = tokens.length - 1;
27734
27795
  const current = tokens[cursor];
@@ -27740,16 +27801,19 @@ function projectMemberCompletions(analysis, document, position) {
27740
27801
  if (!owner || owner.kind !== "identifier") return null;
27741
27802
  const resolvedOwner = projectSymbolAt(analysis, document, owner.range.start);
27742
27803
  if (!resolvedOwner) return null;
27743
- const ownerNames = /* @__PURE__ */ new Set();
27744
- const typeName = projectSymbolTypeName(resolvedOwner.symbol);
27745
- if (typeName) ownerNames.add(typeName);
27746
- if (resolvedOwner.symbol.kind === "global") {
27747
- ownerNames.add(resolvedOwner.symbol.name);
27804
+ const ownerNames = projectReceiverOwnerNames(analysis, resolvedOwner.symbol);
27805
+ if (ownerNames.length === 0) return null;
27806
+ const members = [];
27807
+ const seenNames = /* @__PURE__ */ new Set();
27808
+ for (const ownerName of ownerNames) {
27809
+ for (const symbol of analysis.symbols) {
27810
+ if (symbol.kind !== "member" && symbol.kind !== "graphChild" && symbol.kind !== "enumOption" || symbol.ownerName !== ownerName || !projectQualifiedSymbolMatchesReceiver(symbol, resolvedOwner.symbol) || seenNames.has(symbol.name)) {
27811
+ continue;
27812
+ }
27813
+ seenNames.add(symbol.name);
27814
+ members.push(symbol);
27815
+ }
27748
27816
  }
27749
- if (ownerNames.size === 0) return null;
27750
- const members = analysis.symbols.filter(
27751
- (symbol) => (symbol.kind === "member" || symbol.kind === "graphChild") && symbol.ownerName !== void 0 && ownerNames.has(symbol.ownerName)
27752
- );
27753
27817
  return members.length > 0 ? members : null;
27754
27818
  }
27755
27819
  function projectConstructorArgumentCompletions(analysis, document, position) {
@@ -27892,7 +27956,7 @@ function projectConstructionIndex(analysis) {
27892
27956
  }
27893
27957
  function projectDottedPathBefore(document, position) {
27894
27958
  const tokens = projectTokens(document).filter(
27895
- (token) => token.kind !== "eof" && token.kind !== "comment" && positionCompare(token.range.start, position) < 0
27959
+ (token) => token.kind !== "eof" && token.kind !== "comment" && positionCompare2(token.range.start, position) < 0
27896
27960
  );
27897
27961
  let cursor = tokens.length - 1;
27898
27962
  const current = tokens[cursor];
@@ -28019,7 +28083,7 @@ function projectGraphTargetCompletions(analysis, document, position) {
28019
28083
  const declaration = source ? declarationContaining(source, position) : void 0;
28020
28084
  if (declaration?.kind !== "class") return null;
28021
28085
  const member = declaration.members.filter(
28022
- (candidate) => positionCompare(candidate.range.start, position) <= 0
28086
+ (candidate) => positionCompare2(candidate.range.start, position) <= 0
28023
28087
  ).at(-1);
28024
28088
  if (member?.kind !== "field" || !member.flowInitializer) return null;
28025
28089
  return analysis.symbols.filter(
@@ -28347,6 +28411,9 @@ function projectInlayHints(analysis, document, range2) {
28347
28411
  if (!argumentToken || argumentToken.named) continue;
28348
28412
  const name = parameterNames[argument2];
28349
28413
  if (!name) continue;
28414
+ if (argumentToken.identifier && normalizeProjectHintName(argumentToken.identifier) === normalizeProjectHintName(name)) {
28415
+ continue;
28416
+ }
28350
28417
  if (range2 && !rangeContains(range2, argumentToken.start)) continue;
28351
28418
  hints.push({
28352
28419
  position: argumentToken.start,
@@ -28366,6 +28433,10 @@ function projectInlayHints(analysis, document, range2) {
28366
28433
  }
28367
28434
  return hints;
28368
28435
  }
28436
+ function projectInferredTypeRefactorings(analysis, document, range2) {
28437
+ const snapshot = projectBodySnapshotAt(analysis, document, range2.start) ?? projectBodySnapshotAt(analysis, document, range2.end);
28438
+ return snapshot ? inferredTypeRefactorings(snapshot, range2) : [];
28439
+ }
28369
28440
  function projectCallParameterNames(analysis, document, callee, beforeCallee) {
28370
28441
  if (callee.text === "Reference") return null;
28371
28442
  if (callee.text === "Pause") {
@@ -28412,7 +28483,8 @@ function projectCallArguments(tokens, openIndex) {
28412
28483
  if (depth === 0 && atArgumentStart) {
28413
28484
  result.push({
28414
28485
  start: token.range.start,
28415
- named: token.kind === "identifier" && tokens[index + 1]?.text === ":"
28486
+ named: token.kind === "identifier" && tokens[index + 1]?.text === ":",
28487
+ ...token.kind === "identifier" && (tokens[index + 1]?.text === "," || tokens[index + 1]?.text === ")") ? { identifier: token.text } : {}
28416
28488
  });
28417
28489
  atArgumentStart = false;
28418
28490
  }
@@ -28424,6 +28496,9 @@ function projectCallArguments(tokens, openIndex) {
28424
28496
  }
28425
28497
  return result;
28426
28498
  }
28499
+ function normalizeProjectHintName(name) {
28500
+ return name.replaceAll("_", "").toLocaleLowerCase();
28501
+ }
28427
28502
  function positionKey(position) {
28428
28503
  return `${position.line}:${position.character}`;
28429
28504
  }
@@ -28608,7 +28683,7 @@ function projectSemanticTokens(document, analysis) {
28608
28683
  );
28609
28684
  }
28610
28685
  return result.sort(
28611
- (left, right) => positionCompare(left.range.start, right.range.start)
28686
+ (left, right) => positionCompare2(left.range.start, right.range.start)
28612
28687
  );
28613
28688
  }
28614
28689
  function isProjectContextualKeyword(tokens, tokenIndex) {
@@ -28639,7 +28714,8 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
28639
28714
  (candidate) => candidate.start === token.start && candidate.end === token.end
28640
28715
  );
28641
28716
  const source = analysis.documents.get(document.uri);
28642
- if (source && sourceTypeAt(source, token.range.start) || sourceTokens[tokenIndex - 1]?.text === "new") {
28717
+ const typePosition = source && sourceTypeAt(source, token.range.start);
28718
+ if (typePosition || sourceTokens[tokenIndex - 1]?.text === "new") {
28643
28719
  const types = candidates.filter(
28644
28720
  (symbol) => symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter"
28645
28721
  );
@@ -28652,10 +28728,15 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
28652
28728
  );
28653
28729
  if (scoped.length > 0) return { token, symbol: scoped[0] };
28654
28730
  const visibleCandidates = candidates.filter((symbol) => !symbol.scopeRange);
28655
- if (visibleCandidates.length === 1) {
28656
- return { token, symbol: visibleCandidates[0] };
28657
- }
28658
28731
  if (visibleCandidates.length === 0) return null;
28732
+ const contextualEnum = contextualProjectEnumOptionSymbol(
28733
+ analysis,
28734
+ document,
28735
+ token,
28736
+ visibleCandidates,
28737
+ source
28738
+ );
28739
+ if (contextualEnum) return { token, symbol: contextualEnum };
28659
28740
  if (sourceTokens[tokenIndex + 1]?.text === "=" && sourceTokens[tokenIndex + 2]?.text !== "=") {
28660
28741
  const constructed = constructionMemberSymbol(
28661
28742
  analysis,
@@ -28666,7 +28747,7 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
28666
28747
  if (constructed) return { token, symbol: constructed };
28667
28748
  }
28668
28749
  const owner = source ? declarationContaining(source, token.range.start)?.name : void 0;
28669
- if (owner) {
28750
+ if (owner && sourceTokens[tokenIndex - 1]?.text !== ".") {
28670
28751
  const owned = visibleCandidates.filter(
28671
28752
  (symbol) => symbol.ownerName === owner
28672
28753
  );
@@ -28680,24 +28761,100 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
28680
28761
  dotOwner.range.start,
28681
28762
  index
28682
28763
  );
28683
- const ownerNames = /* @__PURE__ */ new Set();
28684
- if (resolvedOwner) {
28685
- const typeName = projectSymbolTypeName(resolvedOwner.symbol);
28686
- if (typeName) ownerNames.add(typeName);
28687
- if (resolvedOwner.symbol.kind === "global") {
28688
- ownerNames.add(resolvedOwner.symbol.name);
28689
- }
28690
- } else {
28691
- ownerNames.add(dotOwner.text);
28692
- }
28764
+ const ownerNames = resolvedOwner ? projectReceiverOwnerNames(analysis, resolvedOwner.symbol) : [dotOwner.text];
28693
28765
  const qualified = visibleCandidates.filter(
28694
- (symbol) => symbol.ownerName !== void 0 && ownerNames.has(symbol.ownerName)
28766
+ (symbol) => symbol.ownerName !== void 0 && ownerNames.includes(symbol.ownerName) && (resolvedOwner === null || projectQualifiedSymbolMatchesReceiver(symbol, resolvedOwner.symbol))
28695
28767
  );
28696
- if (qualified.length === 1) return { token, symbol: qualified[0] };
28768
+ for (const ownerName of ownerNames) {
28769
+ const nearest = qualified.filter(
28770
+ (symbol) => symbol.ownerName === ownerName
28771
+ );
28772
+ if (nearest.length === 1) return { token, symbol: nearest[0] };
28773
+ if (nearest.length > 1) return null;
28774
+ }
28775
+ return null;
28697
28776
  }
28698
- const projectLevel = visibleCandidates.filter((symbol) => !symbol.ownerName);
28777
+ const values = visibleCandidates.filter(
28778
+ (symbol) => !isProjectTypeSymbol(symbol)
28779
+ );
28780
+ if (values.length === 1) return { token, symbol: values[0] };
28781
+ const projectLevel = (values.length > 0 ? values : visibleCandidates).filter(
28782
+ (symbol) => !symbol.ownerName
28783
+ );
28699
28784
  return projectLevel.length === 1 ? { token, symbol: projectLevel[0] } : null;
28700
28785
  }
28786
+ function isProjectTypeSymbol(symbol) {
28787
+ return symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter";
28788
+ }
28789
+ function projectQualifiedSymbolMatchesReceiver(symbol, receiver) {
28790
+ if (isProjectTypeSymbol(receiver)) {
28791
+ if (receiver.kind === "enum") return symbol.kind === "enumOption";
28792
+ return symbol.kind === "member" && symbol.static === true;
28793
+ }
28794
+ if (symbol.kind === "enumOption") return false;
28795
+ return symbol.kind !== "member" || symbol.static !== true;
28796
+ }
28797
+ function projectReceiverOwnerNames(analysis, receiver) {
28798
+ const result = [];
28799
+ const visitedTypes = /* @__PURE__ */ new Set();
28800
+ const appendTypeAndBases = (typeName2) => {
28801
+ if (visitedTypes.has(typeName2)) return;
28802
+ visitedTypes.add(typeName2);
28803
+ if (!result.includes(typeName2)) result.push(typeName2);
28804
+ const declaration = findTypeDeclaration(analysis, typeName2);
28805
+ if (declaration?.kind !== "class" && declaration?.kind !== "interface") {
28806
+ return;
28807
+ }
28808
+ for (const base of declaration.baseTypes) {
28809
+ const resolved = findTypeDeclaration(analysis, base.name);
28810
+ if (resolved?.kind === "class" || resolved?.kind === "interface") {
28811
+ appendTypeAndBases(base.name);
28812
+ }
28813
+ }
28814
+ };
28815
+ if (receiver.kind === "global") {
28816
+ result.push(receiver.name);
28817
+ }
28818
+ const typeName = projectSymbolTypeName(receiver);
28819
+ if (typeName) appendTypeAndBases(typeName);
28820
+ return result;
28821
+ }
28822
+ function contextualProjectEnumOptionSymbol(analysis, document, token, candidates, source) {
28823
+ if (!isContextualDot(document.text, token.start)) return null;
28824
+ const expectedTypeName = constructionSiteAt(analysis, document, token.range.start)?.expectedTypeName ?? (source ? parameterDefaultTypeNameAt(source, token.range.start) : null);
28825
+ if (!expectedTypeName) return null;
28826
+ const options = candidates.filter(
28827
+ (symbol) => symbol.kind === "enumOption" && symbol.ownerName === expectedTypeName
28828
+ );
28829
+ return options.length === 1 ? options[0] : null;
28830
+ }
28831
+ function parameterDefaultTypeNameAt(document, position) {
28832
+ const fromParameters = (parameters) => {
28833
+ const parameter4 = parameters?.find(
28834
+ (candidate) => candidate.defaultValue && rangeContains(candidate.defaultValue.range, position)
28835
+ );
28836
+ return parameter4?.type.name ?? null;
28837
+ };
28838
+ for (const declaration of document.declarations) {
28839
+ if (declaration.kind !== "class" && declaration.kind !== "interface") {
28840
+ continue;
28841
+ }
28842
+ if (declaration.kind === "class") {
28843
+ const header = fromParameters(declaration.headerParameters);
28844
+ if (header) return header;
28845
+ for (const constructor2 of declaration.constructors) {
28846
+ const constructorParameter = fromParameters(constructor2.parameters);
28847
+ if (constructorParameter) return constructorParameter;
28848
+ }
28849
+ }
28850
+ for (const member of declaration.members) {
28851
+ if (member.kind !== "function") continue;
28852
+ const functionParameter = fromParameters(member.parameters);
28853
+ if (functionParameter) return functionParameter;
28854
+ }
28855
+ }
28856
+ return null;
28857
+ }
28701
28858
  function constructionMemberSymbol(analysis, document, token, candidates) {
28702
28859
  const site = constructionSiteAt(analysis, document, token.range.start);
28703
28860
  let current = site?.enclosingTypeName ?? null;
@@ -28734,7 +28891,7 @@ function projectSymbolTypeName(symbol) {
28734
28891
  }
28735
28892
  function declarationContaining(document, position) {
28736
28893
  return document.declarations.find(
28737
- (declaration) => positionCompare(declaration.range.start, position) <= 0 && positionCompare(position, declaration.range.end) <= 0
28894
+ (declaration) => positionCompare2(declaration.range.start, position) <= 0 && positionCompare2(position, declaration.range.end) <= 0
28738
28895
  );
28739
28896
  }
28740
28897
  function sameProjectSymbol(left, right) {
@@ -28746,14 +28903,14 @@ function sameProjectSymbol(left, right) {
28746
28903
  }
28747
28904
  function tokensBeforePosition(text, position) {
28748
28905
  return lex(text).tokens.filter(
28749
- (token) => token.kind !== "comment" && token.kind !== "eof" && positionCompare(token.range.start, position) < 0
28906
+ (token) => token.kind !== "comment" && token.kind !== "eof" && positionCompare2(token.range.start, position) < 0
28750
28907
  );
28751
28908
  }
28752
28909
  function activeCallOpenIndex(tokens, position) {
28753
28910
  let closeDepth = 0;
28754
28911
  for (let index = tokens.length - 1; index >= 0; index--) {
28755
28912
  const token = tokens[index];
28756
- if (!token || positionCompare(token.range.start, position) > 0) continue;
28913
+ if (!token || positionCompare2(token.range.start, position) > 0) continue;
28757
28914
  if (token.text === ")") {
28758
28915
  closeDepth++;
28759
28916
  continue;
@@ -28772,7 +28929,7 @@ function activeCallParameter(tokens, openIndex, position) {
28772
28929
  let parameter4 = 0;
28773
28930
  for (let index = openIndex + 1; index < tokens.length; index++) {
28774
28931
  const token = tokens[index];
28775
- if (!token || positionCompare(token.range.start, position) >= 0) break;
28932
+ if (!token || positionCompare2(token.range.start, position) >= 0) break;
28776
28933
  if (token.text === "(" || token.text === "[" || token.text === "{") {
28777
28934
  depth++;
28778
28935
  continue;
@@ -28855,7 +29012,7 @@ function constructionSiteAt(analysis, document, position) {
28855
29012
  const root = initializerRootAt(analysis, document, position);
28856
29013
  if (!root) return null;
28857
29014
  const tokens = projectTokens(document).filter(
28858
- (token) => token.kind !== "comment" && token.kind !== "eof" && rangeContains(root.range, token.range.start) && positionCompare(token.range.start, position) < 0
29015
+ (token) => token.kind !== "comment" && token.kind !== "eof" && rangeContains(root.range, token.range.start) && positionCompare2(token.range.start, position) < 0
28859
29016
  );
28860
29017
  const stack = [];
28861
29018
  const expectedType = () => {
@@ -30601,15 +30758,21 @@ function projectSchemaManifest(input, options = {}) {
30601
30758
  "ProjectSchemaManifest.interfaces"
30602
30759
  );
30603
30760
  const genericNames = /* @__PURE__ */ new Map();
30761
+ const genericDeclarations = /* @__PURE__ */ new Map();
30762
+ const genericOwnerClassIds = /* @__PURE__ */ new Map();
30604
30763
  for (const schemaClass2 of classes) {
30764
+ const classId = string2(schemaClass2.id, "schemaClass.id");
30605
30765
  for (const parameter4 of records(
30606
30766
  schemaClass2.genericParameters ?? [],
30607
30767
  "schemaClass.genericParameters"
30608
30768
  )) {
30769
+ const parameterId = string2(parameter4.id, "genericParameter.id");
30609
30770
  genericNames.set(
30610
- string2(parameter4.id, "genericParameter.id"),
30771
+ parameterId,
30611
30772
  string2(parameter4.name, "genericParameter.name")
30612
30773
  );
30774
+ genericDeclarations.set(parameterId, parameter4);
30775
+ genericOwnerClassIds.set(parameterId, classId);
30613
30776
  }
30614
30777
  }
30615
30778
  const rootMemberIds2 = options.rootMemberIds ?? inferRootMemberIds(members);
@@ -30620,6 +30783,8 @@ function projectSchemaManifest(input, options = {}) {
30620
30783
  interfaces: interfaceById,
30621
30784
  enums: indexById(enums, "ProjectSchemaManifest.enums"),
30622
30785
  genericNames,
30786
+ genericDeclarations,
30787
+ genericOwnerClassIds,
30623
30788
  effectiveWritabilityByMemberId: effectiveMemberWritability(
30624
30789
  members,
30625
30790
  classes,
@@ -30993,7 +31158,7 @@ function schemaClass(value, environment, field) {
30993
31158
  return {
30994
31159
  id: parameterId,
30995
31160
  name,
30996
- type: { kind: "typeParameter", id: parameterId, name },
31161
+ type: typeParameter(parameterId, environment, false),
30997
31162
  ...spanAndSelectionLocations(
30998
31163
  parameter4.source,
30999
31164
  parameter4.selectionSpan ?? parameter4.source,
@@ -31982,14 +32147,73 @@ function manifestPrimitive(kind) {
31982
32147
  return null;
31983
32148
  }
31984
32149
  }
31985
- function typeParameter(id2, environment, nullable) {
32150
+ function typeParameter(id2, environment, nullable, visiting = /* @__PURE__ */ new Set()) {
32151
+ const declaration = environment.genericDeclarations.get(id2);
32152
+ const constraint = declaration?.constraint;
32153
+ const next = new Set(visiting).add(id2);
31986
32154
  return {
31987
32155
  kind: "typeParameter",
31988
32156
  id: id2,
31989
32157
  name: environment.genericNames.get(id2) ?? id2,
32158
+ ...environment.genericOwnerClassIds.has(id2) ? { ownerClassId: environment.genericOwnerClassIds.get(id2) } : {},
32159
+ ...visiting.has(id2) || constraint === void 0 || constraint === null ? {} : {
32160
+ constraint: genericConstraintType(
32161
+ constraint,
32162
+ environment,
32163
+ next,
32164
+ `generic parameter ${id2}.constraint`
32165
+ )
32166
+ },
31990
32167
  nullable
31991
32168
  };
31992
32169
  }
32170
+ function genericConstraintType(value, environment, visiting, field) {
32171
+ const constraint = record2(value, field);
32172
+ if (constraint.kind === "enum") {
32173
+ return {
32174
+ kind: "named",
32175
+ typeId: string2(constraint.enumId, `${field}.enumId`),
32176
+ nullable: false
32177
+ };
32178
+ }
32179
+ if (constraint.kind !== "class") {
32180
+ throw new Error(`${field}.kind must be "class" or "enum".`);
32181
+ }
32182
+ const classId = string2(constraint.classId, `${field}.classId`);
32183
+ const target = environment.classes.get(classId);
32184
+ const parameters = target ? records(target.genericParameters ?? [], `${field}.genericParameters`) : [];
32185
+ const bindings = optionalRecord(constraint.classArguments) ?? {};
32186
+ const typeArguments = parameters.flatMap((parameter4) => {
32187
+ const parameterId = string2(parameter4.id, `${field}.genericParameter.id`);
32188
+ const binding = optionalRecord(bindings[parameterId]);
32189
+ if (binding?.kind === "generic" && typeof binding.genericParamId === "string") {
32190
+ return [
32191
+ typeParameter(binding.genericParamId, environment, false, visiting)
32192
+ ];
32193
+ }
32194
+ if (binding?.kind === "member" && typeof binding.memberId === "string") {
32195
+ const member = environment.members.get(binding.memberId);
32196
+ return member ? [
32197
+ {
32198
+ ...memberType(
32199
+ member,
32200
+ environment,
32201
+ /* @__PURE__ */ new Set(),
32202
+ `${field}.classArguments.${parameterId}`
32203
+ ),
32204
+ nullable: false
32205
+ }
32206
+ ] : [];
32207
+ }
32208
+ return [];
32209
+ });
32210
+ return {
32211
+ kind: "named",
32212
+ typeId: classId,
32213
+ nullable: false,
32214
+ ...typeArguments.length === parameters.length && typeArguments.length > 0 ? { typeArguments } : {}
32215
+ };
32216
+ }
31993
32217
  function primitive(name, nullable) {
31994
32218
  return { kind: "primitive", name, nullable };
31995
32219
  }
@@ -32083,6 +32307,154 @@ var init_project_schema_manifest = __esm({
32083
32307
  }
32084
32308
  });
32085
32309
 
32310
+ // ../packages/neoscript-language/src/spelling-diagnostics.ts
32311
+ function enhanceSpellingDiagnostics(document, diagnostics, completionAt) {
32312
+ return diagnostics.map((diagnostic) => {
32313
+ const misspelling = diagnosticMisspelling(diagnostic);
32314
+ if (!misspelling) return diagnostic;
32315
+ const token = diagnosticIdentifierToken(
32316
+ document,
32317
+ diagnostic,
32318
+ misspelling.name
32319
+ );
32320
+ if (!token) return diagnostic;
32321
+ const candidates = spellingCandidates(
32322
+ misspelling,
32323
+ completionAt(token.range.start)
32324
+ );
32325
+ if (candidates.length === 0) return diagnostic;
32326
+ return {
32327
+ ...diagnostic,
32328
+ message: `${diagnostic.message} ${didYouMean(candidates)}`,
32329
+ suggestions: candidates
32330
+ };
32331
+ });
32332
+ }
32333
+ function spellingQuickFixes(document, diagnostic) {
32334
+ const misspelling = diagnosticMisspelling(diagnostic);
32335
+ if (!misspelling || !diagnostic.suggestions) return [];
32336
+ const token = diagnosticIdentifierToken(
32337
+ document,
32338
+ diagnostic,
32339
+ misspelling.name
32340
+ );
32341
+ if (!token) return [];
32342
+ return diagnostic.suggestions.filter((suggestion) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(suggestion)).map((suggestion, index) => ({
32343
+ title: `Change '${misspelling.name}' to '${suggestion}'`,
32344
+ kind: "quickfix",
32345
+ diagnostics: [diagnostic],
32346
+ edit: {
32347
+ changes: {
32348
+ [document.uri]: [{ range: token.range, newText: suggestion }]
32349
+ }
32350
+ },
32351
+ preferred: index === 0
32352
+ }));
32353
+ }
32354
+ function diagnosticMisspelling(diagnostic) {
32355
+ if (/to initialize\b/.test(diagnostic.message)) return null;
32356
+ const unknown = /Unknown (identifier|function) '([^']+)'/.exec(
32357
+ diagnostic.message
32358
+ );
32359
+ if (unknown?.[2]) {
32360
+ return {
32361
+ name: unknown[2],
32362
+ kind: unknown[1] === "function" ? "callable" : "value"
32363
+ };
32364
+ }
32365
+ const member = /has no (?:static )?(?:callable )?member '([^']+)'/.exec(
32366
+ diagnostic.message
32367
+ );
32368
+ if (!member?.[1]) return null;
32369
+ return {
32370
+ name: member[1],
32371
+ kind: /callable member/.test(member[0]) ? "callable" : "member"
32372
+ };
32373
+ }
32374
+ function diagnosticIdentifierToken(document, diagnostic, name) {
32375
+ const candidates = projectTokens(document).filter(
32376
+ (token) => (token.kind === "identifier" || token.kind === "type") && token.text === name
32377
+ );
32378
+ if (candidates.length === 0) return null;
32379
+ const target = positionScore(diagnostic.range.start);
32380
+ return candidates.sort(
32381
+ (left, right) => Math.abs(positionScore(left.range.start) - target) - Math.abs(positionScore(right.range.start) - target)
32382
+ )[0] ?? null;
32383
+ }
32384
+ function positionScore(position) {
32385
+ return position.line * 1e6 + position.character;
32386
+ }
32387
+ function spellingCandidates(misspelling, items) {
32388
+ const allowedKinds = misspelling.kind === "callable" ? /* @__PURE__ */ new Set(["method", "function"]) : misspelling.kind === "member" ? /* @__PURE__ */ new Set(["field", "property", "method", "function", "enumMember"]) : /* @__PURE__ */ new Set([
32389
+ "variable",
32390
+ "parameter",
32391
+ "field",
32392
+ "property",
32393
+ "enumMember",
32394
+ "value"
32395
+ ]);
32396
+ const original = misspelling.name.toLocaleLowerCase();
32397
+ const maximumDistance = original.length <= 4 ? 1 : original.length <= 8 ? 2 : 3;
32398
+ const ranked = /* @__PURE__ */ new Map();
32399
+ for (const item of items) {
32400
+ if (!allowedKinds.has(item.kind)) continue;
32401
+ const candidate = item.label.replace(/^\./, "");
32402
+ if (candidate.toLocaleLowerCase() === original) continue;
32403
+ const distance = damerauLevenshtein(
32404
+ original,
32405
+ candidate.toLocaleLowerCase()
32406
+ );
32407
+ if (distance > maximumDistance) continue;
32408
+ const prior = ranked.get(candidate);
32409
+ if (prior === void 0 || distance < prior)
32410
+ ranked.set(candidate, distance);
32411
+ }
32412
+ return [...ranked].sort(
32413
+ ([left, leftDistance], [right, rightDistance]) => leftDistance - rightDistance || left.localeCompare(right)
32414
+ ).slice(0, 3).map(([candidate]) => candidate);
32415
+ }
32416
+ function damerauLevenshtein(left, right) {
32417
+ const rows = left.length + 1;
32418
+ const columns = right.length + 1;
32419
+ const distance = Array.from(
32420
+ { length: rows },
32421
+ () => Array(columns).fill(0)
32422
+ );
32423
+ for (let row = 0; row < rows; row++) distance[row][0] = row;
32424
+ for (let column = 0; column < columns; column++) {
32425
+ distance[0][column] = column;
32426
+ }
32427
+ for (let row = 1; row < rows; row++) {
32428
+ for (let column = 1; column < columns; column++) {
32429
+ const substitution = left[row - 1] === right[column - 1] ? 0 : 1;
32430
+ distance[row][column] = Math.min(
32431
+ distance[row - 1][column] + 1,
32432
+ distance[row][column - 1] + 1,
32433
+ distance[row - 1][column - 1] + substitution
32434
+ );
32435
+ if (row > 1 && column > 1 && left[row - 1] === right[column - 2] && left[row - 2] === right[column - 1]) {
32436
+ distance[row][column] = Math.min(
32437
+ distance[row][column],
32438
+ distance[row - 2][column - 2] + 1
32439
+ );
32440
+ }
32441
+ }
32442
+ }
32443
+ return distance[left.length][right.length];
32444
+ }
32445
+ function didYouMean(candidates) {
32446
+ const quoted = candidates.map((candidate) => `'${candidate}'`);
32447
+ if (quoted.length === 1) return `Did you mean ${quoted[0]}?`;
32448
+ if (quoted.length === 2) return `Did you mean ${quoted[0]} or ${quoted[1]}?`;
32449
+ return `Did you mean ${quoted.slice(0, -1).join(", ")}, or ${quoted.at(-1)}?`;
32450
+ }
32451
+ var init_spelling_diagnostics = __esm({
32452
+ "../packages/neoscript-language/src/spelling-diagnostics.ts"() {
32453
+ "use strict";
32454
+ init_project_source_tokens();
32455
+ }
32456
+ });
32457
+
32086
32458
  // ../packages/neoscript-language/src/service.ts
32087
32459
  function createNeoScriptLanguageService() {
32088
32460
  return new LanguageService();
@@ -32177,6 +32549,7 @@ var init_service = __esm({
32177
32549
  init_project_source_language_features();
32178
32550
  init_project_source_tokens();
32179
32551
  init_quick_fixes();
32552
+ init_spelling_diagnostics();
32180
32553
  init_syntax();
32181
32554
  init_test_prelude();
32182
32555
  LanguageService = class {
@@ -32266,14 +32639,17 @@ var init_service = __esm({
32266
32639
  if (isProjectDocument(state.document, state.context)) {
32267
32640
  const project = this.projectAnalysis();
32268
32641
  return {
32269
- diagnostics: projectDiagnostics(project, uri),
32642
+ diagnostics: this.enhanceDiagnostics(
32643
+ state,
32644
+ projectDiagnostics(project, uri)
32645
+ ),
32270
32646
  symbols: projectDocumentSymbols(state.document, project),
32271
32647
  semanticTokens: projectSemanticTokens(state.document, project)
32272
32648
  };
32273
32649
  }
32274
32650
  const snapshot = this.scriptSnapshot(state);
32275
32651
  return {
32276
- diagnostics: finalizeDiagnostics(uri, [
32652
+ diagnostics: this.enhanceDiagnostics(state, [
32277
32653
  ...snapshot.parsed.diagnostics,
32278
32654
  ...semanticDiagnostics(snapshot)
32279
32655
  ]),
@@ -32286,7 +32662,10 @@ var init_service = __esm({
32286
32662
  if (signal?.aborted) return [];
32287
32663
  const generation = ++state.validationGeneration;
32288
32664
  if (isProjectDocument(state.document, state.context)) {
32289
- const diagnostics = projectDiagnostics(this.projectAnalysis(), uri);
32665
+ const diagnostics = this.enhanceDiagnostics(
32666
+ state,
32667
+ projectDiagnostics(this.projectAnalysis(), uri)
32668
+ );
32290
32669
  if (signal?.aborted) return [];
32291
32670
  const current2 = this.documents.get(uri);
32292
32671
  if (!current2 || current2.validationGeneration !== generation) return [];
@@ -32304,7 +32683,7 @@ var init_service = __esm({
32304
32683
  if (signal?.aborted) return [];
32305
32684
  const current = this.documents.get(uri);
32306
32685
  if (!current || current.validationGeneration !== generation) return [];
32307
- return finalizeDiagnostics(uri, [
32686
+ return this.enhanceDiagnostics(state, [
32308
32687
  ...snapshot.parsed.diagnostics,
32309
32688
  ...strictDiagnostics
32310
32689
  ]);
@@ -32417,10 +32796,15 @@ var init_service = __esm({
32417
32796
  ...isProjectDocument(state.document, state.context) ? {} : { kind: options?.kind ?? state.context.kind }
32418
32797
  });
32419
32798
  }
32420
- codeActions(uri, diagnostics) {
32799
+ codeActions(uri, diagnostics, range2) {
32421
32800
  const state = this.requireState(uri);
32422
32801
  const actions = [];
32423
32802
  const project = isProjectDocument(state.document, state.context) ? this.projectAnalysis() : null;
32803
+ if (range2) {
32804
+ actions.push(
32805
+ ...project ? projectInferredTypeRefactorings(project, state.document, range2) : inferredTypeRefactorings(this.scriptSnapshot(state), range2)
32806
+ );
32807
+ }
32424
32808
  for (const diagnostic of finalizeDiagnostics(uri, diagnostics)) {
32425
32809
  if (project) {
32426
32810
  actions.push(
@@ -32430,6 +32814,7 @@ var init_service = __esm({
32430
32814
  ...projectConstructionQuickFixes(project, state.document, diagnostic)
32431
32815
  );
32432
32816
  }
32817
+ actions.push(...spellingQuickFixes(state.document, diagnostic));
32433
32818
  const edit = quickFixFor(state.document, diagnostic);
32434
32819
  if (!edit) continue;
32435
32820
  actions.push({
@@ -32442,6 +32827,17 @@ var init_service = __esm({
32442
32827
  }
32443
32828
  return deduplicateCodeActions(actions);
32444
32829
  }
32830
+ /** Adds conservative, completion-backed spelling suggestions to diagnostics. */
32831
+ enhanceDiagnostics(state, diagnostics) {
32832
+ return finalizeDiagnostics(
32833
+ state.document.uri,
32834
+ enhanceSpellingDiagnostics(
32835
+ state.document,
32836
+ diagnostics,
32837
+ (position) => this.complete(state.document.uri, position).items
32838
+ )
32839
+ );
32840
+ }
32445
32841
  projectAnalysis() {
32446
32842
  if (this.cachedProjectAnalysis?.generation === this.projectGeneration) {
32447
32843
  return this.cachedProjectAnalysis.analysis;
@@ -34344,6 +34740,16 @@ function inferMemberOwners(classes, members) {
34344
34740
  schemaClass2.recordId,
34345
34741
  set
34346
34742
  );
34743
+ if (Array.isArray(schemaClass2.data.genericParams)) {
34744
+ for (const parameterValue of schemaClass2.data.genericParams) {
34745
+ if (!isRecord2(parameterValue)) continue;
34746
+ const parameterId = parameterValue.id;
34747
+ const constraint = parameterValue.constraint;
34748
+ if (typeof parameterId !== "string" || !isRecord2(constraint)) continue;
34749
+ if (constraint.kind !== "class") continue;
34750
+ collectGenericOwners(constraint.classArguments, parameterId, set);
34751
+ }
34752
+ }
34347
34753
  }
34348
34754
  for (const [memberId, member] of members) {
34349
34755
  if (typeof member.entryMemberId === "string") {
@@ -37744,8 +38150,19 @@ function assertGenericParameter(value, path) {
37744
38150
  if (parameter4.constraint === null) return;
37745
38151
  const constraint = requireRecord(parameter4.constraint, `${path}.constraint`);
37746
38152
  if (constraint.kind === "class") {
37747
- knownKeys(constraint, `${path}.constraint`, ["kind", "classId"]);
38153
+ knownKeysWithOptional(
38154
+ constraint,
38155
+ `${path}.constraint`,
38156
+ ["kind", "classId"],
38157
+ ["classArguments"]
38158
+ );
37748
38159
  nonEmptyString(constraint.classId, `${path}.constraint.classId`);
38160
+ if (constraint.classArguments !== void 0 && constraint.classArguments !== null) {
38161
+ assertGenericBindingRecord(
38162
+ constraint.classArguments,
38163
+ `${path}.constraint.classArguments`
38164
+ );
38165
+ }
37749
38166
  return;
37750
38167
  }
37751
38168
  if (constraint.kind === "enum") {
@@ -41483,7 +41900,9 @@ function isGenericParamConstraint(value) {
41483
41900
  if (v.kind === "class") {
41484
41901
  if (typeof v.classId !== "string") return false;
41485
41902
  if (v.classId.length === 0) return false;
41486
- return v.enumId === void 0;
41903
+ if (v.enumId !== void 0) return false;
41904
+ const argumentsValue = v.classArguments;
41905
+ return argumentsValue === void 0 || argumentsValue === null || isGenericBindingsRecord(argumentsValue);
41487
41906
  }
41488
41907
  if (v.kind === "enum") {
41489
41908
  if (typeof v.enumId !== "string") return false;
@@ -49253,11 +49672,7 @@ function emitClass(context, schemaClass2, memberIds) {
49253
49672
  const modifier = schemaClass2.isSealed ? "sealed " : schemaClass2.declarationModifier === "abstract" ? "abstract " : "";
49254
49673
  const generics = schemaClass2.genericParameters.length ? `<
49255
49674
  ${schemaClass2.genericParameters.map((parameter4) => {
49256
- const constraint = parameter4.constraint ? ` extends ${parameter4.constraint.kind === "class" ? required(
49257
- context.classes,
49258
- parameter4.constraint.classId,
49259
- "class"
49260
- ).name : required(context.enums, parameter4.constraint.enumId, "enum").name}` : "";
49675
+ const constraint = parameter4.constraint ? ` extends ${renderGenericConstraint(context, parameter4.constraint)}` : "";
49261
49676
  return ` ${id(parameter4.id)} ${parameter4.name}${constraint}`;
49262
49677
  }).join(",\n")}
49263
49678
  >` : "";
@@ -49331,6 +49746,31 @@ ${members.join("\n\n")}
49331
49746
  }
49332
49747
  `;
49333
49748
  }
49749
+ function renderGenericConstraint(context, constraint) {
49750
+ if (constraint.kind === "enum") {
49751
+ return required(context.enums, constraint.enumId, "enum").name;
49752
+ }
49753
+ const target = required(context.classes, constraint.classId, "class");
49754
+ if (target.genericParameters.length === 0) return target.name;
49755
+ const bindings = constraint.classArguments;
49756
+ if (bindings === void 0 || bindings === null) return target.name;
49757
+ const argumentsValue = target.genericParameters.map((parameter4) => {
49758
+ const binding = bindings[parameter4.id];
49759
+ if (binding === void 0) {
49760
+ throw new Error(
49761
+ `Generic constraint ${target.name} is missing its argument for ${parameter4.name}.`
49762
+ );
49763
+ }
49764
+ if (binding.kind === "generic") {
49765
+ return genericName(context, binding.genericParamId);
49766
+ }
49767
+ return renderMemberType(
49768
+ context,
49769
+ required(context.members, binding.memberId, "generic constraint binding")
49770
+ ).replace(/\?$/u, "");
49771
+ });
49772
+ return `${target.name}<${argumentsValue.join(", ")}>`;
49773
+ }
49334
49774
  function baseConstruction(requiredConstructor) {
49335
49775
  if (requiredConstructor === void 0) return "";
49336
49776
  const args = requiredConstructor.baseArguments ?? [];
@@ -55810,7 +56250,15 @@ function lowerClass(context, declaration) {
55810
56250
  return {
55811
56251
  id: parameterId,
55812
56252
  name: parameter4.name,
55813
- constraint: parameter4.constraint ? genericConstraint(context, parameter4.constraint) : null,
56253
+ constraint: parameter4.constraint ? genericConstraint(
56254
+ context,
56255
+ declaration,
56256
+ parameterId,
56257
+ parameter4.constraint,
56258
+ base?.genericParameters.find(
56259
+ (candidate) => candidate.id === parameterId
56260
+ )?.constraint
56261
+ ) : null,
55814
56262
  source: span(parameter4.identity),
55815
56263
  selectionSpan: span(parameter4.identity)
55816
56264
  };
@@ -57761,9 +58209,22 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
57761
58209
  )
57762
58210
  );
57763
58211
  }
57764
- function genericConstraint(context, type) {
58212
+ function genericConstraint(context, ownerClass, parameterId, type, baseConstraint) {
57765
58213
  const classId = context.classIdsByName.get(type.name);
57766
- if (classId) return { kind: "class", classId };
58214
+ if (classId) {
58215
+ const classArguments2 = type.arguments.length === 0 ? void 0 : lowerClassArguments(
58216
+ context,
58217
+ ownerClass,
58218
+ parameterId,
58219
+ type,
58220
+ baseConstraint?.kind === "class" ? baseConstraint.classArguments ?? void 0 : void 0
58221
+ );
58222
+ return {
58223
+ kind: "class",
58224
+ classId,
58225
+ ...classArguments2 === void 0 ? {} : { classArguments: classArguments2 }
58226
+ };
58227
+ }
57767
58228
  return {
57768
58229
  kind: "enum",
57769
58230
  enumId: requiredName2(context.enumIdsByName, type.name, "enum")
@@ -58669,18 +59130,12 @@ function classToLanguageType(schemaClass2, context) {
58669
59130
  typeParameters: schemaClass2.genericParams.map((parameter4) => ({
58670
59131
  id: parameter4.id,
58671
59132
  name: parameter4.name,
58672
- type: {
58673
- kind: "typeParameter",
58674
- id: parameter4.id,
58675
- name: parameter4.name,
58676
- ownerClassId: schemaClass2.id,
58677
- ...parameter4.constraint === void 0 || parameter4.constraint === null ? {} : {
58678
- constraint: namedType(
58679
- parameter4.constraint.kind === "class" ? parameter4.constraint.classId : parameter4.constraint.enumId,
58680
- true
58681
- )
58682
- }
58683
- },
59133
+ type: genericParameterLanguageType(
59134
+ parameter4.id,
59135
+ true,
59136
+ context,
59137
+ genericEnvironment
59138
+ ),
58684
59139
  location: virtualIdentifierLocation(
58685
59140
  context,
58686
59141
  "Classes",
@@ -59330,31 +59785,12 @@ function memberRuntimeType(record3, context, seen = /* @__PURE__ */ new Set(), g
59330
59785
  );
59331
59786
  }
59332
59787
  }
59333
- for (const owner of context.vm.classes) {
59334
- const parameter4 = owner.genericParams?.find(
59335
- (candidate) => candidate.id === genericParamId
59336
- );
59337
- if (parameter4) {
59338
- if (parameter4.constraint?.kind === "class") {
59339
- return namedType(parameter4.constraint.classId, required2);
59340
- }
59341
- if (parameter4.constraint?.kind === "enum") {
59342
- return namedType(parameter4.constraint.enumId, required2);
59343
- }
59344
- return {
59345
- kind: "typeParameter",
59346
- id: genericParamId,
59347
- name: parameter4.name,
59348
- nullable: !required2
59349
- };
59350
- }
59351
- }
59352
- return {
59353
- kind: "typeParameter",
59354
- id: genericParamId,
59355
- name: genericParamId,
59356
- nullable: !required2
59357
- };
59788
+ return genericParameterLanguageType(
59789
+ genericParamId,
59790
+ required2,
59791
+ context,
59792
+ genericEnvironment
59793
+ );
59358
59794
  }
59359
59795
  case 27 /* Variant */: {
59360
59796
  if (!isMemberVariantBase(member)) return UNKNOWN_TYPE2;
@@ -59417,13 +59853,13 @@ function classArguments(member, context, seen, genericEnvironment) {
59417
59853
  )
59418
59854
  ] : [];
59419
59855
  }
59420
- const declaration = context.vm.classes.flatMap((schemaClass2) => schemaClass2.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
59421
59856
  return [
59422
- {
59423
- kind: "typeParameter",
59424
- id: binding.genericParamId,
59425
- name: declaration?.name ?? binding.genericParamId
59426
- }
59857
+ genericParameterLanguageType(
59858
+ binding.genericParamId,
59859
+ true,
59860
+ context,
59861
+ genericEnvironment
59862
+ )
59427
59863
  ];
59428
59864
  }
59429
59865
  const argument2 = analyzerMemberById(context.vm, binding.memberId);
@@ -59571,33 +60007,89 @@ function toLanguageType(type, context, genericEnvironment) {
59571
60007
  );
59572
60008
  }
59573
60009
  }
59574
- const effectiveParamId = environmentEntry?.kind === "unbound" ? environmentEntry.paramId : type.genericParamId;
59575
- const owner = context.vm.classes.find(
59576
- (item) => item.id === type.ownerClassId || item.genericParams?.some(
59577
- (parameter4) => parameter4.id === effectiveParamId
59578
- )
60010
+ return genericParameterLanguageType(
60011
+ environmentEntry?.kind === "unbound" ? environmentEntry.paramId : type.genericParamId,
60012
+ required2,
60013
+ context,
60014
+ genericEnvironment
59579
60015
  );
59580
- const name = owner?.genericParams?.find(
59581
- (parameter4) => parameter4.id === effectiveParamId
59582
- )?.name ?? effectiveParamId;
59583
- const declaration = owner?.genericParams?.find(
59584
- (parameter4) => parameter4.id === effectiveParamId
60016
+ }
60017
+ }
60018
+ }
60019
+ function genericParameterLanguageType(genericParamId, required2, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
60020
+ const environmentEntry = genericEnvironment?.get(genericParamId);
60021
+ if (environmentEntry?.kind === "member") {
60022
+ const binding = analyzerMemberById(context.vm, environmentEntry.memberId);
60023
+ if (binding) {
60024
+ return requiredType(
60025
+ memberRuntimeType(binding, context, /* @__PURE__ */ new Set(), genericEnvironment)
59585
60026
  );
59586
- return {
59587
- kind: "typeParameter",
59588
- id: effectiveParamId,
59589
- name,
59590
- ...owner === void 0 ? {} : { ownerClassId: owner.id },
59591
- ...declaration?.constraint === void 0 || declaration.constraint === null ? {} : {
59592
- constraint: namedType(
59593
- declaration.constraint.kind === "class" ? declaration.constraint.classId : declaration.constraint.enumId,
59594
- true
59595
- )
59596
- },
59597
- nullable: !required2
59598
- };
59599
60027
  }
59600
60028
  }
60029
+ const effectiveParamId = environmentEntry?.kind === "unbound" ? environmentEntry.paramId : genericParamId;
60030
+ const owner = context.vm.classes.find(
60031
+ (schemaClass2) => schemaClass2.genericParams?.some(
60032
+ (parameter4) => parameter4.id === effectiveParamId
60033
+ )
60034
+ );
60035
+ const declaration = owner?.genericParams?.find(
60036
+ (parameter4) => parameter4.id === effectiveParamId
60037
+ );
60038
+ const next = new Set(visiting).add(effectiveParamId);
60039
+ return {
60040
+ kind: "typeParameter",
60041
+ id: effectiveParamId,
60042
+ name: declaration?.name ?? effectiveParamId,
60043
+ ...owner === void 0 ? {} : { ownerClassId: owner.id },
60044
+ ...visiting.has(effectiveParamId) || declaration?.constraint == null ? {} : {
60045
+ constraint: genericConstraintLanguageType(
60046
+ declaration.constraint,
60047
+ context,
60048
+ genericEnvironment,
60049
+ next
60050
+ )
60051
+ },
60052
+ nullable: !required2
60053
+ };
60054
+ }
60055
+ function genericConstraintLanguageType(constraint, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
60056
+ if (constraint.kind === "enum") {
60057
+ return namedType(constraint.enumId, true);
60058
+ }
60059
+ const target = context.vm.classes.find(
60060
+ (schemaClass2) => schemaClass2.id === constraint.classId
60061
+ );
60062
+ const bindings = constraint.classArguments;
60063
+ if (!target?.genericParams?.length || bindings == null) {
60064
+ return namedType(constraint.classId, true);
60065
+ }
60066
+ const typeArguments = target.genericParams.flatMap((parameter4) => {
60067
+ const binding = bindings[parameter4.id];
60068
+ if (binding === void 0) return [];
60069
+ if (binding.kind === "generic") {
60070
+ return [
60071
+ genericParameterLanguageType(
60072
+ binding.genericParamId,
60073
+ true,
60074
+ context,
60075
+ genericEnvironment,
60076
+ visiting
60077
+ )
60078
+ ];
60079
+ }
60080
+ const member = analyzerMemberById(context.vm, binding.memberId);
60081
+ return member ? [
60082
+ requiredType(
60083
+ memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)
60084
+ )
60085
+ ] : [];
60086
+ });
60087
+ return {
60088
+ kind: "named",
60089
+ typeId: constraint.classId,
60090
+ nullable: false,
60091
+ ...typeArguments.length === target.genericParams.length ? { typeArguments } : {}
60092
+ };
59601
60093
  }
59602
60094
  function functionReturnType(type, context, genericEnvironment) {
59603
60095
  return type.type === NS_TYPE_VOID ? primitive2("void", true) : toLanguageType(type, context, genericEnvironment);
@@ -59765,12 +60257,68 @@ function virtualNeoSchemaClassHeader(schemaClass2, context) {
59765
60257
  )?.name ?? constraint.classId : context.vm.enums.find(
59766
60258
  (candidate) => candidate.id === constraint.enumId
59767
60259
  )?.name ?? constraint.enumId;
60260
+ const targetClass = constraint.kind === "class" ? context.vm.classes.find(
60261
+ (candidate) => candidate.id === constraint.classId
60262
+ ) : void 0;
60263
+ const bindings = constraint.kind === "class" ? constraint.classArguments : void 0;
60264
+ const argumentsValue = targetClass?.genericParams?.flatMap(
60265
+ (targetParameter) => {
60266
+ const binding = bindings?.[targetParameter.id];
60267
+ if (binding?.kind === "generic") {
60268
+ const declaration = context.vm.classes.flatMap((candidate) => candidate.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
60269
+ return [
60270
+ virtualCSharpIdentifier(
60271
+ declaration?.name ?? binding.genericParamId
60272
+ )
60273
+ ];
60274
+ }
60275
+ if (binding?.kind === "member") {
60276
+ const member = analyzerMemberById(context.vm, binding.memberId);
60277
+ return [
60278
+ member ? virtualConstraintMemberType(member, context) : "object"
60279
+ ];
60280
+ }
60281
+ return [];
60282
+ }
60283
+ );
60284
+ const argumentSuffix = targetClass?.genericParams?.length && argumentsValue?.length === targetClass.genericParams.length ? `<${argumentsValue.join(", ")}>` : "";
59768
60285
  return [
59769
- ` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}`
60286
+ ` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}${argumentSuffix}`
59770
60287
  ];
59771
60288
  });
59772
60289
  return `public ${schemaClass2.isAbstract ? "abstract " : ""}partial class ${virtualCSharpIdentifier(schemaClass2.name)}${genericParameters}${inheritance}${constraints.join("")} // Neo class ${schemaClass2.id}`;
59773
60290
  }
60291
+ function virtualConstraintMemberType(member, context) {
60292
+ const resolved = resolveMember2(member, context.vm.members);
60293
+ switch (resolved.kind) {
60294
+ case 1 /* Bool */:
60295
+ return "bool";
60296
+ case 2 /* Int */:
60297
+ return "int";
60298
+ case 3 /* String */:
60299
+ return "string";
60300
+ case 4 /* Float */:
60301
+ return "double";
60302
+ case 20 /* Decimal */:
60303
+ return "decimal";
60304
+ case 7 /* Class */: {
60305
+ const classId = getOptionalString(resolved, "classId");
60306
+ const schemaClass2 = context.vm.classes.find(
60307
+ (candidate) => candidate.id === classId
60308
+ );
60309
+ return virtualCSharpIdentifier(schemaClass2?.name ?? classId ?? "object");
60310
+ }
60311
+ case 8 /* Enum */: {
60312
+ const enumId = getOptionalString(resolved, "enumId");
60313
+ const neoEnum = context.vm.enums.find(
60314
+ (candidate) => candidate.id === enumId
60315
+ );
60316
+ return virtualCSharpIdentifier(neoEnum?.name ?? enumId ?? "object");
60317
+ }
60318
+ default:
60319
+ return "object";
60320
+ }
60321
+ }
59774
60322
  function virtualNeoSchemaClassMemberLine(schemaKey, displayName, memberId) {
59775
60323
  return ` public object? ${virtualCSharpIdentifier(schemaKey)} { get; init; } // ${displayName}; Neo member ${memberId}`;
59776
60324
  }
@@ -59806,7 +60354,7 @@ var init_neoscript_language_context_adapter = __esm({
59806
60354
  init_project_root_members();
59807
60355
  init_project_file_registry();
59808
60356
  init_analyzer_types();
59809
- NEOSCRIPT_COMPILER_ADAPTER_REVISION = 1;
60357
+ NEOSCRIPT_COMPILER_ADAPTER_REVISION = 2;
59810
60358
  UNKNOWN_TYPE2 = {
59811
60359
  kind: "primitive",
59812
60360
  name: "unknown"
@@ -81908,10 +82456,13 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
81908
82456
  `Class "${schemaClass2.name}" (${schemaClass2.id}) cannot extend sealed class "${baseClass.name}" (${baseClass.id}).`
81909
82457
  );
81910
82458
  }
81911
- const genericParamConstraintsById = new Map(
82459
+ const genericParamDeclarationsById = new Map(
81912
82460
  classes.flatMap(
81913
82461
  (schemaClass2) => (schemaClass2.genericParams ?? []).map(
81914
- (param) => [param.id, param.constraint]
82462
+ (param) => [
82463
+ param.id,
82464
+ { constraint: param.constraint, ownerClassId: schemaClass2.id }
82465
+ ]
81915
82466
  )
81916
82467
  )
81917
82468
  );
@@ -82826,13 +83377,40 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
82826
83377
  if (!isRecord7(typeInfo) || typeInfo.type !== 21 || typeof typeInfo.genericParamId !== "string") {
82827
83378
  return null;
82828
83379
  }
82829
- const constraint = genericParamConstraintsById.get(typeInfo.genericParamId);
83380
+ const constraint = genericParamDeclarationsById.get(
83381
+ typeInfo.genericParamId
83382
+ )?.constraint;
82830
83383
  if (!constraint) return null;
82831
- return constraint.kind === "class" ? {
82832
- type: 7,
82833
- required: typeInfo.required === true,
82834
- classId: constraint.classId
82835
- } : {
83384
+ if (constraint.kind === "class") {
83385
+ const typeArguments = Object.fromEntries(
83386
+ Object.entries(constraint.classArguments ?? {}).flatMap(
83387
+ ([parameterId, binding]) => {
83388
+ if (binding.kind !== "generic") return [];
83389
+ const ownerClassId = genericParamDeclarationsById.get(
83390
+ binding.genericParamId
83391
+ )?.ownerClassId;
83392
+ return ownerClassId === void 0 ? [] : [
83393
+ [
83394
+ parameterId,
83395
+ {
83396
+ type: 21,
83397
+ required: true,
83398
+ ownerClassId,
83399
+ genericParamId: binding.genericParamId
83400
+ }
83401
+ ]
83402
+ ];
83403
+ }
83404
+ )
83405
+ );
83406
+ return {
83407
+ type: 7,
83408
+ required: typeInfo.required === true,
83409
+ classId: constraint.classId,
83410
+ ...Object.keys(typeArguments).length > 0 ? { typeArguments } : {}
83411
+ };
83412
+ }
83413
+ return {
82836
83414
  type: 8,
82837
83415
  required: typeInfo.required === true,
82838
83416
  enumId: constraint.enumId
@@ -110682,8 +111260,8 @@ var init_registry2 = __esm({
110682
111260
  "use strict";
110683
111261
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
110684
111262
  formatVersion: 3,
110685
- contractVersion: "3.12",
110686
- cliVersion: "0.31.5",
111263
+ contractVersion: "3.13",
111264
+ cliVersion: "0.31.7",
110687
111265
  projectFileUploadBatchSize: 32,
110688
111266
  documentRecords: {
110689
111267
  member: {
@@ -117278,7 +117856,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
117278
117856
  async function main() {
117279
117857
  const args = parseArgs(process.argv.slice(2));
117280
117858
  if (args.command === "--version") {
117281
- console.log("0.31.5");
117859
+ console.log("0.31.7");
117282
117860
  return;
117283
117861
  }
117284
117862
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {