gitnexus 1.6.6-rc.2 → 1.6.6-rc.21

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.
Files changed (112) hide show
  1. package/dist/_shared/index.d.ts +1 -1
  2. package/dist/_shared/index.d.ts.map +1 -1
  3. package/dist/_shared/index.js.map +1 -1
  4. package/dist/_shared/scope-resolution/reference-site.d.ts +8 -0
  5. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  6. package/dist/_shared/scope-resolution/registries/context.d.ts +18 -1
  7. package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
  8. package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
  9. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +4 -2
  10. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -1
  11. package/dist/_shared/scope-resolution/registries/lookup-core.js +8 -23
  12. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
  13. package/dist/cli/analyze.js +65 -3
  14. package/dist/cli/eval-server.d.ts +14 -3
  15. package/dist/cli/eval-server.js +79 -9
  16. package/dist/cli/index.js +3 -1
  17. package/dist/cli/serve.js +6 -1
  18. package/dist/cli/setup.js +6 -4
  19. package/dist/cli/wiki.d.ts +1 -0
  20. package/dist/cli/wiki.js +32 -8
  21. package/dist/core/ingestion/languages/cpp/captures.js +165 -9
  22. package/dist/core/ingestion/languages/cpp/constraint-filter.js +102 -32
  23. package/dist/core/ingestion/languages/cpp/type-classifier.d.ts +9 -9
  24. package/dist/core/ingestion/languages/cpp/type-classifier.js +12 -8
  25. package/dist/core/ingestion/languages/java.js +35 -0
  26. package/dist/core/ingestion/languages/javascript/arity.d.ts +11 -0
  27. package/dist/core/ingestion/languages/javascript/arity.js +11 -0
  28. package/dist/core/ingestion/languages/javascript/captures.d.ts +30 -0
  29. package/dist/core/ingestion/languages/javascript/captures.js +655 -0
  30. package/dist/core/ingestion/languages/javascript/import-target.d.ts +29 -0
  31. package/dist/core/ingestion/languages/javascript/import-target.js +53 -0
  32. package/dist/core/ingestion/languages/javascript/index.d.ts +48 -0
  33. package/dist/core/ingestion/languages/javascript/index.js +48 -0
  34. package/dist/core/ingestion/languages/javascript/interpret.d.ts +29 -0
  35. package/dist/core/ingestion/languages/javascript/interpret.js +41 -0
  36. package/dist/core/ingestion/languages/javascript/merge-bindings.d.ts +16 -0
  37. package/dist/core/ingestion/languages/javascript/merge-bindings.js +18 -0
  38. package/dist/core/ingestion/languages/javascript/query.d.ts +52 -0
  39. package/dist/core/ingestion/languages/javascript/query.js +413 -0
  40. package/dist/core/ingestion/languages/javascript/scope-resolver.d.ts +37 -0
  41. package/dist/core/ingestion/languages/javascript/scope-resolver.js +73 -0
  42. package/dist/core/ingestion/languages/javascript/simple-hooks.d.ts +32 -0
  43. package/dist/core/ingestion/languages/javascript/simple-hooks.js +37 -0
  44. package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +10 -0
  45. package/dist/core/ingestion/languages/typescript/simple-hooks.js +4 -1
  46. package/dist/core/ingestion/languages/typescript.js +15 -0
  47. package/dist/core/ingestion/model/field-registry.d.ts +17 -3
  48. package/dist/core/ingestion/model/field-registry.js +19 -4
  49. package/dist/core/ingestion/model/owned-members-lookup.d.ts +19 -0
  50. package/dist/core/ingestion/model/owned-members-lookup.js +43 -0
  51. package/dist/core/ingestion/model/type-registry.d.ts +9 -0
  52. package/dist/core/ingestion/model/type-registry.js +18 -0
  53. package/dist/core/ingestion/registry-primary-flag.js +1 -0
  54. package/dist/core/ingestion/resolve-references.d.ts +3 -1
  55. package/dist/core/ingestion/resolve-references.js +5 -1
  56. package/dist/core/ingestion/scope-extractor.js +4 -0
  57. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +1 -0
  58. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +37 -7
  59. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +2 -0
  60. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +8 -1
  61. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +2 -0
  62. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +4 -2
  63. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +48 -9
  64. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  65. package/dist/core/ingestion/scope-resolution/pipeline/run.js +2 -0
  66. package/dist/core/lbug/lbug-adapter.d.ts +3 -1
  67. package/dist/core/lbug/lbug-adapter.js +33 -19
  68. package/dist/core/lbug/lbug-config.d.ts +1 -1
  69. package/dist/core/lbug/lbug-config.js +1 -1
  70. package/dist/core/lbug/pool-adapter.d.ts +19 -7
  71. package/dist/core/lbug/pool-adapter.js +70 -44
  72. package/dist/core/lbug/query-params.d.ts +1 -0
  73. package/dist/core/lbug/query-params.js +21 -0
  74. package/dist/core/search/bm25-index.js +4 -6
  75. package/dist/core/wiki/generator.d.ts +13 -0
  76. package/dist/core/wiki/generator.js +45 -4
  77. package/dist/core/wiki/llm-client.d.ts +1 -1
  78. package/dist/core/wiki/llm-client.js +23 -6
  79. package/dist/mcp/local/local-backend.d.ts +18 -3
  80. package/dist/mcp/local/local-backend.js +127 -11
  81. package/dist/mcp/tools.js +10 -0
  82. package/dist/server/api.d.ts +3 -0
  83. package/dist/server/api.js +58 -30
  84. package/package.json +3 -3
  85. package/web/assets/agent-SmDhIVj9.js +608 -0
  86. package/web/assets/{architectureDiagram-UL44E2DR-DvIkEGkp.js → architectureDiagram-UL44E2DR-ChS6kfgC.js} +1 -1
  87. package/web/assets/{chunk-LCXTWHL2-CqJ0oo1x.js → chunk-LCXTWHL2-CikfiTEP.js} +1 -1
  88. package/web/assets/{chunk-RG4AUYOV-D0M6vdq9.js → chunk-RG4AUYOV-D0pH0sP0.js} +1 -1
  89. package/web/assets/{classDiagram-KGZ6W3CR-BB-saqC1.js → classDiagram-KGZ6W3CR-VJjLBrQ3.js} +1 -1
  90. package/web/assets/{classDiagram-v2-72OJOZXJ-Bp2bAlS5.js → classDiagram-v2-72OJOZXJ-CL_v399n.js} +1 -1
  91. package/web/assets/{diagram-3NCE3AQN-BUxnDPOY.js → diagram-3NCE3AQN-DTTuOnDj.js} +1 -1
  92. package/web/assets/{diagram-GF46GFSD-BJTyqqvI.js → diagram-GF46GFSD-Di3e_png.js} +1 -1
  93. package/web/assets/{diagram-QXG6HAR7-DilMHamP.js → diagram-QXG6HAR7-CVQY1hhk.js} +1 -1
  94. package/web/assets/{diagram-WEQXMOUZ-8KUrarg1.js → diagram-WEQXMOUZ-BoxS7CN3.js} +1 -1
  95. package/web/assets/{erDiagram-L5TCEMPS-Doj9mSiW.js → erDiagram-L5TCEMPS-CLTuHusW.js} +1 -1
  96. package/web/assets/{flowDiagram-H6V6AXG4-BOSR-i3p.js → flowDiagram-H6V6AXG4-CQfVb2C4.js} +1 -1
  97. package/web/assets/{index-j4-NuleT.js → index-BuC2I_Cj.js} +5 -5
  98. package/web/assets/{infoDiagram-3YFTVSEB-Ce_TvtaV.js → infoDiagram-3YFTVSEB-BOk6LlXV.js} +1 -1
  99. package/web/assets/{ishikawaDiagram-BNXS4ZKH-4MXIDCSF.js → ishikawaDiagram-BNXS4ZKH-C0sASGB6.js} +1 -1
  100. package/web/assets/{kanban-definition-75IXJCU3-yYdfm8Kk.js → kanban-definition-75IXJCU3-DT9Lizpz.js} +1 -1
  101. package/web/assets/{mindmap-definition-2TDM6QVE-DFNEKM77.js → mindmap-definition-2TDM6QVE-BEYaB7hb.js} +1 -1
  102. package/web/assets/{pieDiagram-CU6KROY3-iZAqpvhd.js → pieDiagram-CU6KROY3-DCgHNkyY.js} +1 -1
  103. package/web/assets/{requirementDiagram-JXO7QTGE-CtDijhnf.js → requirementDiagram-JXO7QTGE-D6vDU9M2.js} +1 -1
  104. package/web/assets/{sequenceDiagram-VS2MUI6T-BdjvyCHM.js → sequenceDiagram-VS2MUI6T-CJrGCTXy.js} +1 -1
  105. package/web/assets/{stateDiagram-7D4R322I-e5odN9fG.js → stateDiagram-7D4R322I-BvxQnQyL.js} +1 -1
  106. package/web/assets/{stateDiagram-v2-36443NZ5-vPsvjR2D.js → stateDiagram-v2-36443NZ5-D8ziO9W2.js} +1 -1
  107. package/web/assets/{timeline-definition-O6YCAMPW-DPAksNQp.js → timeline-definition-O6YCAMPW-B45j2q3m.js} +1 -1
  108. package/web/assets/{vennDiagram-MWXL3ELB-Dtlfdt7J.js → vennDiagram-MWXL3ELB-CRkZRDhi.js} +1 -1
  109. package/web/assets/{wardleyDiagram-CUQ6CDDI-B23uRMUC.js → wardleyDiagram-CUQ6CDDI-BekUytZJ.js} +1 -1
  110. package/web/assets/{xychartDiagram-N2JHSOCM-DxwHeksW.js → xychartDiagram-N2JHSOCM-BeMqwSgr.js} +1 -1
  111. package/web/index.html +1 -1
  112. package/web/assets/agent-D2kLt6Dl.js +0 -597
package/dist/cli/wiki.js CHANGED
@@ -14,6 +14,19 @@ import { WikiGenerator } from '../core/wiki/generator.js';
14
14
  import { resolveLLMConfig } from '../core/wiki/llm-client.js';
15
15
  import { detectCursorCLI } from '../core/wiki/cursor-client.js';
16
16
  import { logger } from '../core/logger.js';
17
+ function parsePositiveIntegerOption(value, flag, multiplier = 1) {
18
+ if (value === undefined)
19
+ return undefined;
20
+ const trimmed = value.trim();
21
+ if (!/^[1-9]\d*$/.test(trimmed)) {
22
+ throw new Error(`${flag} must be a positive integer`);
23
+ }
24
+ const parsed = parseInt(trimmed, 10);
25
+ if (parsed > Math.floor(Number.MAX_SAFE_INTEGER / multiplier)) {
26
+ throw new Error(`${flag} is too large`);
27
+ }
28
+ return parsed;
29
+ }
17
30
  /**
18
31
  * Prompt the user for input via stdin.
19
32
  */
@@ -100,6 +113,17 @@ export const wikiCommand = async (inputPath, options) => {
100
113
  process.exitCode = 1;
101
114
  return;
102
115
  }
116
+ let timeoutSeconds;
117
+ let retries;
118
+ try {
119
+ timeoutSeconds = parsePositiveIntegerOption(options?.timeout, '--timeout', 1000);
120
+ retries = parsePositiveIntegerOption(options?.retries, '--retries');
121
+ }
122
+ catch (error) {
123
+ console.log(` Error: ${error.message}\n`);
124
+ process.exitCode = 1;
125
+ return;
126
+ }
103
127
  // ── Resolve LLM config (with interactive fallback) ─────────────────
104
128
  // Save any CLI overrides immediately
105
129
  if (options?.apiKey ||
@@ -305,15 +329,11 @@ export const wikiCommand = async (inputPath, options) => {
305
329
  }
306
330
  }
307
331
  // ── Apply per-run overrides not saved to config ────────────────────
308
- if (options?.timeout) {
309
- const secs = parseInt(options.timeout, 10);
310
- if (!isNaN(secs) && secs > 0)
311
- llmConfig.requestTimeoutMs = secs * 1000;
332
+ if (timeoutSeconds !== undefined) {
333
+ llmConfig.requestTimeoutMs = timeoutSeconds * 1000;
312
334
  }
313
- if (options?.retries) {
314
- const n = parseInt(options.retries, 10);
315
- if (!isNaN(n) && n > 0)
316
- llmConfig.maxAttempts = n;
335
+ if (retries !== undefined) {
336
+ llmConfig.maxAttempts = retries;
317
337
  }
318
338
  // ── Setup progress bar with elapsed timer ──────────────────────────
319
339
  const bar = new cliProgress.SingleBar({
@@ -344,6 +364,7 @@ export const wikiCommand = async (inputPath, options) => {
344
364
  force: options?.force,
345
365
  concurrency: options?.concurrency ? parseInt(options.concurrency, 10) : undefined,
346
366
  reviewOnly: options?.review,
367
+ lang: options?.lang,
347
368
  };
348
369
  const generator = new WikiGenerator(repoPath, storagePath, lbugPath, llmConfig, wikiOptions, (phase, percent, detail) => {
349
370
  const label = detail || phase;
@@ -473,6 +494,9 @@ export const wikiCommand = async (inputPath, options) => {
473
494
  if (err.message?.includes('No source files')) {
474
495
  console.log(`\n ${err.message}\n`);
475
496
  }
497
+ else if (err.message?.includes('LLM request timed out after')) {
498
+ console.log(`\n Timeout: ${err.message}\n`);
499
+ }
476
500
  else if (err.message?.includes('content filter')) {
477
501
  // Content filter block — actionable message
478
502
  console.log(`\n Content Filter: ${err.message}\n`);
@@ -3,7 +3,7 @@ import { getCppParser, getCppScopeQuery } from './query.js';
3
3
  import { getTreeSitterBufferSize } from '../../constants.js';
4
4
  import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
5
5
  import { splitCppInclude, splitCppUsingDecl } from './import-decomposer.js';
6
- import { computeCppDeclarationArity, computeCppCallArity } from './arity-metadata.js';
6
+ import { classifyCppParameterType, computeCppDeclarationArity, computeCppCallArity, } from './arity-metadata.js';
7
7
  import { markCppAnonymousNamespaceRange, markFileLocal } from './file-local-linkage.js';
8
8
  import { markCppDependentBase } from './two-phase-lookup.js';
9
9
  import { markCppAdlSiteArgs, markCppAdlSiteNoAdl } from './adl.js';
@@ -159,6 +159,10 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
159
159
  if (argTypes !== undefined && argTypes.length > 0) {
160
160
  grouped['@reference.parameter-types'] = syntheticCapture('@reference.parameter-types', cNode, JSON.stringify(argTypes));
161
161
  }
162
+ const argTypeClasses = inferCppCallArgTypeClasses(cNode);
163
+ if (argTypeClasses !== undefined && argTypeClasses.length > 0) {
164
+ grouped['@reference.parameter-type-classes'] = syntheticCapture('@reference.parameter-type-classes', cNode, JSON.stringify(argTypeClasses));
165
+ }
162
166
  }
163
167
  }
164
168
  // ── Inline namespace detection ──────────────────────────────────
@@ -612,6 +616,36 @@ function inferCppCallArgTypes(node) {
612
616
  }
613
617
  return types.length > 0 ? types : undefined;
614
618
  }
619
+ function inferCppCallArgTypeClasses(node) {
620
+ const argList = node.childForFieldName('arguments');
621
+ if (argList === null)
622
+ return undefined;
623
+ const classes = [];
624
+ for (let i = 0; i < argList.childCount; i++) {
625
+ const child = argList.child(i);
626
+ if (child === null)
627
+ continue;
628
+ if (child.type === ',' || child.type === '(' || child.type === ')')
629
+ continue;
630
+ const litType = inferCppLiteralType(child);
631
+ if (litType !== '') {
632
+ classes.push(valueTypeClass(litType));
633
+ }
634
+ else if (child.type === 'identifier') {
635
+ classes.push(lookupDeclaredTypeClassForIdentifier(child));
636
+ }
637
+ else {
638
+ classes.push(unknownTypeClass('unknown'));
639
+ }
640
+ }
641
+ return classes.length > 0 ? classes : undefined;
642
+ }
643
+ function valueTypeClass(base) {
644
+ return { base, cv: 'none', indirection: 'value', pointerDepth: 0 };
645
+ }
646
+ function unknownTypeClass(base) {
647
+ return { base, cv: 'unknown', indirection: 'unknown', pointerDepth: 0 };
648
+ }
615
649
  /**
616
650
  * Infer the canonical type name of a C++ literal AST node.
617
651
  * Returns empty string for non-literal / unknown nodes.
@@ -674,6 +708,9 @@ function lookupDeclaredTypeForIdentifier(identNode) {
674
708
  }
675
709
  if (scope === null)
676
710
  return '';
711
+ const paramType = lookupFunctionParameterType(scope, varName);
712
+ if (paramType !== '')
713
+ return paramType;
677
714
  // Scan declarations in the scope for a matching variable name
678
715
  for (let i = 0; i < scope.childCount; i++) {
679
716
  const stmt = scope.child(i);
@@ -689,18 +726,113 @@ function lookupDeclaredTypeForIdentifier(identNode) {
689
726
  const declarator = stmt.childForFieldName('declarator');
690
727
  if (declarator === null)
691
728
  continue;
692
- if (declarator.type === 'init_declarator') {
693
- const nameChild = declarator.childForFieldName('declarator');
694
- if (nameChild !== null && nameChild.text === varName) {
695
- return normalizeCppTypeText(typeNode.text);
696
- }
697
- }
698
- else if (declarator.text === varName) {
729
+ const nameChild = declaredNameNode(declarator);
730
+ if (nameChild !== null && extractDeclaratorLeafName(nameChild) === varName) {
699
731
  return normalizeCppTypeText(typeNode.text);
700
732
  }
701
733
  }
702
734
  return '';
703
735
  }
736
+ function lookupDeclaredTypeClassForIdentifier(identNode) {
737
+ const varName = identNode.text;
738
+ let scope = identNode.parent;
739
+ while (scope !== null &&
740
+ scope.type !== 'compound_statement' &&
741
+ scope.type !== 'translation_unit') {
742
+ scope = scope.parent;
743
+ }
744
+ if (scope === null)
745
+ return unknownTypeClass('unknown');
746
+ const paramTypeClass = lookupFunctionParameterTypeClass(scope, varName, identNode);
747
+ if (paramTypeClass !== undefined)
748
+ return paramTypeClass;
749
+ for (let i = 0; i < scope.childCount; i++) {
750
+ const stmt = scope.child(i);
751
+ if (stmt === null || stmt.type !== 'declaration')
752
+ continue;
753
+ const typeNode = stmt.childForFieldName('type');
754
+ if (typeNode === null)
755
+ continue;
756
+ if (typeNode.type === 'placeholder_type_specifier')
757
+ continue;
758
+ const declarator = stmt.childForFieldName('declarator');
759
+ if (declarator === null)
760
+ continue;
761
+ const nameChild = declaredNameNode(declarator);
762
+ if (nameChild === null || extractDeclaratorLeafName(nameChild) !== varName)
763
+ continue;
764
+ const typeClass = classifyCppParameterType(typeNode.text, nameChild.text, stmt.text.replace(/;\s*$/, ''));
765
+ if (isKnownEnumName(identNode, typeClass.base)) {
766
+ return { ...typeClass, base: `enum:${typeClass.base}` };
767
+ }
768
+ return typeClass;
769
+ }
770
+ return unknownTypeClass('unknown');
771
+ }
772
+ function lookupFunctionParameterType(scope, varName) {
773
+ const param = findEnclosingFunctionParameter(scope, varName);
774
+ if (param === null)
775
+ return '';
776
+ const typeNode = param.childForFieldName('type');
777
+ if (typeNode === null)
778
+ return '';
779
+ return normalizeCppTypeText(typeNode.text);
780
+ }
781
+ function lookupFunctionParameterTypeClass(scope, varName, identNode) {
782
+ const param = findEnclosingFunctionParameter(scope, varName);
783
+ if (param === null)
784
+ return undefined;
785
+ const typeNode = param.childForFieldName('type');
786
+ if (typeNode === null)
787
+ return undefined;
788
+ const declarator = param.childForFieldName('declarator');
789
+ if (declarator === null)
790
+ return undefined;
791
+ const typeClass = classifyCppParameterType(typeNode.text, declarator.text, param.text);
792
+ if (isKnownEnumName(identNode, typeClass.base)) {
793
+ return { ...typeClass, base: `enum:${typeClass.base}` };
794
+ }
795
+ return typeClass;
796
+ }
797
+ function findEnclosingFunctionParameter(scope, varName) {
798
+ let node = scope.parent;
799
+ while (node !== null) {
800
+ if (node.type === 'function_definition' || node.type === 'function_declarator') {
801
+ const fnDecl = node.type === 'function_declarator'
802
+ ? node
803
+ : findFirstDescendantOfType(node, 'function_declarator');
804
+ const params = fnDecl?.childForFieldName('parameters') ?? null;
805
+ if (params !== null) {
806
+ for (let i = 0; i < params.namedChildCount; i++) {
807
+ const param = params.namedChild(i);
808
+ if (param === null || param.type !== 'parameter_declaration')
809
+ continue;
810
+ const declarator = param.childForFieldName('declarator');
811
+ if (declarator !== null && extractDeclaratorLeafName(declarator) === varName) {
812
+ return param;
813
+ }
814
+ }
815
+ }
816
+ return null;
817
+ }
818
+ node = node.parent;
819
+ }
820
+ return null;
821
+ }
822
+ function declaredNameNode(declarator) {
823
+ if (declarator.type !== 'init_declarator')
824
+ return declarator;
825
+ for (let i = 0; i < declarator.namedChildCount; i++) {
826
+ const child = declarator.namedChild(i);
827
+ if (child === null)
828
+ continue;
829
+ if (child.type === 'identifier')
830
+ return child;
831
+ if (child.type.endsWith('_declarator'))
832
+ return child;
833
+ }
834
+ return declarator.childForFieldName('declarator');
835
+ }
704
836
  /** Normalize a type-specifier text for argument type matching.
705
837
  * Strips qualifiers (const, volatile), namespace prefixes (std::),
706
838
  * and pointer/reference markers. */
@@ -711,6 +843,28 @@ function normalizeCppTypeText(text) {
711
843
  t = t.replace(/[*&]/g, '').trim();
712
844
  return t;
713
845
  }
846
+ function isKnownEnumName(node, typeName) {
847
+ if (typeName === '' || typeName === 'unknown')
848
+ return false;
849
+ let root = node;
850
+ while (root.parent !== null)
851
+ root = root.parent;
852
+ const stack = [root];
853
+ while (stack.length > 0) {
854
+ const cur = stack.pop();
855
+ if (cur.type === 'enum_specifier') {
856
+ const name = cur.childForFieldName('name');
857
+ if (name?.text === typeName)
858
+ return true;
859
+ }
860
+ for (let i = 0; i < cur.childCount; i++) {
861
+ const child = cur.child(i);
862
+ if (child !== null)
863
+ stack.push(child);
864
+ }
865
+ }
866
+ return false;
867
+ }
714
868
  /**
715
869
  * Detect whether a `namespace_definition` AST node is inline.
716
870
  * Tree-sitter-cpp exposes the `inline` keyword as an anonymous child
@@ -1166,7 +1320,9 @@ function extractDeclaratorLeafName(node) {
1166
1320
  // Common wrapper nodes — follow the 'declarator' field when present.
1167
1321
  const next = cur.childForFieldName('declarator') ??
1168
1322
  // parenthesized_declarator: single named child
1169
- (cur.type === 'parenthesized_declarator' ? cur.namedChild(0) : null);
1323
+ (cur.type === 'parenthesized_declarator' || cur.type.endsWith('_declarator')
1324
+ ? cur.namedChild(0)
1325
+ : null);
1170
1326
  if (next === null)
1171
1327
  return null;
1172
1328
  cur = next;
@@ -21,13 +21,9 @@
21
21
  */
22
22
  import { classifyType } from './type-classifier.js';
23
23
  /**
24
- * Curated Tier-A predicate registry — the four canonical
25
- * `<type_traits>` variable templates whose truth tables are closed-form
26
- * over our coarse `TypeClass` enum.
27
- *
28
- * Deferred predicates that need a cv/ref/pointer sidecar on
29
- * `normalizeCppParamType` (today the normalizer strips those markers
30
- * before storage) live in #1579 as one-line follow-up adds.
24
+ * Curated Tier-A predicate registry. Predicates that depend on pointer,
25
+ * reference, or cv shape consult `ConstraintContext.argumentTypeClasses`.
26
+ * Missing or unsupported shape returns 'unknown' to preserve monotonicity.
31
27
  */
32
28
  // ISO `<type_traits>` treats `bool`, `char`, and the signed/unsigned char
33
29
  // variants as integral types (§21.3.4 Table 48), so `is_integral_v<bool>`
@@ -39,40 +35,117 @@ function isIntegralClass(c) {
39
35
  return c === 'integral' || c === 'bool' || c === 'char';
40
36
  }
41
37
  const REGISTRY = new Map([
42
- ['is_integral_v', (cls) => verdictFromBool(isIntegralClass(cls[0]), cls)],
43
- ['is_floating_point_v', (cls) => verdictFromBool(cls[0] === 'floating', cls)],
38
+ [
39
+ 'is_void_v',
40
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'void'),
41
+ ],
42
+ [
43
+ 'is_integral_v',
44
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && isIntegralClass(arg.typeClass)),
45
+ ],
46
+ [
47
+ 'is_floating_point_v',
48
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'floating'),
49
+ ],
44
50
  [
45
51
  'is_arithmetic_v',
46
- (cls) => verdictFromBool(isIntegralClass(cls[0]) || cls[0] === 'floating', cls),
52
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && (isIntegralClass(arg.typeClass) || arg.typeClass === 'floating')),
53
+ ],
54
+ [
55
+ 'is_enum_v',
56
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'enum'),
57
+ ],
58
+ [
59
+ 'is_class_v',
60
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'class'),
61
+ ],
62
+ [
63
+ 'is_pointer_v',
64
+ (args) => unaryShapeVerdict(args, (shape) => shape.indirection === 'pointer' && shape.pointerDepth > 0),
65
+ ],
66
+ [
67
+ 'is_reference_v',
68
+ (args) => unaryShapeVerdict(args, (shape) => shape.indirection === 'lvalue-ref' || shape.indirection === 'rvalue-ref'),
69
+ ],
70
+ [
71
+ 'is_const_v',
72
+ (args) => unaryShapeVerdict(args, (shape) => shape.cv === 'const' || shape.cv === 'const volatile', {
73
+ requireTopLevelCv: true,
74
+ }),
75
+ ],
76
+ [
77
+ 'is_volatile_v',
78
+ (args) => unaryShapeVerdict(args, (shape) => shape.cv === 'volatile' || shape.cv === 'const volatile', {
79
+ requireTopLevelCv: true,
80
+ }),
47
81
  ],
48
- // NOTE: cv-qualifiers are stripped by `normalizeCppParamType` before the
49
- // type token reaches `classifyType`, so `is_same_v<const T, T>` returns
50
- // `'compatible'` instead of the ISO-correct `false`. Tracked under the
51
- // cv-sidecar refactor in #1579's "Out of scope" list; until that lands
52
- // this approximation matches the common `is_same_v<T, ConcreteType>`
53
- // dispatch idiom and silently degrades on cv-distinct compares.
54
82
  [
55
83
  'is_same_v',
56
- (cls) => {
57
- if (cls.length < 2 || cls[0] === 'unknown' || cls[1] === 'unknown')
84
+ (args) => {
85
+ if (args.length < 2 || args[0].typeClass === 'unknown' || args[1].typeClass === 'unknown') {
58
86
  return 'unknown';
59
- return cls[0] === cls[1] ? 'compatible' : 'incompatible';
87
+ }
88
+ return args[0].typeClass === args[1].typeClass ? 'compatible' : 'incompatible';
60
89
  },
61
90
  ],
62
91
  ]);
63
- function verdictFromBool(predicate, cls) {
64
- if (cls[0] === 'unknown')
92
+ function unaryVerdict(args, predicate) {
93
+ const arg = args[0];
94
+ if (arg === undefined || arg.typeClass === 'unknown')
65
95
  return 'unknown';
66
- return predicate ? 'compatible' : 'incompatible';
96
+ return predicate(arg) ? 'compatible' : 'incompatible';
97
+ }
98
+ function unaryShapeVerdict(args, predicate, options = {}) {
99
+ const arg = args[0];
100
+ if (arg === undefined || arg.typeClass === 'unknown')
101
+ return 'unknown';
102
+ const shape = arg.shape;
103
+ if (shape === undefined || shape.indirection === 'unknown' || shape.cv === 'unknown') {
104
+ return 'unknown';
105
+ }
106
+ if (options.requireTopLevelCv === true && shape.indirection === 'pointer') {
107
+ return 'unknown';
108
+ }
109
+ return predicate(shape) ? 'compatible' : 'incompatible';
110
+ }
111
+ function isPlainValue(arg) {
112
+ const shape = arg.shape;
113
+ if (shape === undefined)
114
+ return true;
115
+ return shape.indirection === 'value';
116
+ }
117
+ function classifyConstraintArg(token, shape) {
118
+ if (shape !== undefined && shape.base.startsWith('enum:')) {
119
+ return { typeClass: 'enum', shape };
120
+ }
121
+ const typeClass = token === undefined || token === '' ? 'unknown' : classifyType(token);
122
+ return { typeClass, ...(shape !== undefined ? { shape } : {}) };
123
+ }
124
+ function tokenForArg(ctx, argIdx) {
125
+ const shape = ctx.argumentTypeClasses?.[argIdx];
126
+ if (shape?.base.startsWith('enum:'))
127
+ return shape.base;
128
+ return ctx.argumentTypes?.[argIdx];
129
+ }
130
+ function shapeForTemplateParam(ctx, paramName, argIdx, def) {
131
+ const argShape = ctx.argumentTypeClasses?.[argIdx];
132
+ if (argShape === undefined)
133
+ return undefined;
134
+ const paramShape = def?.parameterTypeClasses?.[argIdx];
135
+ if (paramShape === undefined)
136
+ return argShape;
137
+ if (paramShape.base === paramName && paramShape.indirection === 'value')
138
+ return argShape;
139
+ return undefined;
67
140
  }
68
141
  /** Public surface — registered as `ScopeResolver.constraintCompatibility`. */
69
142
  export function cppConstraintCompatibility(_callsite, def, ctx) {
70
143
  const payload = def.templateConstraints;
71
144
  if (payload === undefined)
72
145
  return 'unknown';
73
- return evaluate(payload.expr, payload, ctx);
146
+ return evaluate(payload.expr, payload, ctx, def);
74
147
  }
75
- function evaluate(expr, payload, ctx) {
148
+ function evaluate(expr, payload, ctx, def) {
76
149
  switch (expr.kind) {
77
150
  case 'unknown':
78
151
  return 'unknown';
@@ -83,18 +156,15 @@ function evaluate(expr, payload, ctx) {
83
156
  const classes = expr.args.map((paramName) => {
84
157
  const argIdx = payload.paramArgIndex[paramName];
85
158
  if (argIdx === undefined)
86
- return 'unknown';
87
- const token = ctx.argumentTypes?.[argIdx];
88
- if (token === undefined || token === '')
89
- return 'unknown';
90
- return classifyType(token);
159
+ return { typeClass: 'unknown' };
160
+ return classifyConstraintArg(tokenForArg(ctx, argIdx), shapeForTemplateParam(ctx, paramName, argIdx, def));
91
161
  });
92
162
  return evaluator(classes);
93
163
  }
94
164
  case 'and': {
95
165
  let result = 'compatible';
96
166
  for (const child of expr.children) {
97
- const v = evaluate(child, payload, ctx);
167
+ const v = evaluate(child, payload, ctx, def);
98
168
  if (v === 'incompatible')
99
169
  return 'incompatible';
100
170
  if (v === 'unknown')
@@ -105,7 +175,7 @@ function evaluate(expr, payload, ctx) {
105
175
  case 'or': {
106
176
  let result = 'incompatible';
107
177
  for (const child of expr.children) {
108
- const v = evaluate(child, payload, ctx);
178
+ const v = evaluate(child, payload, ctx, def);
109
179
  if (v === 'compatible')
110
180
  return 'compatible';
111
181
  if (v === 'unknown')
@@ -114,7 +184,7 @@ function evaluate(expr, payload, ctx) {
114
184
  return result;
115
185
  }
116
186
  case 'not': {
117
- const v = evaluate(expr.child, payload, ctx);
187
+ const v = evaluate(expr.child, payload, ctx, def);
118
188
  if (v === 'compatible')
119
189
  return 'incompatible';
120
190
  if (v === 'incompatible')
@@ -7,20 +7,20 @@
7
7
  * the call-site inference in `captures.ts`) to one of the categories
8
8
  * the `<type_traits>` predicate registry uses for SFINAE filtering.
9
9
  *
10
- * Intentionally coarse: cv / pointer / reference qualifiers are stripped
11
- * upstream by `normalizeCppParamType`. Tier-A predicates
12
- * (`is_integral_v`, `is_floating_point_v`, `is_arithmetic_v`, `is_same_v`)
13
- * are insensitive to those modifiers per ISO `<type_traits>` semantics
14
- * ("including any cv-qualified variants").
10
+ * `argumentTypes` remain normalized for overload narrowing, while
11
+ * constraint predicates that need cv/ref/pointer shape read the parallel
12
+ * `argumentTypeClasses` sidecar. Unknown shapes must stay unknown rather
13
+ * than being guessed as incompatible.
15
14
  */
16
- export type TypeClass = 'integral' | 'floating' | 'bool' | 'char' | 'string' | 'null' | 'class' | 'unknown';
15
+ export type TypeClass = 'integral' | 'floating' | 'bool' | 'char' | 'string' | 'null' | 'void' | 'enum' | 'class' | 'pointer' | 'reference' | 'unknown';
17
16
  /**
18
17
  * Classify a normalized C++ type token. The mapping mirrors the literal-
19
18
  * inference table in `captures.ts:inferCppLiteralType` plus the std::
20
19
  * normalization in `arity-metadata.ts:normalizeCppParamType`.
21
20
  *
22
- * Caller note: token must already be normalized (no `const`, no `&` / `*`,
23
- * no `std::` prefix). Tokens passed via `ConstraintContext.argumentTypes`
24
- * coming from `inferCppCallArgTypes` satisfy this.
21
+ * Caller note: token should be normalized for overload matching. Enum
22
+ * tokens produced by the C++ adapter use the internal `enum:<Name>`
23
+ * prefix so `is_enum_v` does not have to guess that every user token is
24
+ * class-like.
25
25
  */
26
26
  export declare function classifyType(token: string): TypeClass;
@@ -7,25 +7,29 @@
7
7
  * the call-site inference in `captures.ts`) to one of the categories
8
8
  * the `<type_traits>` predicate registry uses for SFINAE filtering.
9
9
  *
10
- * Intentionally coarse: cv / pointer / reference qualifiers are stripped
11
- * upstream by `normalizeCppParamType`. Tier-A predicates
12
- * (`is_integral_v`, `is_floating_point_v`, `is_arithmetic_v`, `is_same_v`)
13
- * are insensitive to those modifiers per ISO `<type_traits>` semantics
14
- * ("including any cv-qualified variants").
10
+ * `argumentTypes` remain normalized for overload narrowing, while
11
+ * constraint predicates that need cv/ref/pointer shape read the parallel
12
+ * `argumentTypeClasses` sidecar. Unknown shapes must stay unknown rather
13
+ * than being guessed as incompatible.
15
14
  */
16
15
  /**
17
16
  * Classify a normalized C++ type token. The mapping mirrors the literal-
18
17
  * inference table in `captures.ts:inferCppLiteralType` plus the std::
19
18
  * normalization in `arity-metadata.ts:normalizeCppParamType`.
20
19
  *
21
- * Caller note: token must already be normalized (no `const`, no `&` / `*`,
22
- * no `std::` prefix). Tokens passed via `ConstraintContext.argumentTypes`
23
- * coming from `inferCppCallArgTypes` satisfy this.
20
+ * Caller note: token should be normalized for overload matching. Enum
21
+ * tokens produced by the C++ adapter use the internal `enum:<Name>`
22
+ * prefix so `is_enum_v` does not have to guess that every user token is
23
+ * class-like.
24
24
  */
25
25
  export function classifyType(token) {
26
26
  if (token.length === 0)
27
27
  return 'unknown';
28
+ if (token.startsWith('enum:'))
29
+ return 'enum';
28
30
  switch (token) {
31
+ case 'void':
32
+ return 'void';
29
33
  case 'int':
30
34
  return 'integral';
31
35
  case 'double':
@@ -26,6 +26,40 @@ import { createVariableExtractor } from '../variable-extractors/generic.js';
26
26
  import { javaVariableConfig } from '../variable-extractors/configs/jvm.js';
27
27
  import { createHeritageExtractor } from '../heritage-extractors/generic.js';
28
28
  import { emitJavaScopeCaptures, interpretJavaImport, interpretJavaTypeBinding, javaBindingScopeFor, javaImportOwningScope, javaMergeBindings, javaReceiverBinding, javaArityCompatibility, resolveJavaImportTarget, } from './java/index.js';
29
+ const orderJavaSameNameTypeCandidates = ({ callSiteFilePath, candidates, }) => {
30
+ if (!callSiteFilePath.endsWith('.java'))
31
+ return null;
32
+ if (candidates.length <= 1)
33
+ return null;
34
+ const callerDir = splitDirectorySegments(callSiteFilePath);
35
+ const scored = candidates.map((candidate, index) => ({
36
+ candidate,
37
+ index,
38
+ score: sharedPrefixLength(callerDir, splitDirectorySegments(candidate.filePath)),
39
+ }));
40
+ const bestScore = Math.max(...scored.map((entry) => entry.score));
41
+ // When all candidates tie, we have no structural signal to prefer one path.
42
+ // Returning null keeps downstream ambiguity handling conservative.
43
+ if (scored.every((entry) => entry.score === bestScore))
44
+ return null;
45
+ const ordered = [...scored]
46
+ .sort((a, b) => b.score - a.score || a.index - b.index)
47
+ .map((entry) => entry.candidate);
48
+ return ordered;
49
+ };
50
+ const splitDirectorySegments = (filePath) => {
51
+ const normalized = filePath.replace(/\\/g, '/');
52
+ // Remove empty segments from leading/trailing/multiple slashes, then drop filename.
53
+ const segments = normalized.split('/').filter(Boolean);
54
+ return segments.slice(0, -1);
55
+ };
56
+ const sharedPrefixLength = (left, right) => {
57
+ const max = Math.min(left.length, right.length);
58
+ let idx = 0;
59
+ while (idx < max && left[idx] === right[idx])
60
+ idx += 1;
61
+ return idx;
62
+ };
29
63
  export const javaProvider = defineLanguage({
30
64
  id: SupportedLanguages.Java,
31
65
  extensions: ['.java'],
@@ -73,4 +107,5 @@ export const javaProvider = defineLanguage({
73
107
  receiverBinding: javaReceiverBinding,
74
108
  arityCompatibility: javaArityCompatibility,
75
109
  resolveImportTarget: resolveJavaImportTarget,
110
+ orderSameNameTypeCandidates: orderJavaSameNameTypeCandidates,
76
111
  });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Arity compatibility for JavaScript.
3
+ *
4
+ * Delegates to `typescriptArityCompatibility` unchanged — JavaScript
5
+ * supports the same arity constructs (rest parameters `...args`, default
6
+ * parameters `p = v`) and the metadata shape (`parameterCount`,
7
+ * `requiredParameterCount`, `parameterTypes`) is synthesized by the same
8
+ * `computeTsArityMetadata` function (which understands both TS and JS
9
+ * parameter node types via `extractTsJsParameters`).
10
+ */
11
+ export { typescriptArityCompatibility as jsArityCompatibility } from '../typescript/arity.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Arity compatibility for JavaScript.
3
+ *
4
+ * Delegates to `typescriptArityCompatibility` unchanged — JavaScript
5
+ * supports the same arity constructs (rest parameters `...args`, default
6
+ * parameters `p = v`) and the metadata shape (`parameterCount`,
7
+ * `requiredParameterCount`, `parameterTypes`) is synthesized by the same
8
+ * `computeTsArityMetadata` function (which understands both TS and JS
9
+ * parameter node types via `extractTsJsParameters`).
10
+ */
11
+ export { typescriptArityCompatibility as jsArityCompatibility } from '../typescript/arity.js';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * `emitScopeCaptures` for JavaScript.
3
+ *
4
+ * Adapts `emitTsScopeCaptures` for the JavaScript grammar:
5
+ *
6
+ * 1. **JS grammar** — uses `tree-sitter-javascript` instead of
7
+ * `tree-sitter-typescript`. The JS scope query is a subset of the
8
+ * TypeScript one (TypeScript-only node types dropped).
9
+ *
10
+ * 2. **CJS `require()` decomposition** — `const { X } = require('./m')`
11
+ * and `const X = require('./m')` are walked in a post-query pass and
12
+ * synthesized as `@import.kind/name/alias/source` markers so that
13
+ * `interpretJsImport` can recover a `ParsedImport` using the same
14
+ * shape as the TypeScript ESM decomposer.
15
+ *
16
+ * 3. **JSDoc type bindings** — JavaScript has no static type annotations
17
+ * so `@type-binding.parameter` / `@type-binding.return` must be
18
+ * inferred from leading JSDoc comments. A lightweight regex scanner
19
+ * (`parseJsDocParams` / `parseJsDocReturn`) extracts `@param {T} n`
20
+ * and `@returns {T}` tags and emits synthetic captures positioned on
21
+ * the annotated function node.
22
+ *
23
+ * 4. **Shared synthesis passes** — destructuring, for-of map-tuple, and
24
+ * instanceof narrowing passes are duplicated from `typescript/captures.ts`
25
+ * (they are pure AST operations with no grammar-specific logic).
26
+ *
27
+ * Pure given the input source text. No I/O, no globals consulted.
28
+ */
29
+ import type { CaptureMatch } from '../../../../_shared/index.js';
30
+ export declare function emitJsScopeCaptures(sourceText: string, filePath: string, cachedTree?: unknown): readonly CaptureMatch[];