gitnexus 1.6.10-rc.48 → 1.6.10-rc.49

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.
@@ -36,6 +36,7 @@ import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
36
36
  import { encodeMarker } from '../../utils/heritage-marker.js';
37
37
  import { DART_BUILT_INS } from './built-ins.js';
38
38
  import { synthesizeCallableFlowCaptures } from '../../utils/callable-flow-captures.js';
39
+ import { preprocessDartExtensionTypes } from './extension-type-preprocess.js';
39
40
  const FUNCTION_DECL_TAGS = [
40
41
  '@declaration.function',
41
42
  '@declaration.method',
@@ -70,14 +71,15 @@ function dartLexicalFunctionOwner(input) {
70
71
  return undefined;
71
72
  }
72
73
  export function emitDartScopeCaptures(sourceText, _filePath, cachedTree) {
74
+ const parseText = preprocessDartExtensionTypes(sourceText);
73
75
  let tree;
74
76
  if (cachedTree !== undefined && cachedTree !== null) {
75
77
  tree = cachedTree;
76
78
  recordCacheHit();
77
79
  }
78
80
  else {
79
- tree = parseSourceSafe(getDartParser(), sourceText, undefined, {
80
- bufferSize: getTreeSitterBufferSize(sourceText),
81
+ tree = parseSourceSafe(getDartParser(), parseText, undefined, {
82
+ bufferSize: getTreeSitterBufferSize(parseText),
81
83
  });
82
84
  recordCacheMiss();
83
85
  }
@@ -161,6 +163,10 @@ export function emitDartScopeCaptures(sourceText, _filePath, cachedTree) {
161
163
  emitHeritage(node, out);
162
164
  return;
163
165
  }
166
+ if (node.type === 'extension_declaration') {
167
+ emitExtensionImplementsHeritage(node, out);
168
+ return;
169
+ }
164
170
  });
165
171
  out.push(...synthesizeCallableFlowCaptures(root, DART_CALLABLE_CAPTURE_OPTIONS));
166
172
  return out;
@@ -475,6 +481,47 @@ function emitHeritage(classNode, out) {
475
481
  emitHeritageMarkers(interfaces, 'implements', className, out);
476
482
  }
477
483
  }
484
+ function emitExtensionImplementsHeritage(extensionNode, out) {
485
+ const nameNode = extensionNode.childForFieldName('name');
486
+ if (nameNode === null)
487
+ return;
488
+ const bodyStart = extensionNode.text.indexOf('{');
489
+ const header = bodyStart === -1 ? extensionNode.text : extensionNode.text.slice(0, bodyStart);
490
+ const implementsIndex = header.indexOf('implements');
491
+ if (implementsIndex === -1)
492
+ return;
493
+ const className = nameNode.text;
494
+ const interfaces = header.slice(implementsIndex + 'implements'.length);
495
+ for (const rawInterface of splitTopLevelCommaList(interfaces)) {
496
+ const target = /^[ \t]*([A-Za-z_$][A-Za-z0-9_$]*)/.exec(rawInterface)?.[1];
497
+ if (target === undefined)
498
+ continue;
499
+ const payload = encodeMarker('heritage', ['implements', target, className]);
500
+ out.push({ '@import.heritage': syntheticCapture('@import.heritage', nameNode, payload) });
501
+ }
502
+ }
503
+ function splitTopLevelCommaList(text) {
504
+ const parts = [];
505
+ let start = 0;
506
+ let angleDepth = 0;
507
+ for (let i = 0; i < text.length; i++) {
508
+ const ch = text[i];
509
+ if (ch === '<') {
510
+ angleDepth++;
511
+ continue;
512
+ }
513
+ if (ch === '>' && angleDepth > 0) {
514
+ angleDepth--;
515
+ continue;
516
+ }
517
+ if (ch === ',' && angleDepth === 0) {
518
+ parts.push(text.slice(start, i));
519
+ start = i + 1;
520
+ }
521
+ }
522
+ parts.push(text.slice(start));
523
+ return parts;
524
+ }
478
525
  function emitHeritageMarkers(container, kind, className, out) {
479
526
  for (let i = 0; i < container.namedChildCount; i++) {
480
527
  const c = container.namedChild(i);
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Rewrites Dart 3.3 `extension type Name(Type value)` headers into ordinary
3
+ * extension headers before tree-sitter sees the source. The vendored grammar
4
+ * currently recovers these declarations through an ERROR subtree, while the
5
+ * existing Dart ingestion path already handles `extension Name on Type`.
6
+ */
7
+ export declare function preprocessDartExtensionTypes(sourceText: string): string;
@@ -0,0 +1,30 @@
1
+ const DART_EXTENSION_TYPE_HEADER = /\b(extension)([ \t]+type[ \t]+(?:const[ \t]+)?)([A-Za-z_$][A-Za-z0-9_$]*)([ \t]*<[^()\r\n]*>)?([ \t]*)\(([^()\r\n]*)\)/g;
2
+ function representationType(representation) {
3
+ const trimmed = representation.trim();
4
+ const match = /^(.*\S)\s+[A-Za-z_$][A-Za-z0-9_$]*$/.exec(trimmed);
5
+ const typeName = match?.[1]?.trim();
6
+ return typeName && typeName.length > 0 ? typeName : null;
7
+ }
8
+ /**
9
+ * Rewrites Dart 3.3 `extension type Name(Type value)` headers into ordinary
10
+ * extension headers before tree-sitter sees the source. The vendored grammar
11
+ * currently recovers these declarations through an ERROR subtree, while the
12
+ * existing Dart ingestion path already handles `extension Name on Type`.
13
+ */
14
+ export function preprocessDartExtensionTypes(sourceText) {
15
+ return sourceText.replace(DART_EXTENSION_TYPE_HEADER, (match, extensionKeyword, extensionTypeGap, name, typeParameters, beforeRepresentation, representation) => {
16
+ const typeName = representationType(representation);
17
+ if (typeName === null)
18
+ return match;
19
+ const representationSpanLength = beforeRepresentation.length + representation.length + 2;
20
+ const rewrittenRepresentation = ` on ${typeName}`;
21
+ if (rewrittenRepresentation.length > representationSpanLength)
22
+ return match;
23
+ return (extensionKeyword +
24
+ ' '.repeat(extensionTypeGap.length) +
25
+ name +
26
+ (typeParameters ?? '') +
27
+ rewrittenRepresentation +
28
+ ' '.repeat(representationSpanLength - rewrittenRepresentation.length));
29
+ });
30
+ }
@@ -29,6 +29,7 @@ import { createCallExtractor } from '../call-extractors/generic.js';
29
29
  import { dartCallConfig } from '../call-extractors/configs/dart.js';
30
30
  import { emitDartScopeCaptures, interpretDartImport, interpretDartTypeBinding, dartBindingScopeFor, dartImportOwningScope, dartReceiverBinding, dartMergeBindings, dartArityCompatibility, } from './dart/index.js';
31
31
  import { DART_BUILT_INS } from './dart/built-ins.js';
32
+ import { preprocessDartExtensionTypes } from './dart/extension-type-preprocess.js';
32
33
  /**
33
34
  * Resolve the enclosing function from a `function_body` node by looking at its
34
35
  * previous sibling. In Dart's tree-sitter grammar, function_signature and
@@ -100,6 +101,7 @@ export const dartProvider = defineLanguage({
100
101
  },
101
102
  ],
102
103
  treeSitterQueries: DART_QUERIES,
104
+ preprocessSource: preprocessDartExtensionTypes,
103
105
  typeConfig: dartConfig,
104
106
  exportChecker: dartExportChecker,
105
107
  importResolver: createImportResolver(dartImportConfig),
@@ -209,7 +209,7 @@ export const CONTAINER_TYPE_TO_LABEL = {
209
209
  record_declaration: 'Record',
210
210
  protocol_declaration: 'Interface',
211
211
  mixin_declaration: 'Mixin',
212
- extension_declaration: 'Extension',
212
+ extension_declaration: 'Class',
213
213
  class: 'Class',
214
214
  // Ruby `module` declarations map to `Trait` so they participate in the
215
215
  // class-like type registry used by `lookupClassByName` / inheritance
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.10-rc.48",
3
+ "version": "1.6.10-rc.49",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",