@colbymchenry/codegraph 0.9.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +150 -70
  2. package/dist/bin/codegraph.d.ts +1 -0
  3. package/dist/context/index.d.ts +9 -0
  4. package/dist/context/markers.d.ts +19 -0
  5. package/dist/db/migrations.d.ts +1 -1
  6. package/dist/db/queries.d.ts +43 -0
  7. package/dist/db/sqlite-adapter.d.ts +7 -0
  8. package/dist/directory.d.ts +34 -2
  9. package/dist/extraction/astro-extractor.d.ts +79 -0
  10. package/dist/extraction/extraction-version.d.ts +25 -0
  11. package/dist/extraction/function-ref.d.ts +118 -0
  12. package/dist/extraction/grammars.d.ts +7 -1
  13. package/dist/extraction/index.d.ts +34 -0
  14. package/dist/extraction/languages/c-cpp.d.ts +8 -0
  15. package/dist/extraction/languages/csharp.d.ts +22 -0
  16. package/dist/extraction/languages/r.d.ts +3 -0
  17. package/dist/extraction/languages/typescript.d.ts +13 -0
  18. package/dist/extraction/liquid-extractor.d.ts +7 -0
  19. package/dist/extraction/razor-extractor.d.ts +42 -0
  20. package/dist/extraction/tree-sitter-types.d.ts +33 -0
  21. package/dist/extraction/tree-sitter.d.ts +237 -0
  22. package/dist/extraction/vue-extractor.d.ts +15 -0
  23. package/dist/index.d.ts +41 -3
  24. package/dist/installer/instructions-template.d.ts +34 -11
  25. package/dist/installer/targets/opencode.d.ts +9 -1
  26. package/dist/installer/targets/shared.d.ts +14 -0
  27. package/dist/mcp/daemon.d.ts +60 -1
  28. package/dist/mcp/dynamic-boundaries.d.ts +41 -0
  29. package/dist/mcp/ppid-watchdog.d.ts +44 -0
  30. package/dist/mcp/proxy.d.ts +6 -0
  31. package/dist/mcp/server-instructions.d.ts +12 -1
  32. package/dist/mcp/session.d.ts +2 -0
  33. package/dist/mcp/stdin-teardown.d.ts +27 -0
  34. package/dist/mcp/tools.d.ts +110 -49
  35. package/dist/resolution/callback-synthesizer.d.ts +3 -3
  36. package/dist/resolution/frameworks/astro.d.ts +9 -0
  37. package/dist/resolution/frameworks/index.d.ts +1 -0
  38. package/dist/resolution/import-resolver.d.ts +10 -0
  39. package/dist/resolution/index.d.ts +80 -0
  40. package/dist/resolution/name-matcher.d.ts +61 -0
  41. package/dist/resolution/types.d.ts +27 -3
  42. package/dist/resolution/workspace-packages.d.ts +48 -0
  43. package/dist/search/query-utils.d.ts +35 -1
  44. package/dist/sync/watcher.d.ts +124 -32
  45. package/dist/telemetry/index.d.ts +146 -0
  46. package/dist/types.d.ts +25 -2
  47. package/dist/upgrade/index.d.ts +132 -0
  48. package/dist/utils.d.ts +30 -24
  49. package/package.json +7 -7
@@ -0,0 +1,79 @@
1
+ import { ExtractionResult } from '../types';
2
+ /**
3
+ * AstroExtractor - Extracts code relationships from Astro component files
4
+ *
5
+ * Astro files are multi-language: a TypeScript frontmatter block fenced by
6
+ * `---` lines, a JSX-like HTML template, and optional <script>/<style> blocks.
7
+ * Rather than parsing a full Astro grammar, we extract the frontmatter and
8
+ * <script> contents and delegate them to the TypeScript TreeSitterExtractor
9
+ * (Astro processes both as TypeScript by default — no `lang` attr needed).
10
+ *
11
+ * Also extracts function calls from template expressions (`{fn(...)}`) and
12
+ * component usages (`<PascalCase>`) so cross-file edges are captured even
13
+ * when the only reference lives in markup.
14
+ *
15
+ * Every .astro file produces a component node (Astro components are always
16
+ * importable).
17
+ */
18
+ export declare class AstroExtractor {
19
+ private filePath;
20
+ private source;
21
+ private nodes;
22
+ private edges;
23
+ private unresolvedReferences;
24
+ private errors;
25
+ constructor(filePath: string, source: string);
26
+ /**
27
+ * Extract from Astro source
28
+ */
29
+ extract(): ExtractionResult;
30
+ /**
31
+ * Create a component node for the .astro file
32
+ */
33
+ private createComponentNode;
34
+ /**
35
+ * Extract the frontmatter block: the content between the opening `---`
36
+ * fence (first non-blank line of the file) and the closing `---` fence.
37
+ * An unclosed fence is treated as "no frontmatter" rather than swallowing
38
+ * the whole template as TypeScript.
39
+ *
40
+ * Returns the content plus its 0-indexed start line, or null.
41
+ */
42
+ private extractFrontmatter;
43
+ /**
44
+ * Extract <script> blocks from the template portion
45
+ */
46
+ private extractScriptBlocks;
47
+ /**
48
+ * Process frontmatter / script content by delegating to TreeSitterExtractor.
49
+ * Astro treats both as TypeScript by default.
50
+ */
51
+ private processScriptContent;
52
+ /**
53
+ * Line ranges (0-indexed, inclusive) the template scans must skip:
54
+ * the frontmatter block and <script>/<style> blocks.
55
+ */
56
+ private getCoveredRanges;
57
+ /**
58
+ * Extract function calls from Astro template expressions.
59
+ *
60
+ * Astro templates embed JSX-like expressions (`{formatDate(post.date)}`,
61
+ * `class:list={cn(...)}`), so calls frequently live in markup rather than
62
+ * the frontmatter. We scan template lines for `{expression}` groups and
63
+ * extract call patterns from them. A `{` group left open at end-of-line
64
+ * (the pervasive `{posts.map((post) => (` pattern) contributes the calls
65
+ * on its opening line.
66
+ */
67
+ private extractTemplateCalls;
68
+ /**
69
+ * Extract component usages from the Astro template.
70
+ *
71
+ * PascalCase tags like <Layout>, <PostCard /> represent component
72
+ * instantiations — analogous to function calls in imperative code.
73
+ * Lowercase tags are native HTML (Astro does not register kebab-case
74
+ * components the way Vue does, so those are real custom elements and
75
+ * are skipped).
76
+ */
77
+ private extractTemplateComponents;
78
+ }
79
+ //# sourceMappingURL=astro-extractor.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Extraction version
3
+ *
4
+ * A monotonically-increasing integer that identifies the *shape and depth* of
5
+ * what the extractor writes into the graph. Unlike `CURRENT_SCHEMA_VERSION`
6
+ * (which tracks the SQLite table layout and is migrated in place), this tracks
7
+ * the EXTRACTED CONTENT — node kinds, edges, synthesizers, resolver coverage.
8
+ *
9
+ * When an index was built by an older engine whose `EXTRACTION_VERSION` is
10
+ * below the running engine's, the data on disk is structurally fine but
11
+ * *stale*: it's missing whatever a newer extractor would now produce. A schema
12
+ * migration can't backfill that — only a re-index can. So this is the signal
13
+ * `codegraph status` uses to recommend a re-index, and the reason `codegraph
14
+ * upgrade` reminds users to refresh their projects.
15
+ *
16
+ * BUMP THIS when a release changes extraction output enough that existing
17
+ * indexes should be rebuilt to benefit — e.g. a new language/framework
18
+ * extractor, a new dynamic-dispatch synthesizer, a new node/edge kind, or a
19
+ * resolver fix that materially changes which edges exist. Do NOT bump for
20
+ * pure bug fixes, CLI/UX changes, or schema-only migrations. Over-bumping
21
+ * turns the re-index hint into noise — keep it honest (see CLAUDE.md, "Honesty
22
+ * in the product is load-bearing").
23
+ */
24
+ export declare const EXTRACTION_VERSION = 24;
25
+ //# sourceMappingURL=extraction-version.d.ts.map
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Function-as-value capture (#756) — registration-linking for callbacks.
3
+ *
4
+ * A function name used as a VALUE — passed as a call argument
5
+ * (`register_handler(target_cb)`, `signal(SIGINT, handler)`), assigned to a
6
+ * field or function pointer (`o->cb = target_cb`, `OnFire := TargetCb`),
7
+ * placed in a struct/object initializer (`{ .recv_cb = my_cb }`,
8
+ * `{ recv: targetCb }`, `Ops{Cb: targetCb}`), or listed in a function table
9
+ * (`static cb_t table[] = { cb_a, cb_b }`) — is a real dependency that static
10
+ * call extraction misses entirely: `callers(target_cb)` showed nothing but
11
+ * direct calls, so every callback looked dead and its registration sites were
12
+ * invisible to impact analysis.
13
+ *
14
+ * This module captures those value positions during the AST walk as
15
+ * `function_ref` candidates. Capture is table-driven per language (the value
16
+ * positions and wrapper forms differ per grammar — `&fn` in C, `Main::fn` in
17
+ * Java, `::fn` in Kotlin, `#selector(fn)` in Swift, `@TargetCb` in Pascal,
18
+ * `method(:fn)` in Ruby). Candidates are GATED at end-of-file extraction
19
+ * (see `TreeSitterExtractor.flushFnRefCandidates`): only names matching a
20
+ * same-file function/method or an imported binding survive, which bounds
21
+ * volume and keeps precision high. Resolution then matches survivors against
22
+ * function/method nodes ONLY (`matchFunctionRef` in
23
+ * `src/resolution/name-matcher.ts`) and persists them as `references` edges,
24
+ * which `callers`/`impact` already traverse.
25
+ *
26
+ * Deliberately NOT covered (resolving the *dispatch* — `o->cb(x)` → the
27
+ * registered function — needs data-flow through struct fields; a wrong edge
28
+ * is worse than none): indirect-call resolution and `obj.method` member
29
+ * values where `obj` isn't `this`/`self` (the receiver's type is statically
30
+ * unknowable without local data-flow).
31
+ */
32
+ import type { Node as SyntaxNode } from 'web-tree-sitter';
33
+ export interface FnRefCandidate {
34
+ name: string;
35
+ line: number;
36
+ column: number;
37
+ /** Which capture position produced this candidate (gate policy keys on it). */
38
+ mode: CaptureMode;
39
+ /**
40
+ * True when the value was an explicit reference form (`&fn`, `&Cls::m`,
41
+ * `::fn`, `#selector`, `method(:sym)`) rather than a bare identifier —
42
+ * C++'s flush policy keys on it.
43
+ */
44
+ explicitRef: boolean;
45
+ /**
46
+ * Skip the same-file/import name gate for this candidate. Set for PHP
47
+ * string callables in known HOF positions: PHP global functions are
48
+ * referenced cross-file WITHOUT imports (global namespace), so the gate
49
+ * can't see them — the strong positional prior (a string argument to
50
+ * `usort`/`array_map`/…) plus resolution's unique-or-drop rule carry the
51
+ * precision instead.
52
+ */
53
+ skipGate?: boolean;
54
+ }
55
+ /** How to pull candidate value nodes out of a dispatched container node. */
56
+ type CaptureMode = 'args' | 'rhs' | 'value' | 'list' | 'varinit';
57
+ interface CaptureRule {
58
+ mode: CaptureMode;
59
+ /** Field holding the value for rhs/value/varinit (defaults per mode). */
60
+ field?: string;
61
+ }
62
+ export interface FnRefSpec {
63
+ /** Bare identifier node types that can act as a function value. */
64
+ idTypes: Set<string>;
65
+ /** Container node type → how to extract candidate values from it. */
66
+ dispatch: Map<string, CaptureRule>;
67
+ /**
68
+ * Transparent wrapper layers between a container and its values
69
+ * (`argument`, `value_argument`, `literal_element`, `expression_list`…).
70
+ * Value: the field to descend into, or null for "named children".
71
+ * `expression_list` fans out to ALL named children (Go multi-assign).
72
+ */
73
+ layers?: Map<string, string | null>;
74
+ /**
75
+ * Unary wrappers whose operand is the function value — C/C++ `&fn`
76
+ * (pointer_expression), Pascal `@Fn` (exprUnary), Scala eta `fn _`
77
+ * (postfix_expression). Value: operand field, or null for first named child.
78
+ */
79
+ unwrap?: Map<string, string | null>;
80
+ /**
81
+ * Whole-node reference forms needing bespoke name extraction —
82
+ * `method_reference` (Java), `callable_reference` / `navigation_expression`
83
+ * (Kotlin), `selector_expression` (Swift `#selector` / ObjC `@selector`),
84
+ * Ruby `method(:sym)` calls, and `this.method` member forms.
85
+ */
86
+ special?: Set<string>;
87
+ /**
88
+ * Capture modes whose candidates skip the same-file/import gate and rely on
89
+ * resolution's unique-or-drop rule instead. C-family only: an initializer
90
+ * value, function-pointer assignment RHS, or table element is a
91
+ * function-pointer position by construction, and C has no symbol imports —
92
+ * the dominant repo-scale pattern (`server.c`'s command table naming
93
+ * handlers defined across files) would otherwise be invisible. Call
94
+ * arguments stay gated everywhere (locals passed as args dwarf callbacks).
95
+ */
96
+ ungatedModes?: Set<CaptureMode>;
97
+ /**
98
+ * C++ only: in args/rhs/varinit positions, accept ONLY explicit reference
99
+ * forms (`&fn`, `&Cls::method`) — never bare identifiers. C++ codebases are
100
+ * dense with generic free-function/accessor names (`begin`, `end`, `out`,
101
+ * `size`, `data`) that collide with parameters and locals, and out-of-line
102
+ * member definitions extract as function-kind nodes — bare-id matching on
103
+ * fmt was mostly wrong edges. File-scope initializer tables (value/list)
104
+ * still accept bare identifiers, same as C.
105
+ */
106
+ addressOfOnly?: boolean;
107
+ }
108
+ /**
109
+ * Capture specs by language.
110
+ */
111
+ export declare const FN_REF_SPECS: Record<string, FnRefSpec | undefined>;
112
+ /**
113
+ * Extract candidate names from a dispatched container node. Returns the
114
+ * (name, position) pairs of every function-value-shaped expression found.
115
+ */
116
+ export declare function captureFnRefCandidates(container: SyntaxNode, rule: CaptureRule, spec: FnRefSpec, source: string): FnRefCandidate[];
117
+ export {};
118
+ //# sourceMappingURL=function-ref.d.ts.map
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Parser } from 'web-tree-sitter';
9
9
  import { Language } from '../types';
10
- export type GrammarLanguage = Exclude<Language, 'svelte' | 'vue' | 'liquid' | 'yaml' | 'twig' | 'xml' | 'properties' | 'unknown'>;
10
+ export type GrammarLanguage = Exclude<Language, 'svelte' | 'vue' | 'astro' | 'liquid' | 'razor' | 'yaml' | 'twig' | 'xml' | 'properties' | 'unknown'>;
11
11
  /**
12
12
  * File extension to Language mapping
13
13
  */
@@ -18,6 +18,12 @@ export declare const EXTENSION_MAP: Record<string, Language>;
18
18
  * from EXTENSION_MAP so parser support and indexing selection never drift.
19
19
  */
20
20
  export declare function isSourceFile(filePath: string): boolean;
21
+ /**
22
+ * Shopify OS 2.0 JSON template (`templates/*.json`) or section group
23
+ * (`sections/*.json`) — these reference sections by `"type"`, so the Liquid
24
+ * extractor links them. (config/ + locales/ JSON have no section refs.)
25
+ */
26
+ export declare function isShopifyLiquidJson(filePath: string): boolean;
21
27
  /**
22
28
  * Play Framework routes file: the extensionless `conf/routes` (and included
23
29
  * `conf/*.routes`). No grammar — route extraction is done by the Play framework
@@ -53,6 +53,40 @@ export declare function hashContent(content: string): string;
53
53
  * it project code; the explicit `.gitignore` negation is the only opt-in).
54
54
  */
55
55
  export declare function buildDefaultIgnore(rootDir: string): Ignore;
56
+ /**
57
+ * Workspace-scope ignore matcher. Ordinary paths get the root's matcher
58
+ * (built-in defaults + root `.gitignore`); paths inside an EMBEDDED repo get
59
+ * that repo's own matcher (defaults + its root `.gitignore`) — the parent's
60
+ * `.gitignore` hides a child repo from git, not from the index (#514). A
61
+ * directory path (trailing slash) that is an ANCESTOR of an embedded root is
62
+ * never ignored, so directory-pruning callers (the Linux per-directory
63
+ * watcher) still descend to reach the embedded repos.
64
+ *
65
+ * Single source of truth for indexer and watcher scope — they must not diverge.
66
+ */
67
+ export declare class ScopeIgnore {
68
+ private rootMatcher;
69
+ private embedded;
70
+ private defaults;
71
+ constructor(rootMatcher: Ignore, embedded: Array<{
72
+ root: string;
73
+ matcher: Ignore;
74
+ }>);
75
+ ignores(rel: string): boolean;
76
+ }
77
+ /**
78
+ * Build the workspace-scope matcher. When the caller already knows the
79
+ * embedded roots (the scanner discovers them during collection), pass them to
80
+ * skip rediscovery; otherwise they're discovered here (the watcher path).
81
+ */
82
+ export declare function buildScopeIgnore(rootDir: string, embeddedRoots?: Iterable<string>): ScopeIgnore;
83
+ /**
84
+ * Standalone discovery of every embedded repo root under `rootDir` (relative,
85
+ * trailing-slashed) — both the untracked kind (#193) and the gitignored kind
86
+ * (#514), recursively (an embedded repo can embed further repos). Returns []
87
+ * for non-git roots: the filesystem walk handles nested repos there already.
88
+ */
89
+ export declare function discoverEmbeddedRepoRoots(rootDir: string): string[];
56
90
  /**
57
91
  * Recursively scan a directory for source files.
58
92
  *
@@ -1,4 +1,12 @@
1
1
  import type { LanguageExtractor } from '../tree-sitter-types';
2
+ /**
3
+ * Normalize a C++ return type to the bare class name a method could be called
4
+ * on. Unwraps smart-pointer / optional wrappers to their element type
5
+ * (`std::unique_ptr<Widget>` → `Widget`) so a factory's `->method()` resolves on
6
+ * the pointee. Strips cv-qualifiers, `&`/`*`, namespace qualifiers, and other
7
+ * template args. Returns undefined for primitives / void / `auto` / empty.
8
+ */
9
+ export declare function normalizeCppReturnType(raw: string): string | undefined;
2
10
  export declare const cExtractor: LanguageExtractor;
3
11
  export declare const cppExtractor: LanguageExtractor;
4
12
  //# sourceMappingURL=c-cpp.d.ts.map
@@ -1,3 +1,25 @@
1
1
  import type { LanguageExtractor } from '../tree-sitter-types';
2
+ /**
3
+ * Blank C# conditional-compilation directive lines (`#if` / `#elif` / `#else` /
4
+ * `#endif`) before parsing. The vendored tree-sitter-c-sharp grammar mis-parses
5
+ * a `#if` that appears *inside an enum member list* — the canonical
6
+ * multi-targeting shape:
7
+ *
8
+ * enum ReadType {
9
+ * #if HAVE_DATE_TIME_OFFSET
10
+ * ReadAsDateTimeOffset,
11
+ * #endif
12
+ * ReadAsDouble,
13
+ * }
14
+ *
15
+ * It emits an ERROR that, for a nested enum, detaches the *enclosing class's*
16
+ * member list, so most of the class's methods drop out of the index. Removing
17
+ * the directive lines (keeping the guarded code) sidesteps it. Both branches of
18
+ * an `#if/#else` are kept — the same behaviour the previous grammar produced,
19
+ * and the right default for a code graph (index every symbol regardless of
20
+ * build flags). Replacement preserves byte offsets (directive text → spaces,
21
+ * newlines kept) so every symbol's line/column stays exact. (#237)
22
+ */
23
+ export declare function blankCsharpPreprocessorDirectives(source: string): string;
2
24
  export declare const csharpExtractor: LanguageExtractor;
3
25
  //# sourceMappingURL=csharp.d.ts.map
@@ -0,0 +1,3 @@
1
+ import type { LanguageExtractor } from '../tree-sitter-types';
2
+ export declare const rExtractor: LanguageExtractor;
3
+ //# sourceMappingURL=r.d.ts.map
@@ -1,3 +1,16 @@
1
1
  import type { LanguageExtractor } from '../tree-sitter-types';
2
+ import type { Node as SyntaxNode } from 'web-tree-sitter';
3
+ /**
4
+ * A TS/JS class field (`public_field_definition` / `field_definition`) is a
5
+ * METHOD only when its value is callable — an arrow function, a function
6
+ * expression, or a HOF call wrapping one (`onScroll = throttle(() => {…})`),
7
+ * exactly mirroring what `resolveBody` below knows how to walk. Everything
8
+ * else (`public fonts: Fonts;`, `count = 0`, `static defaults = {…}`) is a
9
+ * PROPERTY. Previously every field extracted as method-kind (#808), which
10
+ * misrepresented class shape and defeated kind-based filtering — the reason
11
+ * #756's function-ref resolution had to restrict TS/JS bare identifiers to
12
+ * function targets.
13
+ */
14
+ export declare function classifyTsClassMember(node: SyntaxNode): 'method' | 'property';
2
15
  export declare const typescriptExtractor: LanguageExtractor;
3
16
  //# sourceMappingURL=typescript.d.ts.map
@@ -24,6 +24,13 @@ export declare class LiquidExtractor {
24
24
  * Create a file node for the Liquid template
25
25
  */
26
26
  private createFileNode;
27
+ /**
28
+ * Shopify OS 2.0 JSON template / section group. Both have a `sections` object
29
+ * mapping an id → `{ "type": "<section-name>", ... }`; the `type` names a
30
+ * `sections/<type>.liquid` file. Emit a `references` edge to each, so a section
31
+ * used only from a JSON template (the OS 2.0 norm) is no longer orphaned.
32
+ */
33
+ private extractShopifyJsonSections;
27
34
  /**
28
35
  * Extract {% render 'snippet' %} and {% include 'snippet' %} references
29
36
  */
@@ -0,0 +1,42 @@
1
+ import { ExtractionResult } from '../types';
2
+ export declare class RazorExtractor {
3
+ private filePath;
4
+ private source;
5
+ private nodes;
6
+ private edges;
7
+ private unresolvedReferences;
8
+ private errors;
9
+ constructor(filePath: string, source: string);
10
+ extract(): ExtractionResult;
11
+ private createComponentNode;
12
+ /** Last `.`-segment (`App.ViewModels.RegisterModel` → `RegisterModel`). */
13
+ private lastSegment;
14
+ /**
15
+ * Split a type expression into the capitalized type names it contains — base
16
+ * type plus any generic arguments (`Bar<Foo, Baz>` → `Bar`, `Foo`, `Baz`),
17
+ * each reduced to its last namespace segment. Lowercase/keyword tokens drop out.
18
+ */
19
+ private typeNames;
20
+ private pushRef;
21
+ private extractDirectives;
22
+ private extractComponentTags;
23
+ /**
24
+ * Find the matching `}` for the `{` at `openIdx`, skipping string literals and
25
+ * comments so a brace inside `"{"` / `// }` doesn't throw off the count.
26
+ * Returns the index of the closing brace, or -1 if unbalanced.
27
+ */
28
+ private matchBrace;
29
+ /** `@code { … }` / `@functions { … }` (Blazor) and `@{ … }` (Razor) C# blocks. */
30
+ private extractCodeBlocks;
31
+ /**
32
+ * Delegate each `@code`/`@functions`/`@{` block's C# to the tree-sitter C#
33
+ * extractor and attribute the block's external references (service/DTO calls,
34
+ * `new X()`, type uses) to the component. The block is wrapped in a synthetic
35
+ * class so tree-sitter parses the component's fields/methods in a class context
36
+ * (a Blazor `@code` body compiles into the component's partial class). We keep
37
+ * only the dependency references — coverage just needs the edges to external
38
+ * types, not per-member nodes. Degrades gracefully if the C# grammar isn't loaded.
39
+ */
40
+ private processCodeBlocks;
41
+ }
42
+ //# sourceMappingURL=razor-extractor.d.ts.map
@@ -69,6 +69,15 @@ export interface ExtractorContext {
69
69
  * language-specific details like signatures, visibility, and imports.
70
70
  */
71
71
  export interface LanguageExtractor {
72
+ /**
73
+ * Optional source transform applied immediately before the grammar parses the
74
+ * file. Used to work around grammar gaps that would otherwise corrupt the
75
+ * parse tree (e.g. C# blanks conditional-compilation directive lines the
76
+ * grammar mis-parses inside enum bodies). MUST preserve byte offsets (replace
77
+ * removed text with spaces, keep newlines) so node positions and getNodeText
78
+ * stay correct; the returned string is used for both parsing and extraction.
79
+ */
80
+ preParse?: (source: string) => string;
72
81
  /** Node types that represent functions */
73
82
  functionTypes: string[];
74
83
  /** Node types that represent classes */
@@ -119,6 +128,14 @@ export interface LanguageExtractor {
119
128
  isStatic?: (node: SyntaxNode) => boolean;
120
129
  /** Check if variable declaration is a constant (const vs let/var) */
121
130
  isConst?: (node: SyntaxNode) => boolean;
131
+ /**
132
+ * Extract extra symbol-level modifier keywords to persist on the node's
133
+ * `decorators` list (e.g. Kotlin `expect`/`actual` multiplatform markers).
134
+ * Called generically for every created node; return undefined/[] when none.
135
+ * Used by the resolver to link `expect` declarations to their `actual`
136
+ * implementations across source sets.
137
+ */
138
+ extractModifiers?: (node: SyntaxNode) => string[] | undefined;
122
139
  /** Additional node types to treat as class declarations (e.g. Dart: 'mixin_declaration') */
123
140
  extraClassNodeTypes?: string[];
124
141
  /** Whether methods can be top-level without enclosing class (Go: true) */
@@ -135,6 +152,14 @@ export interface LanguageExtractor {
135
152
  * for multiple concepts (e.g. Swift uses class_declaration for classes, structs, and enums).
136
153
  */
137
154
  classifyClassNode?: (node: SyntaxNode) => 'class' | 'struct' | 'enum' | 'interface' | 'trait';
155
+ /**
156
+ * Classify a methodTypes node when the grammar reuses one node type for
157
+ * both callable and data members (#808): TS/JS class FIELDS
158
+ * (`public_field_definition` / `field_definition`) are methods only when
159
+ * their value is callable (`onClick = () => {}`); a plain field
160
+ * (`public fonts: Fonts;`, `count = 0`) is a property. Default: 'method'.
161
+ */
162
+ classifyMethodNode?: (node: SyntaxNode) => 'method' | 'property';
138
163
  /**
139
164
  * Resolve the body node for a function/method/class when it's not a child field.
140
165
  * (e.g. Dart puts function_body as a sibling, not a child.)
@@ -156,6 +181,14 @@ export interface LanguageExtractor {
156
181
  * When present, the receiver type is included in the qualified name for better searchability.
157
182
  */
158
183
  getReceiverType?: (node: SyntaxNode, source: string) => string | undefined;
184
+ /**
185
+ * Extract a function/method's normalized return type name (bare class name,
186
+ * smart-pointer pointee unwrapped), stored on the node as `returnType`. Used
187
+ * by C/C++ so resolution can infer a chained receiver's type from what the
188
+ * inner call returns (`Foo::instance().bar()` → resolve `bar` on `Foo`,
189
+ * issue #645). Return undefined for primitives / void / constructors.
190
+ */
191
+ getReturnType?: (node: SyntaxNode, source: string) => string | undefined;
159
192
  /**
160
193
  * Resolve the actual node kind for a type alias declaration.
161
194
  * Used by Go where `type_spec` is the named declaration wrapper for structs/interfaces: