gitnexus 1.6.12-rc.2 → 1.6.12-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 (188) hide show
  1. package/dist/_shared/graph/types.d.ts +1 -1
  2. package/dist/_shared/graph/types.d.ts.map +1 -1
  3. package/dist/_shared/language-detection.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.js +2 -0
  5. package/dist/_shared/language-detection.js.map +1 -1
  6. package/dist/_shared/languages.d.ts +1 -0
  7. package/dist/_shared/languages.d.ts.map +1 -1
  8. package/dist/_shared/languages.js +1 -0
  9. package/dist/_shared/languages.js.map +1 -1
  10. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  11. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  12. package/dist/_shared/lbug/schema-constants.js +2 -0
  13. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  14. package/dist/_shared/scope-resolution/language-classification.d.ts +2 -1
  15. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  16. package/dist/_shared/scope-resolution/language-classification.js +3 -1
  17. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  18. package/dist/_shared/scope-resolution/registries/class-registry.d.ts +3 -3
  19. package/dist/_shared/scope-resolution/registries/class-registry.js +3 -3
  20. package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
  21. package/dist/_shared/scope-resolution/registries/context.js +2 -0
  22. package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
  23. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/resolve-type-ref.js +2 -0
  25. package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
  26. package/dist/cli/analyze-config.d.ts +2 -2
  27. package/dist/cli/analyze-config.js +10 -33
  28. package/dist/cli/doctor.js +6 -4
  29. package/dist/cli/eval-server.js +13 -1
  30. package/dist/cli/i18n/en.d.ts +4 -2
  31. package/dist/cli/i18n/en.js +4 -2
  32. package/dist/cli/i18n/resources.d.ts +6 -2
  33. package/dist/cli/i18n/zh-CN.d.ts +2 -0
  34. package/dist/cli/i18n/zh-CN.js +4 -2
  35. package/dist/core/analysis-feature-registry.d.ts +1 -1
  36. package/dist/core/analysis-feature-registry.js +2 -0
  37. package/dist/core/auto-sync/starter.js +2 -2
  38. package/dist/core/embeddings/ast-utils.js +8 -3
  39. package/dist/core/embeddings/chunker.js +67 -10
  40. package/dist/core/embeddings/embedding-pipeline.d.ts +1 -1
  41. package/dist/core/embeddings/embedding-pipeline.js +1 -1
  42. package/dist/core/embeddings/structural-extractor.js +2 -2
  43. package/dist/core/embeddings/types.d.ts +4 -2
  44. package/dist/core/embeddings/types.js +18 -0
  45. package/dist/core/git-ref.d.ts +22 -0
  46. package/dist/core/git-ref.js +114 -0
  47. package/dist/core/git-staleness.js +14 -0
  48. package/dist/core/group/extractors/graphql-extractor.d.ts +1 -1
  49. package/dist/core/group/extractors/graphql-extractor.js +149 -13
  50. package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
  51. package/dist/core/group/extractors/manifest-extractor.js +2 -2
  52. package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +5 -8
  53. package/dist/core/ingestion/content-language-classification.d.ts +10 -0
  54. package/dist/core/ingestion/content-language-classification.js +30 -0
  55. package/dist/core/ingestion/filesystem-walker.d.ts +1 -0
  56. package/dist/core/ingestion/filesystem-walker.js +1 -1
  57. package/dist/core/ingestion/import-resolvers/node-workspace-packages.js +3 -2
  58. package/dist/core/ingestion/language-config.d.ts +82 -13
  59. package/dist/core/ingestion/language-config.js +217 -13
  60. package/dist/core/ingestion/language-provider.d.ts +88 -1
  61. package/dist/core/ingestion/languages/index.d.ts +7 -0
  62. package/dist/core/ingestion/languages/index.js +30 -1
  63. package/dist/core/ingestion/languages/objective-c/analysis-features.d.ts +10 -0
  64. package/dist/core/ingestion/languages/objective-c/analysis-features.js +19 -0
  65. package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.d.ts +13 -0
  66. package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.js +124 -0
  67. package/dist/core/ingestion/languages/objective-c/facts.d.ts +148 -0
  68. package/dist/core/ingestion/languages/objective-c/facts.js +1150 -0
  69. package/dist/core/ingestion/languages/objective-c/import-target.d.ts +11 -0
  70. package/dist/core/ingestion/languages/objective-c/import-target.js +122 -0
  71. package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.d.ts +24 -0
  72. package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.js +261 -0
  73. package/dist/core/ingestion/languages/objective-c/resolution-config.d.ts +41 -0
  74. package/dist/core/ingestion/languages/objective-c/resolution-config.js +282 -0
  75. package/dist/core/ingestion/languages/objective-c/scope-resolver.d.ts +2 -0
  76. package/dist/core/ingestion/languages/objective-c/scope-resolver.js +503 -0
  77. package/dist/core/ingestion/languages/objective-c.d.ts +2 -0
  78. package/dist/core/ingestion/languages/objective-c.js +300 -0
  79. package/dist/core/ingestion/languages/typescript/query.d.ts +31 -0
  80. package/dist/core/ingestion/languages/typescript/query.js +7 -1
  81. package/dist/core/ingestion/languages/typescript/tsconfig.js +3 -2
  82. package/dist/core/ingestion/languages/typescript.js +1 -1
  83. package/dist/core/ingestion/languages/zig/query.d.ts +26 -0
  84. package/dist/core/ingestion/languages/zig/query.js +61 -1
  85. package/dist/core/ingestion/languages/zig/range-binding.d.ts +8 -0
  86. package/dist/core/ingestion/languages/zig/range-binding.js +24 -0
  87. package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +3 -2
  88. package/dist/core/ingestion/languages/zig/scope-resolver.js +18 -5
  89. package/dist/core/ingestion/languages/zig/this-alias-bindings.d.ts +58 -0
  90. package/dist/core/ingestion/languages/zig/this-alias-bindings.js +176 -0
  91. package/dist/core/ingestion/languages/zig/workspace-static-gating.d.ts +8 -0
  92. package/dist/core/ingestion/languages/zig/workspace-static-gating.js +82 -0
  93. package/dist/core/ingestion/model/registration-table.d.ts +3 -3
  94. package/dist/core/ingestion/model/registration-table.js +9 -5
  95. package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
  96. package/dist/core/ingestion/model/symbol-table.js +2 -0
  97. package/dist/core/ingestion/model/type-registry.d.ts +1 -1
  98. package/dist/core/ingestion/parsing-processor.d.ts +22 -6
  99. package/dist/core/ingestion/parsing-processor.js +39 -20
  100. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +9 -1
  101. package/dist/core/ingestion/pipeline-phases/parse-impl.js +307 -96
  102. package/dist/core/ingestion/pipeline-phases/parse-round-budget.d.ts +42 -0
  103. package/dist/core/ingestion/pipeline-phases/parse-round-budget.js +50 -0
  104. package/dist/core/ingestion/pipeline-phases/parse.d.ts +7 -1
  105. package/dist/core/ingestion/scope-extractor.js +4 -0
  106. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +13 -0
  107. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +2 -0
  108. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +2 -0
  109. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +78 -5
  110. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +262 -7
  111. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +5 -2
  112. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  113. package/dist/core/ingestion/scope-resolution/pipeline/run.js +10 -1
  114. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +39 -3
  115. package/dist/core/ingestion/scope-resolution/scope/walkers.js +82 -3
  116. package/dist/core/ingestion/scope-resolution/value-ref-edges.d.ts +14 -0
  117. package/dist/core/ingestion/scope-resolution/value-ref-edges.js +14 -0
  118. package/dist/core/ingestion/tree-sitter-queries.js +2 -0
  119. package/dist/core/ingestion/utils/symbol-labels.js +2 -0
  120. package/dist/core/ingestion/workers/parse-worker.d.ts +1 -1
  121. package/dist/core/ingestion/workers/parse-worker.js +63 -3
  122. package/dist/core/ingestion/workers/worker-pool.d.ts +56 -2
  123. package/dist/core/ingestion/workers/worker-pool.js +117 -26
  124. package/dist/core/lbug/csv-generator.js +2 -0
  125. package/dist/core/lbug/schema.d.ts +3 -1
  126. package/dist/core/lbug/schema.js +27 -0
  127. package/dist/core/search/fts-indexes.js +13 -4
  128. package/dist/core/search/fts-schema.js +2 -0
  129. package/dist/core/tree-sitter/parser-loader.js +10 -0
  130. package/dist/core/tree-sitter/vendored-grammars.d.ts +1 -1
  131. package/dist/core/tree-sitter/vendored-grammars.js +2 -1
  132. package/dist/mcp/local/local-backend.d.ts +33 -0
  133. package/dist/mcp/local/local-backend.js +166 -5
  134. package/dist/mcp/tools.js +6 -4
  135. package/dist/server/analyze-job.d.ts +19 -1
  136. package/dist/server/analyze-job.js +14 -3
  137. package/dist/server/analyze-launch.d.ts +14 -0
  138. package/dist/server/analyze-launch.js +59 -14
  139. package/dist/server/analyze-worker-ipc.d.ts +6 -5
  140. package/dist/server/analyze-worker-ipc.js +4 -0
  141. package/dist/server/api.js +68 -21
  142. package/dist/server/git-clone.d.ts +38 -5
  143. package/dist/server/git-clone.js +216 -38
  144. package/dist/server/repo-projection.d.ts +88 -0
  145. package/dist/server/repo-projection.js +53 -0
  146. package/dist/storage/file-lock.js +5 -3
  147. package/dist/storage/parse-cache.js +32 -1
  148. package/dist/storage/parsedfile-store.js +53 -1
  149. package/dist/storage/v8-sidecar.d.ts +11 -0
  150. package/dist/storage/v8-sidecar.js +15 -7
  151. package/dist/utils/process-identity.d.ts +13 -0
  152. package/dist/utils/process-identity.js +18 -0
  153. package/package.json +1 -1
  154. package/scripts/build-tree-sitter-grammars.cjs +4 -3
  155. package/vendor/tree-sitter-objc/LICENSE +21 -0
  156. package/vendor/tree-sitter-objc/README.md +18 -0
  157. package/vendor/tree-sitter-objc/binding.gyp +35 -0
  158. package/vendor/tree-sitter-objc/bindings/node/binding.cc +19 -0
  159. package/vendor/tree-sitter-objc/bindings/node/binding_test.js +9 -0
  160. package/vendor/tree-sitter-objc/bindings/node/index.d.ts +27 -0
  161. package/vendor/tree-sitter-objc/bindings/node/index.js +11 -0
  162. package/vendor/tree-sitter-objc/grammar.js +1286 -0
  163. package/vendor/tree-sitter-objc/package.json +56 -0
  164. package/vendor/tree-sitter-objc/prebuilds/SHA256SUMS +6 -0
  165. package/vendor/tree-sitter-objc/prebuilds/darwin-arm64/tree-sitter-objc.node +0 -0
  166. package/vendor/tree-sitter-objc/prebuilds/darwin-x64/tree-sitter-objc.node +0 -0
  167. package/vendor/tree-sitter-objc/prebuilds/linux-arm64/tree-sitter-objc.node +0 -0
  168. package/vendor/tree-sitter-objc/prebuilds/linux-x64/tree-sitter-objc.node +0 -0
  169. package/vendor/tree-sitter-objc/prebuilds/win32-arm64/tree-sitter-objc.node +0 -0
  170. package/vendor/tree-sitter-objc/prebuilds/win32-x64/tree-sitter-objc.node +0 -0
  171. package/vendor/tree-sitter-objc/queries/folds.scm +20 -0
  172. package/vendor/tree-sitter-objc/queries/highlights.scm +216 -0
  173. package/vendor/tree-sitter-objc/queries/indents.scm +1 -0
  174. package/vendor/tree-sitter-objc/queries/injections.scm +10 -0
  175. package/vendor/tree-sitter-objc/queries/locals.scm +1 -0
  176. package/vendor/tree-sitter-objc/src/grammar.json +16292 -0
  177. package/vendor/tree-sitter-objc/src/node-types.json +7524 -0
  178. package/vendor/tree-sitter-objc/src/parser.c +684023 -0
  179. package/vendor/tree-sitter-objc/src/tree_sitter/alloc.h +54 -0
  180. package/vendor/tree-sitter-objc/src/tree_sitter/array.h +291 -0
  181. package/vendor/tree-sitter-objc/src/tree_sitter/parser.h +266 -0
  182. package/vendor/tree-sitter-objc/tree-sitter-objc.wasm +0 -0
  183. package/vendor/tree-sitter-objc/tree-sitter.json +38 -0
  184. package/web/assets/{agent-BMRqXorA.js → agent-C2n33ANd.js} +1 -1
  185. package/web/assets/{index-Dj3vQOHK.js → index-CHJoW_P1.js} +18 -18
  186. package/web/assets/src-jc8Ffy3T.js +1 -0
  187. package/web/index.html +2 -2
  188. package/web/assets/src-Df5C1Nz4.js +0 -1
@@ -11,17 +11,14 @@
11
11
  * Conservative by design: we only tag an edge when we can prove the
12
12
  * gating expression evaluates to `false`. Anything ambiguous → live.
13
13
  *
14
- * Scope of v1:
14
+ * Supported scope:
15
15
  *
16
16
  * (a) **File-local** consts (`pub const FOO = false;`, plus const-to-const
17
17
  * aliases up to 5 hops), built once per file by `buildZigBoolConstMap`.
18
- * (b) **Cross-file** (`const cfg = @import("./cfg.zig"); if (cfg.FOO)`) is
19
- * NOT resolved yet. The evaluator keeps the seam for it (`importAliases`
20
- * + `lookupBoolsForPath`, consumed by the `field_expression` case), but
21
- * the only caller passes an empty alias map and a lookup that always
22
- * returns `undefined`, because the capture emitter runs in the parse
23
- * worker and sees only the current file. Tracked in #3162. Until then
24
- * every `cfg.FOO` condition folds to unknown, i.e. live.
18
+ * (b) **Cross-file** direct imports (`const cfg = @import("./cfg.zig");
19
+ * if (cfg.FOO)`) are enriched after per-file extraction. The workspace
20
+ * caller supplies `importAliases` and `lookupBoolsForPath`; the parse
21
+ * worker still uses empty/undefined inputs and remains file-local.
25
22
  *
26
23
  * Also out of scope: multi-hop member access (`cfg.sub.FOO`), re-exported
27
24
  * consts, runtime-evaluated bools (`const FOO = computeIt();`), and
@@ -0,0 +1,10 @@
1
+ import type { SupportedLanguages } from '../../_shared/index.js';
2
+ /**
3
+ * Classify files whose language cannot be determined from their extension.
4
+ *
5
+ * Source text is retained only for the duration of each individual read and
6
+ * classification. The returned map deliberately contains language results,
7
+ * not source text, so downstream phases can reuse the decision without
8
+ * holding every candidate header in memory or rereading it to classify again.
9
+ */
10
+ export declare function classifyContentLanguages(repoPath: string, relativePaths: readonly string[]): Promise<ReadonlyMap<string, SupportedLanguages | null>>;
@@ -0,0 +1,30 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { mapConcurrent } from '../../lib/utils.js';
4
+ import { READ_CONCURRENCY } from './filesystem-walker.js';
5
+ import { getLanguageForFileContent } from './languages/index.js';
6
+ /**
7
+ * Classify files whose language cannot be determined from their extension.
8
+ *
9
+ * Source text is retained only for the duration of each individual read and
10
+ * classification. The returned map deliberately contains language results,
11
+ * not source text, so downstream phases can reuse the decision without
12
+ * holding every candidate header in memory or rereading it to classify again.
13
+ */
14
+ export async function classifyContentLanguages(repoPath, relativePaths) {
15
+ const classifications = new Map();
16
+ const results = await mapConcurrent(relativePaths, async (relativePath) => {
17
+ const sourceText = await fs.readFile(path.join(repoPath, relativePath), 'utf-8');
18
+ return {
19
+ path: relativePath,
20
+ language: getLanguageForFileContent(relativePath, sourceText),
21
+ };
22
+ }, { concurrency: READ_CONCURRENCY });
23
+ // An unreadable file yields `undefined` from mapConcurrent. Leave it absent
24
+ // so the caller retains the existing filename-based fallback behavior.
25
+ for (const result of results) {
26
+ if (result !== undefined)
27
+ classifications.set(result.path, result.language);
28
+ }
29
+ return classifications;
30
+ }
@@ -7,6 +7,7 @@ export interface ScannedFile {
7
7
  export interface FilePath {
8
8
  path: string;
9
9
  }
10
+ export declare const READ_CONCURRENCY = 32;
10
11
  export interface WalkRepositoryOptions {
11
12
  /**
12
13
  * Suppress the operator-facing large-file notice. Set by read-only callers
@@ -6,7 +6,7 @@ import { glob } from 'glob';
6
6
  import { createIgnoreFilter } from '../../config/ignore-service.js';
7
7
  import { mapConcurrent } from '../../lib/utils.js';
8
8
  import { logger } from '../logger.js';
9
- const READ_CONCURRENCY = 32;
9
+ export const READ_CONCURRENCY = 32;
10
10
  const ANALYZE_PROGRESS_ACTIVE_ENV = 'GITNEXUS_ANALYZE_PROGRESS_ACTIVE';
11
11
  const DECLARATION_COMPANION_SUFFIXES = [
12
12
  { declaration: '.d.ts', implementations: ['.ts', '.tsx'] },
@@ -268,13 +268,14 @@ export async function loadNodeWorkspacePackages(repoRoot) {
268
268
  const scope = await loadWorkspaceScope(repoRoot);
269
269
  const byName = new Map();
270
270
  const queue = [{ dir: repoRoot, depth: 0 }];
271
+ let queueHead = 0;
271
272
  let dirsScanned = 0;
272
- while (queue.length > 0) {
273
+ while (queueHead < queue.length) {
273
274
  if (dirsScanned >= SCAN_MAX_DIRS) {
274
275
  logger.warn(`[node] package.json scan of ${repoRoot} hit the ${SCAN_MAX_DIRS}-directory cap; workspace packages below it will not resolve`);
275
276
  break;
276
277
  }
277
- const { dir, depth } = queue.shift();
278
+ const { dir, depth } = queue[queueHead++];
278
279
  dirsScanned++;
279
280
  let entries;
280
281
  try {
@@ -71,13 +71,24 @@ export interface SwiftPackageConfig {
71
71
  /** Zig package config parsed from build.zig.zon and the root build.zig */
72
72
  export interface ZigBuildZonConfig {
73
73
  /**
74
- * Map of dependency name -> the raw `.path = "..."` value, exactly as
75
- * written in build.zig.zon (relative to the repo root, and possibly
76
- * escaping it: `../local_dep`). Consumers normalize — see
77
- * `normalizeZigDepPath` below, which rejects absolute
78
- * and repo-escaping values. `.url`-based deps cannot be resolved to a
79
- * repo-local file (they unpack into a build cache outside the repo) and so
80
- * are not included here.
74
+ * Map of dependency name -> the dep's directory, in one of two spellings
75
+ * depending on which package this config describes:
76
+ *
77
+ * - ROOT package (`pkg === ''`): the raw `.path = "..."` value, exactly as
78
+ * written in build.zig.zon (relative to the repo root, and possibly
79
+ * escaping it: `../local_dep`). This is what `parseZigBuildZon` promises
80
+ * and what its tests pin.
81
+ * - NESTED package: repo-relative and already normalized, because a nested
82
+ * package's `.path` is written relative to ITS directory and means
83
+ * nothing against the repo-relative keys consumers match on
84
+ * (`packages/app`'s `../core` is stored as `packages/core`). A dep
85
+ * escaping the REPO root is dropped rather than stored.
86
+ *
87
+ * Either spelling is safe to hand to `normalizeZigDepPath` below — it rejects
88
+ * absolute and repo-escaping values and is idempotent on an already
89
+ * normalized one, which is what `resolveZigImportInternal` relies on.
90
+ * `.url`-based deps cannot be resolved to a repo-local file (they unpack into
91
+ * a build cache outside the repo) and so are not included here.
81
92
  */
82
93
  pathDeps: Map<string, string>;
83
94
  /**
@@ -116,6 +127,27 @@ export interface ZigBuildZonConfig {
116
127
  */
117
128
  buildModules?: readonly ZigBuildModule[];
118
129
  }
130
+ /**
131
+ * One Zig build package: the directory whose `build.zig` / `build.zig.zon`
132
+ * declare the config, and that config with every path REPO-relative.
133
+ *
134
+ * A Zig module's import table is declared by the `build.zig` of the package it
135
+ * belongs to, so a repo holding several packages holds several import tables —
136
+ * the same shape a TypeScript monorepo has with a `tsconfig.json` per package.
137
+ */
138
+ export interface ZigPackageScope {
139
+ /** Repo-relative directory the package governs (`''` for the repo root). */
140
+ readonly dir: string;
141
+ readonly config: ZigBuildZonConfig;
142
+ }
143
+ /**
144
+ * Every Zig build package in the repo, indexed so the nearest one to a file
145
+ * wins — the `TsconfigIndex` analogue, and for the same reason.
146
+ */
147
+ export interface ZigWorkspaceIndex {
148
+ /** Deepest-first, so the first `dir` that prefixes a file path governs it. */
149
+ readonly packages: readonly ZigPackageScope[];
150
+ }
119
151
  /** One build module of the root `build.zig` — see `ZigBuildZonConfig.buildModules`. */
120
152
  export interface ZigBuildModule {
121
153
  /** The `addModule("<name>", …)` name; absent for `createModule` bindings
@@ -189,14 +221,51 @@ export declare function loadSwiftPackageConfig(repoRoot: string): Promise<SwiftP
189
221
  * string literals — a commented-out `.path` or a `}` inside a comment
190
222
  * or string cannot declare a dep or truncate the block.
191
223
  */
192
- export declare function loadZigBuildConfig(repoRoot: string): Promise<ZigBuildZonConfig | null>;
224
+ export declare function loadZigBuildConfig(repoRoot: string, packageDir?: string): Promise<ZigBuildZonConfig | null>;
193
225
  /**
194
- * Normalize a `.path` value from build.zig.zon into a repo-relative form.
195
- * Returns null for paths that escape the repo root (start with `..`) or
196
- * are absolute — those point to files we don't index. `.` / `./` normalize
197
- * to the empty string (the repo root itself). Shared with the import
198
- * resolver so both sides agree on which deps are in-repo.
226
+ * The Zig build package governing `filePath` — the nearest one at or above it.
227
+ *
228
+ * A Zig module's import table is declared by the `build.zig` of the package the
229
+ * file belongs to, so the nearest enclosing package is the faithful reading of
230
+ * `@import("name")` at that site, exactly as `tsconfigFor` reads a non-relative
231
+ * specifier against the nearest enclosing project.
232
+ *
233
+ * There is deliberately NO fall-through to an enclosing package when the nearest
234
+ * one does not bind the name. Falling through is how a vendored dependency's
235
+ * `@import("config")` silently resolved to the outer repo's `config` module —
236
+ * the same failure `loadTsconfigIndex` documents for a package whose own
237
+ * tsconfig declares no `baseUrl`, and the same failure the per-module import
238
+ * tables in `resolveZigImportInternal` already exist to prevent one level down.
239
+ */
240
+ export declare function zigPackageFor(index: ZigWorkspaceIndex | null | undefined, filePath: string): ZigBuildZonConfig | null;
241
+ /**
242
+ * Load every Zig build package in the repo, nearest-first.
243
+ *
244
+ * Called with no `packageDir` — which is how every call site read it before
245
+ * this function existed — `loadZigBuildConfig` reads the ROOT `build.zig` /
246
+ * `build.zig.zon` and nothing else. That is the whole configuration of a
247
+ * single-package repo and none of the configuration of a monorepo: a repo
248
+ * laying its packages out as `packages/<name>/build.zig` has no root build
249
+ * files at all, so the loader answers `null` and EVERY bare
250
+ * `@import("<module>")` in it goes unresolved — cross-file resolution silently
251
+ * degrades to relative imports only. Measured on a two-package fixture:
252
+ * `config = null`, `@import("core")` → `null`.
253
+ *
254
+ * The loader itself is not root-bound any more: this function is what supplies
255
+ * it a `packageDir`, one per package below.
256
+ *
257
+ * So the packages are discovered the way tsconfigs are (`findTsconfigFiles`):
258
+ * one bounded breadth-first walk that skips the hardcoded ignore set, then
259
+ * deepest-first ordering so `zigPackageFor` can take the first match.
260
+ *
261
+ * Called from `ScopeResolver.loadResolutionConfig`, which the orchestrator runs
262
+ * once per LANGUAGE workspace pass — so the walk happens only for repos that
263
+ * actually contain Zig. `loadImportConfigs`, which runs unconditionally for
264
+ * every repo, keeps calling `loadZigBuildConfig` for the root package alone;
265
+ * that is the same split TypeScript already has between the cheap
266
+ * `loadTsconfigPaths` and the repo-walking `loadTsconfigIndex`.
199
267
  */
268
+ export declare function loadZigWorkspaceIndex(repoRoot: string): Promise<ZigWorkspaceIndex | null>;
200
269
  export declare function normalizeZigDepPath(depPath: string): string | null;
201
270
  /**
202
271
  * The `root_source_file` paths a `build.zig` declares, dep-relative, with the
@@ -3,6 +3,7 @@ import { createReadStream } from 'fs';
3
3
  import { createInterface } from 'readline';
4
4
  import path from 'path';
5
5
  import { isDev } from './utils/env.js';
6
+ import { isHardcodedIgnoredDirectoryAtPath } from '../../config/ignore-service.js';
6
7
  import { mapConcurrent } from '../../lib/utils.js';
7
8
  import { logger } from '../logger.js';
8
9
  function normalizeComposerDirectory(baseDir, directory) {
@@ -475,10 +476,18 @@ export async function loadSwiftPackageConfig(repoRoot) {
475
476
  * string literals — a commented-out `.path` or a `}` inside a comment
476
477
  * or string cannot declare a dep or truncate the block.
477
478
  */
478
- export async function loadZigBuildConfig(repoRoot) {
479
+ export async function loadZigBuildConfig(repoRoot, packageDir = '') {
480
+ // Every path this function returns is REPO-relative, because that is the
481
+ // keyspace `allFilePaths` uses. The parsers below answer package-relative, so
482
+ // a nested package rebases them through `inPackage`. For the root package
483
+ // (`packageDir === ''`) the prefix is empty and every value is byte-identical
484
+ // to what this function returned before nested packages existed.
485
+ const pkg = packageDir === '' ? '' : `${packageDir}/`;
486
+ const inPackage = (relToPackage) => `${pkg}${relToPackage}`;
487
+ const packageFile = (name) => path.join(repoRoot, packageDir, name);
479
488
  let config = null;
480
489
  try {
481
- const raw = await fs.readFile(path.join(repoRoot, 'build.zig.zon'), 'utf-8');
490
+ const raw = await fs.readFile(packageFile('build.zig.zon'), 'utf-8');
482
491
  config = parseZigBuildZon(raw);
483
492
  }
484
493
  catch {
@@ -490,10 +499,11 @@ export async function loadZigBuildConfig(repoRoot) {
490
499
  let rootModules;
491
500
  let rootBuildZig = null;
492
501
  try {
493
- rootBuildZig = await fs.readFile(path.join(repoRoot, 'build.zig'), 'utf-8');
502
+ rootBuildZig = await fs.readFile(packageFile('build.zig'), 'utf-8');
494
503
  const parsed = parseZigRootModules(rootBuildZig);
495
- if (parsed.size > 0)
496
- rootModules = parsed;
504
+ if (parsed.size > 0) {
505
+ rootModules = new Map(Array.from(parsed, ([name, root]) => [name, inPackage(root)]));
506
+ }
497
507
  }
498
508
  catch {
499
509
  // No root build.zig — nothing to declare.
@@ -502,7 +512,7 @@ export async function loadZigBuildConfig(repoRoot) {
502
512
  if (rootBuildZig === null)
503
513
  return null;
504
514
  // No zon: no path deps, so `dep.module(…)` operands resolve to nothing.
505
- const buildModules = parseZigBuildModules(rootBuildZig);
515
+ const buildModules = rebaseZigBuildModules(parseZigBuildModules(rootBuildZig), inPackage);
506
516
  if (!rootModules && buildModules.length === 0)
507
517
  return null;
508
518
  return {
@@ -519,10 +529,25 @@ export async function loadZigBuildConfig(repoRoot) {
519
529
  // Per path dep: the modules its build.zig NAMES (`addModule("core", …)`),
520
530
  // repo-relative — what a root-build.zig `dep.module("core")` operand means.
521
531
  const depModules = new Map();
532
+ // A nested package's `.path` values are written relative to ITS directory, so
533
+ // they are rebased here and stored repo-relative; `resolveZigImportInternal`
534
+ // then reads them through the same `normalizeZigDepPath`, which is idempotent
535
+ // on an already-normalized value. A dep that escapes the REPO root (not merely
536
+ // the package) resolves to nothing and is dropped. The root package keeps its
537
+ // raw spelling, which is what `parseZigBuildZon` promises and its tests pin.
538
+ const pathDeps = pkg === '' ? config.pathDeps : new Map();
522
539
  for (const [depName, depPath] of config.pathDeps) {
523
- const rel = normalizeZigDepPath(depPath);
540
+ // Asked of the value AS WRITTEN, before the package prefix goes on: an
541
+ // absolute `.path` points outside the repository whichever package declared
542
+ // it, and prefixing hides that from `normalizeZigDepPath`. See
543
+ // `isAbsoluteZigDepPath`.
544
+ if (isAbsoluteZigDepPath(depPath))
545
+ continue;
546
+ const rel = normalizeZigDepPath(`${pkg}${depPath}`);
524
547
  if (rel === null)
525
548
  continue;
549
+ if (pkg !== '')
550
+ pathDeps.set(depName, rel);
526
551
  let buildZig;
527
552
  try {
528
553
  buildZig = await fs.readFile(path.join(repoRoot, rel, 'build.zig'), 'utf-8');
@@ -542,14 +567,169 @@ export async function loadZigBuildConfig(repoRoot) {
542
567
  if (named.size > 0)
543
568
  depModules.set(depName, named);
544
569
  }
545
- const buildModules = rootBuildZig === null ? [] : parseZigBuildModules(rootBuildZig, depModules);
570
+ const buildModules = rootBuildZig === null
571
+ ? []
572
+ : rebaseZigBuildModules(parseZigBuildModules(rootBuildZig, depModules), inPackage, depModules);
546
573
  return {
547
574
  ...config,
575
+ pathDeps,
548
576
  ...(moduleRoots.size > 0 ? { moduleRoots } : {}),
549
577
  ...(rootModules ? { rootModules } : {}),
550
578
  ...(buildModules.length > 0 ? { buildModules } : {}),
551
579
  };
552
580
  }
581
+ /**
582
+ * Rebase a package's own build modules to repo-relative paths.
583
+ *
584
+ * `parseZigBuildModules` answers package-relative for everything it read out of
585
+ * the `build.zig` it was handed, with one exception: an alias resolved through
586
+ * `depModules` (`addImport("api", dep.module("core"))`) is already repo-relative,
587
+ * because `depModules` was built that way. Prefixing that a second time would
588
+ * point the alias at a path no file has. The already-repo-relative values are
589
+ * therefore identified by membership in `depModules`, not guessed at from their
590
+ * shape.
591
+ */
592
+ function rebaseZigBuildModules(modules, inPackage, depModules) {
593
+ if (inPackage('') === '')
594
+ return [...modules];
595
+ const fromDep = new Set();
596
+ for (const named of depModules?.values() ?? [])
597
+ for (const root of named.values())
598
+ fromDep.add(root);
599
+ return modules.map((mod) => ({
600
+ ...(mod.name !== undefined ? { name: mod.name } : {}),
601
+ root: inPackage(mod.root),
602
+ imports: new Map(Array.from(mod.imports, ([alias, root]) => [
603
+ alias,
604
+ fromDep.has(root) ? root : inPackage(root),
605
+ ])),
606
+ }));
607
+ }
608
+ /** Bounds for the package walk, mirroring the tsconfig scan. */
609
+ const ZIG_SCAN_MAX_DIRS = 20_000;
610
+ const ZIG_SCAN_MAX_DEPTH = 24;
611
+ /**
612
+ * The Zig build package governing `filePath` — the nearest one at or above it.
613
+ *
614
+ * A Zig module's import table is declared by the `build.zig` of the package the
615
+ * file belongs to, so the nearest enclosing package is the faithful reading of
616
+ * `@import("name")` at that site, exactly as `tsconfigFor` reads a non-relative
617
+ * specifier against the nearest enclosing project.
618
+ *
619
+ * There is deliberately NO fall-through to an enclosing package when the nearest
620
+ * one does not bind the name. Falling through is how a vendored dependency's
621
+ * `@import("config")` silently resolved to the outer repo's `config` module —
622
+ * the same failure `loadTsconfigIndex` documents for a package whose own
623
+ * tsconfig declares no `baseUrl`, and the same failure the per-module import
624
+ * tables in `resolveZigImportInternal` already exist to prevent one level down.
625
+ */
626
+ export function zigPackageFor(index, filePath) {
627
+ if (index === null || index === undefined)
628
+ return null;
629
+ for (const scope of index.packages) {
630
+ if (scope.dir === '')
631
+ return scope.config;
632
+ if (filePath.startsWith(`${scope.dir}/`))
633
+ return scope.config;
634
+ }
635
+ return null;
636
+ }
637
+ /**
638
+ * Load every Zig build package in the repo, nearest-first.
639
+ *
640
+ * Called with no `packageDir` — which is how every call site read it before
641
+ * this function existed — `loadZigBuildConfig` reads the ROOT `build.zig` /
642
+ * `build.zig.zon` and nothing else. That is the whole configuration of a
643
+ * single-package repo and none of the configuration of a monorepo: a repo
644
+ * laying its packages out as `packages/<name>/build.zig` has no root build
645
+ * files at all, so the loader answers `null` and EVERY bare
646
+ * `@import("<module>")` in it goes unresolved — cross-file resolution silently
647
+ * degrades to relative imports only. Measured on a two-package fixture:
648
+ * `config = null`, `@import("core")` → `null`.
649
+ *
650
+ * The loader itself is not root-bound any more: this function is what supplies
651
+ * it a `packageDir`, one per package below.
652
+ *
653
+ * So the packages are discovered the way tsconfigs are (`findTsconfigFiles`):
654
+ * one bounded breadth-first walk that skips the hardcoded ignore set, then
655
+ * deepest-first ordering so `zigPackageFor` can take the first match.
656
+ *
657
+ * Called from `ScopeResolver.loadResolutionConfig`, which the orchestrator runs
658
+ * once per LANGUAGE workspace pass — so the walk happens only for repos that
659
+ * actually contain Zig. `loadImportConfigs`, which runs unconditionally for
660
+ * every repo, keeps calling `loadZigBuildConfig` for the root package alone;
661
+ * that is the same split TypeScript already has between the cheap
662
+ * `loadTsconfigPaths` and the repo-walking `loadTsconfigIndex`.
663
+ */
664
+ export async function loadZigWorkspaceIndex(repoRoot) {
665
+ const dirs = await findZigPackageDirs(repoRoot);
666
+ if (dirs.length === 0)
667
+ return null;
668
+ const packages = [];
669
+ for (const dir of dirs) {
670
+ const config = await loadZigBuildConfig(repoRoot, dir);
671
+ // A `build.zig` that declares no module and no path dep contributes nothing
672
+ // a lookup could answer with. Keeping it as an empty scope would be worse
673
+ // than dropping it: it would shadow an enclosing package that DOES declare
674
+ // the name, and answer nothing in its place.
675
+ if (config !== null)
676
+ packages.push({ dir, config });
677
+ }
678
+ if (packages.length === 0)
679
+ return null;
680
+ // Deepest first, so `zigPackageFor` takes the most specific package rather
681
+ // than whichever the walk reached first.
682
+ packages.sort((a, b) => b.dir.length - a.dir.length || a.dir.localeCompare(b.dir));
683
+ return { packages };
684
+ }
685
+ /** Repo-relative directories holding a `build.zig` and/or a `build.zig.zon`. */
686
+ async function findZigPackageDirs(repoRoot) {
687
+ const found = [];
688
+ const queue = [{ dir: repoRoot, depth: 0 }];
689
+ // A HEAD INDEX rather than `queue.shift()`. The queue is pushed to while it is
690
+ // drained, which keeps the array in a mode where `shift()` memmoves the whole
691
+ // remainder instead of taking V8's left-trimming fast path — so the walk is
692
+ // quadratic in the frontier, and `ZIG_SCAN_MAX_DIRS` is the bound on how bad
693
+ // that gets. Measured at that bound (20,000 dequeues): 53 ms at fan-out 4 and
694
+ // 81 ms at fan-out 20, against 0.8 ms here — 66-106x, paid before any config
695
+ // is read. Memory is unchanged: entries were already retained by the pushes,
696
+ // `shift()` only dropped the head.
697
+ let queueHead = 0;
698
+ let dirsScanned = 0;
699
+ while (queueHead < queue.length && dirsScanned < ZIG_SCAN_MAX_DIRS) {
700
+ const { dir, depth } = queue[queueHead++];
701
+ dirsScanned++;
702
+ let entries;
703
+ try {
704
+ entries = await fs.readdir(dir, { withFileTypes: true });
705
+ }
706
+ catch {
707
+ continue;
708
+ }
709
+ let isPackage = false;
710
+ for (const entry of entries) {
711
+ if (entry.isDirectory()) {
712
+ const childDir = path.join(dir, entry.name);
713
+ if (isHardcodedIgnoredDirectoryAtPath(repoRoot, childDir))
714
+ continue;
715
+ if (depth < ZIG_SCAN_MAX_DEPTH)
716
+ queue.push({ dir: childDir, depth: depth + 1 });
717
+ continue;
718
+ }
719
+ if (!entry.isFile())
720
+ continue;
721
+ // Either marker declares a package: a `build.zig` with no zon still names
722
+ // modules, and a zon with no build.zig still names path deps.
723
+ if (entry.name === 'build.zig' || entry.name === 'build.zig.zon')
724
+ isPackage = true;
725
+ }
726
+ if (isPackage) {
727
+ const rel = path.relative(repoRoot, dir).split(path.sep).join('/');
728
+ found.push(rel === '.' || rel === '' ? '' : rel);
729
+ }
730
+ }
731
+ return found;
732
+ }
553
733
  /**
554
734
  * Normalize a `.path` value from build.zig.zon into a repo-relative form.
555
735
  * Returns null for paths that escape the repo root (start with `..`) or
@@ -557,13 +737,37 @@ export async function loadZigBuildConfig(repoRoot) {
557
737
  * to the empty string (the repo root itself). Shared with the import
558
738
  * resolver so both sides agree on which deps are in-repo.
559
739
  */
740
+ /**
741
+ * Does this `.path` value point outside the repository BY ITS SPELLING —
742
+ * POSIX absolute (`/dep`), Windows drive-qualified (`C:\dep`, `C:/dep`),
743
+ * root-relative (`\dep`) or UNC (`\\server\share`)?
744
+ *
745
+ * Separators are normalized first so every Windows spelling is visible to the
746
+ * one test. Exported-in-spirit rather than inlined because it must be asked in
747
+ * TWO places and the two must not drift: `normalizeZigDepPath` asks it of the
748
+ * value it is given, and `loadZigBuildConfig` asks it of a NESTED package's
749
+ * value BEFORE prefixing the package directory. That second call is the whole
750
+ * point — prefixing turns `/dep` into `packages/app//dep`, which is relative by
751
+ * inspection, so the check inside `normalizeZigDepPath` no longer sees an
752
+ * absolute path and the empty segment is simply dropped, mapping an
753
+ * out-of-repo dependency onto a real in-repo directory if one happens to exist.
754
+ *
755
+ * `path.posix.join` is NOT a substitute: it strips the leading slash too
756
+ * (`join('packages/app/', '/dep')` is `packages/app/dep`), so it produces the
757
+ * same fabricated path without ever rejecting anything.
758
+ *
759
+ * A `..` prefix is deliberately NOT handled here. `../core` escapes the
760
+ * package but not necessarily the repo, and rebasing it is exactly what the
761
+ * nested-package branch exists to do; `normalizeZigDepPath` rejects the ones
762
+ * that still escape the ROOT after rebasing.
763
+ */
764
+ function isAbsoluteZigDepPath(depPath) {
765
+ const normalized = depPath.replace(/\\/g, '/');
766
+ return normalized.startsWith('/') || /^[A-Za-z]:\//.test(normalized);
767
+ }
560
768
  export function normalizeZigDepPath(depPath) {
561
- // Normalize separators BEFORE the absolute check so every Windows spelling
562
- // is visible to it: POSIX (`/x`), drive (`C:\x`, `C:/x`), root-relative
563
- // (`\x` → `/x`) and UNC (`\\server\share` → `//server/share`) paths all
564
- // point outside the repository.
565
769
  const normalized = depPath.replace(/\\/g, '/');
566
- if (normalized.startsWith('/') || /^[A-Za-z]:\//.test(normalized))
770
+ if (isAbsoluteZigDepPath(depPath))
567
771
  return null;
568
772
  const parts = [];
569
773
  for (const part of normalized.split('/')) {
@@ -20,7 +20,7 @@ import type { VariableExtractor } from './variable-types.js';
20
20
  import type { ImportResolverFn } from './import-resolvers/types.js';
21
21
  import type { SyntaxNode } from './utils/ast-helpers.js';
22
22
  import type { CfgVisitor } from './cfg/types.js';
23
- import type { GraphNode, NodeLabel } from '../../_shared/index.js';
23
+ import type { GraphNode, NodeLabel, ParameterTypeClass, RelationshipType } from '../../_shared/index.js';
24
24
  import type { ExtractedRoute } from './route-extractors/laravel.js';
25
25
  import type { SharedSpringType } from './route-extractors/spring-shared.js';
26
26
  import type { ModuleConstants, Operand, RepoConstants } from './route-extractors/constant-resolver.js';
@@ -67,6 +67,60 @@ export declare function runDefinitionPropertiesExtractor(extractor: DefinitionPr
67
67
  /** Provider metadata is additive; graph identity and source-location fields
68
68
  * supplied by the worker remain authoritative. */
69
69
  export declare function mergeCanonicalDefinitionProperties<TCanonical extends Readonly<Record<string, unknown>>>(providerProperties: Readonly<Record<string, unknown>>, canonicalProperties: TCanonical): Record<string, unknown> & TCanonical;
70
+ export interface ProviderSemanticNode {
71
+ readonly id: string;
72
+ readonly label: NodeLabel;
73
+ readonly properties: {
74
+ readonly name: string;
75
+ readonly filePath: string;
76
+ readonly startLine: number;
77
+ readonly endLine: number;
78
+ readonly language: SupportedLanguages;
79
+ readonly isExported: boolean;
80
+ readonly qualifiedName?: string;
81
+ readonly parameterCount?: number;
82
+ readonly requiredParameterCount?: number;
83
+ readonly parameterTypes?: readonly string[];
84
+ readonly parameterTypeClasses?: readonly ParameterTypeClass[];
85
+ readonly returnType?: string;
86
+ readonly declaredType?: string;
87
+ readonly visibility?: string;
88
+ readonly isStatic?: boolean;
89
+ readonly isReadonly?: boolean;
90
+ readonly [key: string]: unknown;
91
+ };
92
+ }
93
+ export type ProviderSemanticRelationshipType = Extract<RelationshipType, 'DECLARES' | 'DEFINES' | 'HAS_METHOD' | 'HAS_PROPERTY'>;
94
+ export interface ProviderSemanticRelationship {
95
+ readonly id: string;
96
+ readonly sourceId: string;
97
+ readonly targetId: string;
98
+ readonly type: ProviderSemanticRelationshipType;
99
+ readonly confidence: number;
100
+ readonly reason: string;
101
+ }
102
+ export interface ProviderSemanticSymbol {
103
+ readonly filePath: string;
104
+ readonly name: string;
105
+ readonly nodeId: string;
106
+ readonly type: NodeLabel;
107
+ readonly qualifiedName?: string;
108
+ readonly parameterCount?: number;
109
+ readonly requiredParameterCount?: number;
110
+ readonly parameterTypes?: readonly string[];
111
+ readonly parameterTypeClasses?: readonly ParameterTypeClass[];
112
+ readonly returnType?: string;
113
+ readonly declaredType?: string;
114
+ readonly ownerId?: string;
115
+ readonly visibility?: string;
116
+ readonly isStatic?: boolean;
117
+ readonly isReadonly?: boolean;
118
+ }
119
+ export interface ProviderSemanticGraph {
120
+ readonly nodes: readonly ProviderSemanticNode[];
121
+ readonly relationships: readonly ProviderSemanticRelationship[];
122
+ readonly symbols: readonly ProviderSemanticSymbol[];
123
+ }
70
124
  /** Configuration for AST-based framework detection patterns. */
71
125
  export interface AstFrameworkPatternConfig {
72
126
  framework: string;
@@ -156,6 +210,27 @@ interface LanguageProviderConfig {
156
210
  * and language-specific callable compatibility.
157
211
  */
158
212
  readonly runtimeSymbolStrategy?: RuntimeSymbolStrategy;
213
+ /**
214
+ * Optional content-based language classifier. The filename detector remains
215
+ * the default source of truth; this hook lets a provider claim ambiguous
216
+ * files only when the source text carries language-specific evidence.
217
+ *
218
+ * Used for extensions shared by several languages, where mapping the suffix
219
+ * globally would steal files from an existing provider. Implementations must
220
+ * be deterministic and conservative: false negatives are acceptable, false
221
+ * positives change which parser and resolver consumes the file.
222
+ *
223
+ * Default: undefined (provider never overrides filename detection).
224
+ */
225
+ readonly classifyFileContent?: (filePath: string, sourceText: string) => boolean;
226
+ /**
227
+ * Cheap path-only prefilter for `classifyFileContent`. When supplied, callers
228
+ * can avoid loading source text for files this provider would never claim.
229
+ *
230
+ * Default: undefined (only callers that already have content invoke
231
+ * `classifyFileContent`).
232
+ */
233
+ readonly shouldClassifyFileContent?: (filePath: string) => boolean;
159
234
  /** Type extraction: declarations, initializers, for-loop bindings */
160
235
  readonly typeConfig: LanguageTypeConfig;
161
236
  /** Export detection: is this AST node a public/exported symbol? */
@@ -513,6 +588,18 @@ interface LanguageProviderConfig {
513
588
  * language-agnostic operand fold).
514
589
  */
515
590
  readonly foldRoutePathOperands?: (filePath: string, operands: readonly Operand[], repo: RepoConstants) => string | null;
591
+ /**
592
+ * Optional provider-owned semantic graph extraction for languages whose
593
+ * stable symbol identities cannot be represented by the generic query
594
+ * pipeline's `(label, filePath, qualifiedName)` rule.
595
+ *
596
+ * Runs in the parse worker after tree-sitter has parsed the file and after
597
+ * `extractParsedFile` has produced the scope-resolution artifact. The hook is
598
+ * deterministic and AST-based: it receives the already-parsed tree and must
599
+ * return plain graph nodes/relationships/symbol-table rows. Existing
600
+ * providers leave it undefined, preserving the generic capture path exactly.
601
+ */
602
+ readonly extractSemanticGraph?: (tree: Parser.Tree, filePath: string, sourceText: string) => ProviderSemanticGraph;
516
603
  /** Built-in/stdlib names that should be filtered from the call graph for this language.
517
604
  * Default: undefined (no language-specific filtering). */
518
605
  readonly builtInNames?: ReadonlySet<string>;
@@ -20,6 +20,7 @@ export declare const providers: {
20
20
  csharp: LanguageProvider;
21
21
  c: LanguageProvider;
22
22
  cpp: LanguageProvider;
23
+ "objective-c": LanguageProvider;
23
24
  php: LanguageProvider;
24
25
  ruby: LanguageProvider;
25
26
  swift: LanguageProvider;
@@ -33,3 +34,9 @@ export declare function getProvider(language: SupportedLanguages): LanguageProvi
33
34
  /** Look up a language provider from a file path by extension.
34
35
  * Returns null if the file extension is not recognized. */
35
36
  export declare function getProviderForFile(filePath: string): LanguageProvider | null;
37
+ /** Return the provider whose content classifier confidently claims this file. */
38
+ export declare function getProviderForFileContent(filePath: string, content: string): LanguageProvider | null;
39
+ /** True when at least one provider wants source text before language bucketing. */
40
+ export declare function needsContentLanguageClassification(filePath: string): boolean;
41
+ /** Return the effective language for a file, optionally using source content. */
42
+ export declare function getLanguageForFileContent(filePath: string, content: string): SupportedLanguages | null;