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.
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +2 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts +2 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.js +3 -1
- package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +3 -3
- package/dist/_shared/scope-resolution/registries/class-registry.js +3 -3
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.js +2 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.js +2 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
- package/dist/cli/analyze-config.d.ts +2 -2
- package/dist/cli/analyze-config.js +10 -33
- package/dist/cli/doctor.js +6 -4
- package/dist/cli/eval-server.js +13 -1
- package/dist/cli/i18n/en.d.ts +4 -2
- package/dist/cli/i18n/en.js +4 -2
- package/dist/cli/i18n/resources.d.ts +6 -2
- package/dist/cli/i18n/zh-CN.d.ts +2 -0
- package/dist/cli/i18n/zh-CN.js +4 -2
- package/dist/core/analysis-feature-registry.d.ts +1 -1
- package/dist/core/analysis-feature-registry.js +2 -0
- package/dist/core/auto-sync/starter.js +2 -2
- package/dist/core/embeddings/ast-utils.js +8 -3
- package/dist/core/embeddings/chunker.js +67 -10
- package/dist/core/embeddings/embedding-pipeline.d.ts +1 -1
- package/dist/core/embeddings/embedding-pipeline.js +1 -1
- package/dist/core/embeddings/structural-extractor.js +2 -2
- package/dist/core/embeddings/types.d.ts +4 -2
- package/dist/core/embeddings/types.js +18 -0
- package/dist/core/git-ref.d.ts +22 -0
- package/dist/core/git-ref.js +114 -0
- package/dist/core/git-staleness.js +14 -0
- package/dist/core/group/extractors/graphql-extractor.d.ts +1 -1
- package/dist/core/group/extractors/graphql-extractor.js +149 -13
- package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
- package/dist/core/group/extractors/manifest-extractor.js +2 -2
- package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +5 -8
- package/dist/core/ingestion/content-language-classification.d.ts +10 -0
- package/dist/core/ingestion/content-language-classification.js +30 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +1 -0
- package/dist/core/ingestion/filesystem-walker.js +1 -1
- package/dist/core/ingestion/import-resolvers/node-workspace-packages.js +3 -2
- package/dist/core/ingestion/language-config.d.ts +82 -13
- package/dist/core/ingestion/language-config.js +217 -13
- package/dist/core/ingestion/language-provider.d.ts +88 -1
- package/dist/core/ingestion/languages/index.d.ts +7 -0
- package/dist/core/ingestion/languages/index.js +30 -1
- package/dist/core/ingestion/languages/objective-c/analysis-features.d.ts +10 -0
- package/dist/core/ingestion/languages/objective-c/analysis-features.js +19 -0
- package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.d.ts +13 -0
- package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.js +124 -0
- package/dist/core/ingestion/languages/objective-c/facts.d.ts +148 -0
- package/dist/core/ingestion/languages/objective-c/facts.js +1150 -0
- package/dist/core/ingestion/languages/objective-c/import-target.d.ts +11 -0
- package/dist/core/ingestion/languages/objective-c/import-target.js +122 -0
- package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.d.ts +24 -0
- package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.js +261 -0
- package/dist/core/ingestion/languages/objective-c/resolution-config.d.ts +41 -0
- package/dist/core/ingestion/languages/objective-c/resolution-config.js +282 -0
- package/dist/core/ingestion/languages/objective-c/scope-resolver.d.ts +2 -0
- package/dist/core/ingestion/languages/objective-c/scope-resolver.js +503 -0
- package/dist/core/ingestion/languages/objective-c.d.ts +2 -0
- package/dist/core/ingestion/languages/objective-c.js +300 -0
- package/dist/core/ingestion/languages/typescript/query.d.ts +31 -0
- package/dist/core/ingestion/languages/typescript/query.js +7 -1
- package/dist/core/ingestion/languages/typescript/tsconfig.js +3 -2
- package/dist/core/ingestion/languages/typescript.js +1 -1
- package/dist/core/ingestion/languages/zig/query.d.ts +26 -0
- package/dist/core/ingestion/languages/zig/query.js +61 -1
- package/dist/core/ingestion/languages/zig/range-binding.d.ts +8 -0
- package/dist/core/ingestion/languages/zig/range-binding.js +24 -0
- package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +3 -2
- package/dist/core/ingestion/languages/zig/scope-resolver.js +18 -5
- package/dist/core/ingestion/languages/zig/this-alias-bindings.d.ts +58 -0
- package/dist/core/ingestion/languages/zig/this-alias-bindings.js +176 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.d.ts +8 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.js +82 -0
- package/dist/core/ingestion/model/registration-table.d.ts +3 -3
- package/dist/core/ingestion/model/registration-table.js +9 -5
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/model/symbol-table.js +2 -0
- package/dist/core/ingestion/model/type-registry.d.ts +1 -1
- package/dist/core/ingestion/parsing-processor.d.ts +22 -6
- package/dist/core/ingestion/parsing-processor.js +39 -20
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +9 -1
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +307 -96
- package/dist/core/ingestion/pipeline-phases/parse-round-budget.d.ts +42 -0
- package/dist/core/ingestion/pipeline-phases/parse-round-budget.js +50 -0
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +7 -1
- package/dist/core/ingestion/scope-extractor.js +4 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +13 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +2 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +2 -0
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +78 -5
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +262 -7
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +5 -2
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +10 -1
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +39 -3
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +82 -3
- package/dist/core/ingestion/scope-resolution/value-ref-edges.d.ts +14 -0
- package/dist/core/ingestion/scope-resolution/value-ref-edges.js +14 -0
- package/dist/core/ingestion/tree-sitter-queries.js +2 -0
- package/dist/core/ingestion/utils/symbol-labels.js +2 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -1
- package/dist/core/ingestion/workers/parse-worker.js +63 -3
- package/dist/core/ingestion/workers/worker-pool.d.ts +56 -2
- package/dist/core/ingestion/workers/worker-pool.js +117 -26
- package/dist/core/lbug/csv-generator.js +2 -0
- package/dist/core/lbug/schema.d.ts +3 -1
- package/dist/core/lbug/schema.js +27 -0
- package/dist/core/search/fts-indexes.js +13 -4
- package/dist/core/search/fts-schema.js +2 -0
- package/dist/core/tree-sitter/parser-loader.js +10 -0
- package/dist/core/tree-sitter/vendored-grammars.d.ts +1 -1
- package/dist/core/tree-sitter/vendored-grammars.js +2 -1
- package/dist/mcp/local/local-backend.d.ts +33 -0
- package/dist/mcp/local/local-backend.js +166 -5
- package/dist/mcp/tools.js +6 -4
- package/dist/server/analyze-job.d.ts +19 -1
- package/dist/server/analyze-job.js +14 -3
- package/dist/server/analyze-launch.d.ts +14 -0
- package/dist/server/analyze-launch.js +59 -14
- package/dist/server/analyze-worker-ipc.d.ts +6 -5
- package/dist/server/analyze-worker-ipc.js +4 -0
- package/dist/server/api.js +68 -21
- package/dist/server/git-clone.d.ts +38 -5
- package/dist/server/git-clone.js +216 -38
- package/dist/server/repo-projection.d.ts +88 -0
- package/dist/server/repo-projection.js +53 -0
- package/dist/storage/file-lock.js +5 -3
- package/dist/storage/parse-cache.js +32 -1
- package/dist/storage/parsedfile-store.js +53 -1
- package/dist/storage/v8-sidecar.d.ts +11 -0
- package/dist/storage/v8-sidecar.js +15 -7
- package/dist/utils/process-identity.d.ts +13 -0
- package/dist/utils/process-identity.js +18 -0
- package/package.json +1 -1
- package/scripts/build-tree-sitter-grammars.cjs +4 -3
- package/vendor/tree-sitter-objc/LICENSE +21 -0
- package/vendor/tree-sitter-objc/README.md +18 -0
- package/vendor/tree-sitter-objc/binding.gyp +35 -0
- package/vendor/tree-sitter-objc/bindings/node/binding.cc +19 -0
- package/vendor/tree-sitter-objc/bindings/node/binding_test.js +9 -0
- package/vendor/tree-sitter-objc/bindings/node/index.d.ts +27 -0
- package/vendor/tree-sitter-objc/bindings/node/index.js +11 -0
- package/vendor/tree-sitter-objc/grammar.js +1286 -0
- package/vendor/tree-sitter-objc/package.json +56 -0
- package/vendor/tree-sitter-objc/prebuilds/SHA256SUMS +6 -0
- package/vendor/tree-sitter-objc/prebuilds/darwin-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/darwin-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/linux-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/linux-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/win32-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/win32-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/queries/folds.scm +20 -0
- package/vendor/tree-sitter-objc/queries/highlights.scm +216 -0
- package/vendor/tree-sitter-objc/queries/indents.scm +1 -0
- package/vendor/tree-sitter-objc/queries/injections.scm +10 -0
- package/vendor/tree-sitter-objc/queries/locals.scm +1 -0
- package/vendor/tree-sitter-objc/src/grammar.json +16292 -0
- package/vendor/tree-sitter-objc/src/node-types.json +7524 -0
- package/vendor/tree-sitter-objc/src/parser.c +684023 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/array.h +291 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/parser.h +266 -0
- package/vendor/tree-sitter-objc/tree-sitter-objc.wasm +0 -0
- package/vendor/tree-sitter-objc/tree-sitter.json +38 -0
- package/web/assets/{agent-BMRqXorA.js → agent-C2n33ANd.js} +1 -1
- package/web/assets/{index-Dj3vQOHK.js → index-CHJoW_P1.js} +18 -18
- package/web/assets/src-jc8Ffy3T.js +1 -0
- package/web/index.html +2 -2
- 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
|
-
*
|
|
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");
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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
|
+
}
|
|
@@ -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
|
|
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
|
|
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
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* `
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
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
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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 (
|
|
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;
|