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
|
@@ -5,17 +5,19 @@
|
|
|
5
5
|
* Thin wiring: Zig has no inheritance (default MRO linearization over an
|
|
6
6
|
* empty heritage set), no `super`, and is statically typed (field-fallback
|
|
7
7
|
* heuristic off per the contract guidance). Import resolution reuses the
|
|
8
|
-
* same `resolveZigImportInternal` the legacy import-resolver config wraps,
|
|
9
|
-
*
|
|
8
|
+
* same `resolveZigImportInternal` the legacy import-resolver config wraps, with
|
|
9
|
+
* the repo's Zig build packages threaded through `loadResolutionConfig` and the
|
|
10
|
+
* one governing each file selected per-file by `zigPackageFor`.
|
|
10
11
|
*/
|
|
11
12
|
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
12
13
|
import { buildMro, defaultLinearize } from '../../scope-resolution/passes/mro.js';
|
|
13
14
|
import { populateClassOwnedMembers } from '../../scope-resolution/scope/walkers.js';
|
|
14
|
-
import {
|
|
15
|
+
import { loadZigWorkspaceIndex, zigPackageFor, } from '../../language-config.js';
|
|
15
16
|
import { resolveZigImportInternal } from '../../import-resolvers/zig.js';
|
|
16
17
|
import { zigProvider } from '../zig.js';
|
|
17
18
|
import { expandZigWildcardNames, zigArityCompatibility, zigMergeBindings } from './index.js';
|
|
18
19
|
import { populateZigRangeBindings } from './range-binding.js';
|
|
20
|
+
import { populateZigWorkspaceStaticGating } from './workspace-static-gating.js';
|
|
19
21
|
export const zigScopeResolver = {
|
|
20
22
|
language: SupportedLanguages.Zig,
|
|
21
23
|
languageProvider: zigProvider,
|
|
@@ -40,14 +42,25 @@ export const zigScopeResolver = {
|
|
|
40
42
|
// (`opmod.Op.lookup.event_max()`) — walked hop by hop from the verified
|
|
41
43
|
// import; a one-hop split at the last dot resolved none of them.
|
|
42
44
|
resolveNamespaceChains: true,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
// The whole workspace, not just the root package. A Zig module's import table
|
|
46
|
+
// is declared by the `build.zig` of the package the file belongs to, so a repo
|
|
47
|
+
// laying its packages out as `packages/<name>/build.zig` has as many import
|
|
48
|
+
// tables as packages — and reading only the root one leaves every bare
|
|
49
|
+
// `@import("<module>")` in such a repo unresolved. Same shape, same reason, as
|
|
50
|
+
// `loadTsconfigIndex` for a TypeScript monorepo.
|
|
51
|
+
loadResolutionConfig: (repoPath) => loadZigWorkspaceIndex(repoPath),
|
|
52
|
+
resolveImportTarget: (targetRaw, fromFile, allFilePaths, resolutionConfig) => resolveZigImportInternal(fromFile, targetRaw, allFilePaths,
|
|
53
|
+
// The package governing THIS file — `zigPackageFor` is the `tsconfigFor`
|
|
54
|
+
// analogue. `resolveZigImportInternal` is handed one package's config and
|
|
55
|
+
// is unchanged by this: which config it receives is the only difference.
|
|
56
|
+
zigPackageFor(resolutionConfig, fromFile)),
|
|
45
57
|
// `pub usingnamespace @import("x.zig");` — target decls become local decls.
|
|
46
58
|
expandsWildcardTo: (targetModuleScope, parsedFiles) => expandZigWildcardNames(targetModuleScope, parsedFiles),
|
|
47
59
|
mergeBindings: zigMergeBindings,
|
|
48
60
|
arityCompatibility: zigArityCompatibility,
|
|
49
61
|
buildMro: (graph, parsedFiles, nodeLookup) => buildMro(graph, parsedFiles, nodeLookup, defaultLinearize),
|
|
50
62
|
populateOwners: (parsed) => populateClassOwnedMembers(parsed),
|
|
63
|
+
populateWorkspaceReferences: populateZigWorkspaceStaticGating,
|
|
51
64
|
// Payload captures — `for (items) |it|`, `if (opt) |v|`, `while (it.next())
|
|
52
65
|
// |x|` — typed from the subject's binding after finalize (F6).
|
|
53
66
|
populateRangeBindings: populateZigRangeBindings,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bind a Zig `const X = @This();` alias to the container it names (#3219
|
|
3
|
+
* review round 8).
|
|
4
|
+
*
|
|
5
|
+
* `@This()` IS the enclosing container, and Zig code says so constantly: the
|
|
6
|
+
* single most common spelling is `const Self = @This();`, followed by
|
|
7
|
+
* `Alias.member` wherever the explicit form is wanted (`Self.width(self)`, a
|
|
8
|
+
* registration `bridge.accessor(Self.width, …)`, a nested type `Self.Node`).
|
|
9
|
+
* A compiler resolves `Self` and the container's own name to the same type.
|
|
10
|
+
* This index did not, for one specific reason:
|
|
11
|
+
*
|
|
12
|
+
* - A container-level alias (`const Self = @This();` inside `struct {…}`)
|
|
13
|
+
* mints a `Variable` beside the `Struct`, so `Self` binds to a VALUE. Every
|
|
14
|
+
* class-like lookup filters on `isClassLike` and walks straight past it.
|
|
15
|
+
* - A FILE-level alias in a file-as-struct mints nothing at all —
|
|
16
|
+
* `isZigFileThisAlias` suppresses the Const deliberately, so it cannot
|
|
17
|
+
* shadow the type for `x: *Page`. The name is then bound to nothing, while
|
|
18
|
+
* the container itself is bound under the FILE STEM.
|
|
19
|
+
*
|
|
20
|
+
* So `Self.width` resolved only when the alias happened to be spelled like its
|
|
21
|
+
* container. Measured on the three Zig corpora on hand: 73 of ghostty's 185
|
|
22
|
+
* `@This()` files, 93 of tigerbeetle's 94 and 8 of mach's 42 spell it
|
|
23
|
+
* differently, carrying 302 `Alias.member` references between them, 96 of those
|
|
24
|
+
* calls. Those were not wrong edges — they were no edges, and a caller list
|
|
25
|
+
* missing them is exactly the false confidence #3399 is about.
|
|
26
|
+
*
|
|
27
|
+
* WHAT THIS ADDS, precisely: one binding of the alias NAME to the container's
|
|
28
|
+
* own definition, appended to `indexes.bindingAugmentations` (the sanctioned
|
|
29
|
+
* post-finalize channel, invariant I8 — `indexes.bindings` is frozen). The
|
|
30
|
+
* augmentation channel is consulted by `lookupBindingsAt` only AFTER a scope's
|
|
31
|
+
* own `Scope.bindings`, so this can never outrank a real local declaration: the
|
|
32
|
+
* `Variable` the container-level alias already mints still answers first for
|
|
33
|
+
* anything that wants a value, and the container answers for anything that
|
|
34
|
+
* wants a type. Nothing is replaced and nothing is removed.
|
|
35
|
+
*
|
|
36
|
+
* WHAT IT DELIBERATELY DOES NOT DO. Only aliases declared DIRECTLY in a
|
|
37
|
+
* container body or at file level are bound, which is the same set
|
|
38
|
+
* `collectZigThisAliases` recognizes for the type-rewrite path. A function-local
|
|
39
|
+
* `const Self = @This();` also names the enclosing container, but it belongs in
|
|
40
|
+
* that function's scope, not the container's, and binding it here would make it
|
|
41
|
+
* visible to sibling functions that never declared it.
|
|
42
|
+
*/
|
|
43
|
+
import type { ParsedFile } from '../../../../_shared/index.js';
|
|
44
|
+
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
|
45
|
+
import type { SyntaxNode } from '../../utils/ast-helpers.js';
|
|
46
|
+
/**
|
|
47
|
+
* Bind every `@This()` alias declared in `parsed` at container or file level.
|
|
48
|
+
*
|
|
49
|
+
* Called per file from `populateZigRangeBindings`, which already holds the
|
|
50
|
+
* parsed tree — a second pass over `parsedFiles` would re-parse every file when
|
|
51
|
+
* the tree cache is cold. That is the only thing the two share. Ordering
|
|
52
|
+
* against the payload bindings that follow does not matter, twice over: the
|
|
53
|
+
* payload walk types its subjects through `findReceiverTypeBinding`, which
|
|
54
|
+
* never reads the channel written here, and a `@This()` alias is a
|
|
55
|
+
* container-private name no other file can import, so nothing outside this file
|
|
56
|
+
* reads it either.
|
|
57
|
+
*/
|
|
58
|
+
export declare function bindZigThisAliases(parsed: ParsedFile, root: SyntaxNode, indexes: ScopeResolutionIndexes): void;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bind a Zig `const X = @This();` alias to the container it names (#3219
|
|
3
|
+
* review round 8).
|
|
4
|
+
*
|
|
5
|
+
* `@This()` IS the enclosing container, and Zig code says so constantly: the
|
|
6
|
+
* single most common spelling is `const Self = @This();`, followed by
|
|
7
|
+
* `Alias.member` wherever the explicit form is wanted (`Self.width(self)`, a
|
|
8
|
+
* registration `bridge.accessor(Self.width, …)`, a nested type `Self.Node`).
|
|
9
|
+
* A compiler resolves `Self` and the container's own name to the same type.
|
|
10
|
+
* This index did not, for one specific reason:
|
|
11
|
+
*
|
|
12
|
+
* - A container-level alias (`const Self = @This();` inside `struct {…}`)
|
|
13
|
+
* mints a `Variable` beside the `Struct`, so `Self` binds to a VALUE. Every
|
|
14
|
+
* class-like lookup filters on `isClassLike` and walks straight past it.
|
|
15
|
+
* - A FILE-level alias in a file-as-struct mints nothing at all —
|
|
16
|
+
* `isZigFileThisAlias` suppresses the Const deliberately, so it cannot
|
|
17
|
+
* shadow the type for `x: *Page`. The name is then bound to nothing, while
|
|
18
|
+
* the container itself is bound under the FILE STEM.
|
|
19
|
+
*
|
|
20
|
+
* So `Self.width` resolved only when the alias happened to be spelled like its
|
|
21
|
+
* container. Measured on the three Zig corpora on hand: 73 of ghostty's 185
|
|
22
|
+
* `@This()` files, 93 of tigerbeetle's 94 and 8 of mach's 42 spell it
|
|
23
|
+
* differently, carrying 302 `Alias.member` references between them, 96 of those
|
|
24
|
+
* calls. Those were not wrong edges — they were no edges, and a caller list
|
|
25
|
+
* missing them is exactly the false confidence #3399 is about.
|
|
26
|
+
*
|
|
27
|
+
* WHAT THIS ADDS, precisely: one binding of the alias NAME to the container's
|
|
28
|
+
* own definition, appended to `indexes.bindingAugmentations` (the sanctioned
|
|
29
|
+
* post-finalize channel, invariant I8 — `indexes.bindings` is frozen). The
|
|
30
|
+
* augmentation channel is consulted by `lookupBindingsAt` only AFTER a scope's
|
|
31
|
+
* own `Scope.bindings`, so this can never outrank a real local declaration: the
|
|
32
|
+
* `Variable` the container-level alias already mints still answers first for
|
|
33
|
+
* anything that wants a value, and the container answers for anything that
|
|
34
|
+
* wants a type. Nothing is replaced and nothing is removed.
|
|
35
|
+
*
|
|
36
|
+
* WHAT IT DELIBERATELY DOES NOT DO. Only aliases declared DIRECTLY in a
|
|
37
|
+
* container body or at file level are bound, which is the same set
|
|
38
|
+
* `collectZigThisAliases` recognizes for the type-rewrite path. A function-local
|
|
39
|
+
* `const Self = @This();` also names the enclosing container, but it belongs in
|
|
40
|
+
* that function's scope, not the container's, and binding it here would make it
|
|
41
|
+
* visible to sibling functions that never declared it.
|
|
42
|
+
*/
|
|
43
|
+
import { isClassLike } from '../../scope-resolution/scope/walkers.js';
|
|
44
|
+
import { isZigKeywordDeclaration, ZIG_CONTAINER_TYPES } from './captures.js';
|
|
45
|
+
/** `const X = @This();` — the declaration shape, wherever it sits. */
|
|
46
|
+
function thisAliasName(node) {
|
|
47
|
+
if (node.type !== 'variable_declaration' || !isZigKeywordDeclaration(node))
|
|
48
|
+
return undefined;
|
|
49
|
+
const named = node.namedChildren.filter((c) => c !== null);
|
|
50
|
+
if (named.length !== 2 || named[0].type !== 'identifier')
|
|
51
|
+
return undefined;
|
|
52
|
+
const value = named[1];
|
|
53
|
+
if (value.type !== 'builtin_function' || value.namedChild(0)?.text !== '@This')
|
|
54
|
+
return undefined;
|
|
55
|
+
return named[0].text;
|
|
56
|
+
}
|
|
57
|
+
/** The class-like definition a Class scope is the body of. */
|
|
58
|
+
function containerDefOf(scope) {
|
|
59
|
+
return scope.ownedDefs.find((d) => isClassLike(d.type));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The Class scope of the FILE-AS-STRUCT, if this file is one.
|
|
63
|
+
*
|
|
64
|
+
* Identified by range rather than by name: it is the only Class scope that both
|
|
65
|
+
* hangs directly off the module scope AND spans the same lines as it. A
|
|
66
|
+
* namespace-only file with a top-level `pub const Counter = struct {…}` also
|
|
67
|
+
* produces a Class scope under the module scope, and it also carries the file
|
|
68
|
+
* stem when the file is `Counter.zig` — matching on the name would bind that
|
|
69
|
+
* file's `@This()` alias to `Counter`, which is not what `@This()` means there.
|
|
70
|
+
*/
|
|
71
|
+
function fileStructScope(scopes, moduleScope) {
|
|
72
|
+
return scopes.find((s) => s.kind === 'Class' &&
|
|
73
|
+
s.parent === moduleScope.id &&
|
|
74
|
+
s.range.startLine === moduleScope.range.startLine &&
|
|
75
|
+
s.range.endLine === moduleScope.range.endLine);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Innermost Class scope containing `node`.
|
|
79
|
+
*
|
|
80
|
+
* Compared on (line, column) rather than line alone, because a Zig container
|
|
81
|
+
* can nest inside another on ONE line — `const A = struct { const S = @This();
|
|
82
|
+
* const B = struct { const T = @This(); }; };` gives both scopes the same start
|
|
83
|
+
* line, and picking between them by line would be a coin toss that binds an
|
|
84
|
+
* alias to the wrong container. A wrong edge is the one outcome this whole
|
|
85
|
+
* change set treats as worse than no edge.
|
|
86
|
+
*/
|
|
87
|
+
function enclosingClassScope(scopes, node) {
|
|
88
|
+
const line = node.startPosition.row + 1;
|
|
89
|
+
const column = node.startPosition.column;
|
|
90
|
+
const startsAtOrBefore = (l, c) => l < line || (l === line && c <= column);
|
|
91
|
+
const endsAtOrAfter = (l, c) => l > line || (l === line && c >= column);
|
|
92
|
+
let best;
|
|
93
|
+
for (const s of scopes) {
|
|
94
|
+
if (s.kind !== 'Class')
|
|
95
|
+
continue;
|
|
96
|
+
if (!startsAtOrBefore(s.range.startLine, s.range.startCol))
|
|
97
|
+
continue;
|
|
98
|
+
if (!endsAtOrAfter(s.range.endLine, s.range.endCol))
|
|
99
|
+
continue;
|
|
100
|
+
if (best === undefined ||
|
|
101
|
+
s.range.startLine > best.range.startLine ||
|
|
102
|
+
(s.range.startLine === best.range.startLine && s.range.startCol > best.range.startCol)) {
|
|
103
|
+
best = s;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return best;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Append `alias -> def` at `scopeId`, skipping the append when THIS def is
|
|
110
|
+
* already bound there. Idempotence, not precedence: a duplicate would be
|
|
111
|
+
* harmless for lookup (`lookupBindingsAt` dedupes by `def.nodeId`) but would
|
|
112
|
+
* make the channel's contents depend on how many times the hook ran. Other
|
|
113
|
+
* bindings under the same name are left alone — the channel is append-only per
|
|
114
|
+
* I8, and the whole point of the augmentation tier is that a scope's own
|
|
115
|
+
* `Scope.bindings` are consulted first and still win.
|
|
116
|
+
*/
|
|
117
|
+
function appendBinding(indexes, scopeId, alias, def) {
|
|
118
|
+
const channel = indexes.bindingAugmentations;
|
|
119
|
+
let byName = channel.get(scopeId);
|
|
120
|
+
if (byName === undefined) {
|
|
121
|
+
byName = new Map();
|
|
122
|
+
channel.set(scopeId, byName);
|
|
123
|
+
}
|
|
124
|
+
const bucket = byName.get(alias);
|
|
125
|
+
if (bucket === undefined) {
|
|
126
|
+
byName.set(alias, [{ def, origin: 'local' }]);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (bucket.some((ref) => ref.def.nodeId === def.nodeId))
|
|
130
|
+
return;
|
|
131
|
+
bucket.push({ def, origin: 'local' });
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Bind every `@This()` alias declared in `parsed` at container or file level.
|
|
135
|
+
*
|
|
136
|
+
* Called per file from `populateZigRangeBindings`, which already holds the
|
|
137
|
+
* parsed tree — a second pass over `parsedFiles` would re-parse every file when
|
|
138
|
+
* the tree cache is cold. That is the only thing the two share. Ordering
|
|
139
|
+
* against the payload bindings that follow does not matter, twice over: the
|
|
140
|
+
* payload walk types its subjects through `findReceiverTypeBinding`, which
|
|
141
|
+
* never reads the channel written here, and a `@This()` alias is a
|
|
142
|
+
* container-private name no other file can import, so nothing outside this file
|
|
143
|
+
* reads it either.
|
|
144
|
+
*/
|
|
145
|
+
export function bindZigThisAliases(parsed, root, indexes) {
|
|
146
|
+
const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
|
|
147
|
+
if (moduleScope === undefined)
|
|
148
|
+
return;
|
|
149
|
+
const fileStruct = fileStructScope(parsed.scopes, moduleScope);
|
|
150
|
+
const visit = (node) => {
|
|
151
|
+
const alias = thisAliasName(node);
|
|
152
|
+
if (alias !== undefined) {
|
|
153
|
+
const parent = node.parent;
|
|
154
|
+
if (parent?.type === 'source_file') {
|
|
155
|
+
// The file-as-struct's own name. Bound at the MODULE scope, which is
|
|
156
|
+
// where the container is already bound under the file stem, so the
|
|
157
|
+
// alias and the stem are visible to exactly the same sites.
|
|
158
|
+
const def = fileStruct === undefined ? undefined : containerDefOf(fileStruct);
|
|
159
|
+
if (def !== undefined)
|
|
160
|
+
appendBinding(indexes, moduleScope.id, alias, def);
|
|
161
|
+
}
|
|
162
|
+
else if (parent !== null && ZIG_CONTAINER_TYPES.has(parent.type)) {
|
|
163
|
+
const scope = enclosingClassScope(parsed.scopes, node);
|
|
164
|
+
const def = scope === undefined ? undefined : containerDefOf(scope);
|
|
165
|
+
if (scope !== undefined && def !== undefined)
|
|
166
|
+
appendBinding(indexes, scope.id, alias, def);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
170
|
+
const child = node.namedChild(i);
|
|
171
|
+
if (child !== null)
|
|
172
|
+
visit(child);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
visit(root);
|
|
176
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParsedFile } from '../../../../_shared/index.js';
|
|
2
|
+
export declare function populateZigWorkspaceStaticGating(parsedFiles: ParsedFile[], ctx: {
|
|
3
|
+
readonly fileContents: ReadonlyMap<string, string>;
|
|
4
|
+
readonly treeCache?: {
|
|
5
|
+
get(filePath: string): unknown;
|
|
6
|
+
};
|
|
7
|
+
readonly resolutionConfig?: unknown;
|
|
8
|
+
}): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { getTreeSitterBufferSize } from '../../constants.js';
|
|
2
|
+
import { zigPackageFor } from '../../language-config.js';
|
|
3
|
+
import { resolveZigImportInternal } from '../../import-resolvers/zig.js';
|
|
4
|
+
import { buildZigBoolConstMap, collectZigStaticGatedRanges, isPositionStaticGated, } from '../../call-extractors/zig-static-gating.js';
|
|
5
|
+
import { parseSourceSafe, ParseTimeoutError } from '../../../tree-sitter/safe-parse.js';
|
|
6
|
+
import { getZigParser } from './query.js';
|
|
7
|
+
export function populateZigWorkspaceStaticGating(parsedFiles, ctx) {
|
|
8
|
+
const parser = getZigParser();
|
|
9
|
+
const trees = new Map();
|
|
10
|
+
const bools = new Map();
|
|
11
|
+
for (const parsed of parsedFiles) {
|
|
12
|
+
const source = ctx.fileContents.get(parsed.filePath);
|
|
13
|
+
if (source === undefined)
|
|
14
|
+
continue;
|
|
15
|
+
let tree = ctx.treeCache?.get(parsed.filePath);
|
|
16
|
+
if (tree === undefined) {
|
|
17
|
+
try {
|
|
18
|
+
tree = parseSourceSafe(parser, source, undefined, {
|
|
19
|
+
bufferSize: getTreeSitterBufferSize(source),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err instanceof ParseTimeoutError)
|
|
24
|
+
continue;
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
trees.set(parsed.filePath, tree);
|
|
29
|
+
bools.set(parsed.filePath, buildZigBoolConstMap(tree.rootNode));
|
|
30
|
+
}
|
|
31
|
+
const knownPaths = new Set(trees.keys());
|
|
32
|
+
for (const [index, parsed] of parsedFiles.entries()) {
|
|
33
|
+
const tree = trees.get(parsed.filePath);
|
|
34
|
+
if (tree === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
const aliases = collectImportAliases(tree, parsed.filePath, knownPaths,
|
|
37
|
+
// `resolutionConfig` is the whole Zig workspace; the package governing
|
|
38
|
+
// THIS file is what `resolveZigImportInternal` takes. Selected here rather
|
|
39
|
+
// than hoisted out of the loop because the answer is per-file: two files
|
|
40
|
+
// of this pass can belong to different packages.
|
|
41
|
+
zigPackageFor(ctx.resolutionConfig, parsed.filePath));
|
|
42
|
+
if (aliases.size === 0)
|
|
43
|
+
continue;
|
|
44
|
+
const ranges = collectZigStaticGatedRanges(tree.rootNode, bools.get(parsed.filePath) ?? new Map(), aliases, (filePath) => bools.get(filePath));
|
|
45
|
+
if (ranges.length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
const next = parsed.referenceSites.map((site) => site.kind === 'call' &&
|
|
48
|
+
site.staticGated !== true &&
|
|
49
|
+
isPositionStaticGated(site.atRange.startLine, site.atRange.startCol, ranges)
|
|
50
|
+
? { ...site, staticGated: true }
|
|
51
|
+
: site);
|
|
52
|
+
parsedFiles[index] = Object.freeze({ ...parsed, referenceSites: Object.freeze(next) });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function collectImportAliases(tree, fromFile, knownPaths, packageConfig) {
|
|
56
|
+
const candidates = new Map();
|
|
57
|
+
const declarationCounts = new Map();
|
|
58
|
+
for (const decl of tree.rootNode.descendantsOfType('variable_declaration')) {
|
|
59
|
+
const names = decl.namedChildren.filter((node) => node.type === 'identifier');
|
|
60
|
+
const binding = names[0]?.text;
|
|
61
|
+
if (binding === undefined)
|
|
62
|
+
continue;
|
|
63
|
+
declarationCounts.set(binding, (declarationCounts.get(binding) ?? 0) + 1);
|
|
64
|
+
const builtin = decl.namedChildren.find((node) => node.type === 'builtin_function' && node.text.startsWith('@import('));
|
|
65
|
+
const raw = builtin?.descendantsOfType('string').at(0)?.text;
|
|
66
|
+
if (raw === undefined)
|
|
67
|
+
continue;
|
|
68
|
+
const specifier = raw.replace(/^['"]|['"]$/g, '');
|
|
69
|
+
const target = resolveZigImportInternal(fromFile, specifier, knownPaths, packageConfig);
|
|
70
|
+
if (target !== null)
|
|
71
|
+
candidates.set(binding, target);
|
|
72
|
+
}
|
|
73
|
+
const aliases = new Map();
|
|
74
|
+
for (const [binding, target] of candidates) {
|
|
75
|
+
// Alias lookup below is name-based rather than position-aware. If a name
|
|
76
|
+
// is redeclared in another lexical scope, fail open instead of applying
|
|
77
|
+
// either module's constants to every use of that spelling.
|
|
78
|
+
if (declarationCounts.get(binding) === 1)
|
|
79
|
+
aliases.set(binding, target);
|
|
80
|
+
}
|
|
81
|
+
return aliases;
|
|
82
|
+
}
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
* └── symbols (SymbolTable) ← owns fileIndex + callableByName,
|
|
16
16
|
* calls dispatch() in add()
|
|
17
17
|
*
|
|
18
|
-
* ## Behavior groups (
|
|
18
|
+
* ## Behavior groups (4 hooks, 12 table entries)
|
|
19
19
|
*
|
|
20
20
|
* | Group | NodeLabel values | Hook | Skip callable? |
|
|
21
21
|
* |---------------|---------------------------------------------------|--------------|----------------|
|
|
22
|
-
* | class-like | Class, Struct, Interface, Enum, Record, Trait
|
|
22
|
+
* | class-like | Class, Protocol, Category, Struct, Interface, Enum, Record, Trait | classLikeHook | no |
|
|
23
23
|
* | method-like | Method, Constructor | methodHook | no |
|
|
24
24
|
* | property | Property | propertyHook | YES |
|
|
25
25
|
* | impl-block | Impl | implHook | no |
|
|
@@ -81,7 +81,7 @@ export interface RegistrationTableDeps {
|
|
|
81
81
|
* registry (if any) receives the symbol write during `SymbolTable.add()`:
|
|
82
82
|
*
|
|
83
83
|
* - `dispatch` — owner-scoped registry write via the dispatch table
|
|
84
|
-
* (Class/Struct/Interface/Enum/Record/Trait → types.registerClass,
|
|
84
|
+
* (Class/Protocol/Category/Struct/Interface/Enum/Record/Trait → types.registerClass,
|
|
85
85
|
* Method/Constructor → methods.register,
|
|
86
86
|
* Property → fields.register,
|
|
87
87
|
* Impl → types.registerImpl)
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
* └── symbols (SymbolTable) ← owns fileIndex + callableByName,
|
|
16
16
|
* calls dispatch() in add()
|
|
17
17
|
*
|
|
18
|
-
* ## Behavior groups (
|
|
18
|
+
* ## Behavior groups (4 hooks, 12 table entries)
|
|
19
19
|
*
|
|
20
20
|
* | Group | NodeLabel values | Hook | Skip callable? |
|
|
21
21
|
* |---------------|---------------------------------------------------|--------------|----------------|
|
|
22
|
-
* | class-like | Class, Struct, Interface, Enum, Record, Trait
|
|
22
|
+
* | class-like | Class, Protocol, Category, Struct, Interface, Enum, Record, Trait | classLikeHook | no |
|
|
23
23
|
* | method-like | Method, Constructor | methodHook | no |
|
|
24
24
|
* | property | Property | propertyHook | YES |
|
|
25
25
|
* | impl-block | Impl | implHook | no |
|
|
@@ -79,6 +79,8 @@ import { FREE_CALLABLE_TYPES } from './symbol-table.js';
|
|
|
79
79
|
const LABEL_BEHAVIOR = {
|
|
80
80
|
// dispatch — owner-scoped registry writes
|
|
81
81
|
Class: 'dispatch',
|
|
82
|
+
Protocol: 'dispatch',
|
|
83
|
+
Category: 'dispatch',
|
|
82
84
|
Struct: 'dispatch',
|
|
83
85
|
Interface: 'dispatch',
|
|
84
86
|
Enum: 'dispatch',
|
|
@@ -169,8 +171,8 @@ export const DISPATCH_LABELS = new Set(labelsWithBehavior('dispatch'));
|
|
|
169
171
|
*/
|
|
170
172
|
export const createRegistrationTable = (deps) => {
|
|
171
173
|
const { types, methods, fields } = deps;
|
|
172
|
-
// Hook 1: class-like — Class, Struct, Interface, Enum, Record, Trait.
|
|
173
|
-
// Shared reference —
|
|
174
|
+
// Hook 1: class-like — Class, Protocol, Category, Struct, Interface, Enum, Record, Trait.
|
|
175
|
+
// Shared reference — eight table entries point at this one closure.
|
|
174
176
|
const classLikeHook = (name, def) => {
|
|
175
177
|
const qualifiedKey = def.qualifiedName ?? name;
|
|
176
178
|
types.registerClass(name, qualifiedKey, def);
|
|
@@ -205,11 +207,13 @@ export const createRegistrationTable = (deps) => {
|
|
|
205
207
|
// classified as 'dispatch'. This is the compile-time twin of the
|
|
206
208
|
// runtime taxonomy — no drift possible.
|
|
207
209
|
const dispatchByLabel = {
|
|
208
|
-
// class-like —
|
|
210
|
+
// class-like — eight labels share the single `classLikeHook` closure,
|
|
209
211
|
// kept in lockstep with `CLASS_TYPES_TUPLE` via the
|
|
210
212
|
// `Record<ClassLikeLabel, 'dispatch'>` cross-invariant on
|
|
211
213
|
// `LABEL_BEHAVIOR`.
|
|
212
214
|
Class: classLikeHook,
|
|
215
|
+
Protocol: classLikeHook,
|
|
216
|
+
Category: classLikeHook,
|
|
213
217
|
Struct: classLikeHook,
|
|
214
218
|
Interface: classLikeHook,
|
|
215
219
|
Enum: classLikeHook,
|
|
@@ -52,7 +52,7 @@ import type { NodeLabel, ParameterTypeClass, SymbolDefinition } from '../../../_
|
|
|
52
52
|
* `impl Trait for Struct`, and Scala traits all contribute methods to the
|
|
53
53
|
* hierarchy of their using/implementing type.
|
|
54
54
|
*/
|
|
55
|
-
export declare const CLASS_TYPES_TUPLE: readonly ["Class", "Struct", "Interface", "Enum", "Record", "Trait"];
|
|
55
|
+
export declare const CLASS_TYPES_TUPLE: readonly ["Class", "Protocol", "Category", "Struct", "Interface", "Enum", "Record", "Trait"];
|
|
56
56
|
export type ClassLikeLabel = (typeof CLASS_TYPES_TUPLE)[number];
|
|
57
57
|
export declare const CLASS_TYPES: ReadonlySet<NodeLabel>;
|
|
58
58
|
/** Free-callable labels — single source of truth for "callables that have
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { SymbolDefinition } from '../../../_shared/index.js';
|
|
9
9
|
export interface TypeRegistry {
|
|
10
10
|
/**
|
|
11
|
-
* Look up class-like definitions (Class, Struct, Interface, Enum, Record, Trait)
|
|
11
|
+
* Look up class-like definitions (Class, Protocol, Category, Struct, Interface, Enum, Record, Trait)
|
|
12
12
|
* by simple name. Returns all matching definitions across files
|
|
13
13
|
* (e.g. partial classes). Returned array is a view into the live
|
|
14
14
|
* internal index — do not mutate.
|
|
@@ -3,6 +3,7 @@ import type { SymbolTableWriter } from './model/index.js';
|
|
|
3
3
|
import { type ExportedTypeMap } from './call-processor.js';
|
|
4
4
|
import type { ParsedFile } from '../../_shared/index.js';
|
|
5
5
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
6
|
+
import type { DispatchGroup } from './workers/worker-pool.js';
|
|
6
7
|
import type { ParseWorkerResult, ExtractedRoute, ExtractedFetchCall, ExtractedDecoratorRoute, ExtractedModuleConstants, ExtractedToolDef, FileScopeBindings, ExtractedORMQuery, FetchWrapperDef } from './workers/parse-worker.js';
|
|
7
8
|
import type { ExtractedRouterConstructorPrefix, ExtractedRouterImport, ExtractedRouterInclude, ExtractedRouterModuleAlias } from './route-extractors/fastapi-router-bindings.js';
|
|
8
9
|
import type { SharedSpringType } from './route-extractors/spring-shared.js';
|
|
@@ -47,12 +48,12 @@ export interface WorkerExtractedData {
|
|
|
47
48
|
*/
|
|
48
49
|
export declare const mergeChunkResults: (graph: KnowledgeGraph, symbolTable: SymbolTableWriter, chunkResults: readonly ParseWorkerResult[], exportedTypeMap?: ExportedTypeMap) => WorkerExtractedData;
|
|
49
50
|
/**
|
|
50
|
-
* Dispatch
|
|
51
|
-
* results, WITHOUT merging them into the graph.
|
|
52
|
-
* {@link
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
51
|
+
* Dispatch ONE chunk's files to the worker pool and return the RAW per-worker
|
|
52
|
+
* results, WITHOUT merging them into the graph. A thin single-group wrapper
|
|
53
|
+
* over {@link dispatchChunkParseRound}, used by {@link processParsing}'s
|
|
54
|
+
* one-shot path. The chunk-to-chunk overlap this once described now lives in
|
|
55
|
+
* `parse-impl.ts` at ROUND granularity (`startRound` / `drainRound` /
|
|
56
|
+
* `closeRound`), which batches several chunks into one dispatch.
|
|
56
57
|
* Returns `[]` for an all-unparseable chunk (the caller merges `[]` → empty).
|
|
57
58
|
*/
|
|
58
59
|
export declare const dispatchChunkParse: (files: {
|
|
@@ -67,6 +68,21 @@ outRawResults?: ParseWorkerResult[],
|
|
|
67
68
|
* (#2038). `undefined` ⇒ no durable write (tests / no-cache path).
|
|
68
69
|
*/
|
|
69
70
|
chunkHash?: string) => Promise<ParseWorkerResult[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Dispatch SEVERAL parse-cache chunks as one pool round and return their raw
|
|
73
|
+
* results, one array per input group in input order.
|
|
74
|
+
*
|
|
75
|
+
* `WorkerPool.dispatch` is a barrier, so one round-trip per chunk leaves most
|
|
76
|
+
* slots idle whenever a chunk is smaller than the pool — which stable
|
|
77
|
+
* `(language, hash(path) % 128)` packs usually are. Batching chunks into one
|
|
78
|
+
* `dispatchGroups` call removes those barriers; jobs are still cut at chunk
|
|
79
|
+
* boundaries, so every result stays attributable to the chunk whose cache key
|
|
80
|
+
* owns it.
|
|
81
|
+
*/
|
|
82
|
+
export declare const dispatchChunkParseRound: (groups: ReadonlyArray<DispatchGroup<{
|
|
83
|
+
path: string;
|
|
84
|
+
content: string;
|
|
85
|
+
}>>, workerPool: WorkerPool, onFileProgress?: FileProgressCallback) => Promise<ParseWorkerResult[][]>;
|
|
70
86
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|
|
71
87
|
path: string;
|
|
72
88
|
content: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getLanguageForFileContent } from './languages/index.js';
|
|
2
2
|
import { accumulateExportedTypesFromParsedNode } from './call-processor.js';
|
|
3
3
|
import { logger } from '../logger.js';
|
|
4
4
|
function compareText(left, right) {
|
|
@@ -147,12 +147,12 @@ export const mergeChunkResults = (graph, symbolTable, chunkResults, exportedType
|
|
|
147
147
|
};
|
|
148
148
|
};
|
|
149
149
|
/**
|
|
150
|
-
* Dispatch
|
|
151
|
-
* results, WITHOUT merging them into the graph.
|
|
152
|
-
* {@link
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
150
|
+
* Dispatch ONE chunk's files to the worker pool and return the RAW per-worker
|
|
151
|
+
* results, WITHOUT merging them into the graph. A thin single-group wrapper
|
|
152
|
+
* over {@link dispatchChunkParseRound}, used by {@link processParsing}'s
|
|
153
|
+
* one-shot path. The chunk-to-chunk overlap this once described now lives in
|
|
154
|
+
* `parse-impl.ts` at ROUND granularity (`startRound` / `drainRound` /
|
|
155
|
+
* `closeRound`), which batches several chunks into one dispatch.
|
|
156
156
|
* Returns `[]` for an all-unparseable chunk (the caller merges `[]` → empty).
|
|
157
157
|
*/
|
|
158
158
|
export const dispatchChunkParse = async (files, workerPool, onFileProgress,
|
|
@@ -164,23 +164,42 @@ outRawResults,
|
|
|
164
164
|
* (#2038). `undefined` ⇒ no durable write (tests / no-cache path).
|
|
165
165
|
*/
|
|
166
166
|
chunkHash) => {
|
|
167
|
-
const
|
|
168
|
-
for (const file of files) {
|
|
169
|
-
const lang = getLanguageFromFilename(file.path);
|
|
170
|
-
if (lang)
|
|
171
|
-
parseableFiles.push({ path: file.path, content: file.content });
|
|
172
|
-
}
|
|
173
|
-
if (parseableFiles.length === 0)
|
|
174
|
-
return [];
|
|
175
|
-
const total = files.length;
|
|
176
|
-
const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
|
|
177
|
-
onFileProgress?.(Math.min(filesProcessed, total), total, 'Parsing...');
|
|
178
|
-
}, chunkHash);
|
|
167
|
+
const [chunkResults = []] = await dispatchChunkParseRound([{ items: files, chunkHash }], workerPool, onFileProgress);
|
|
179
168
|
// Capture raw results for the incremental parse cache before merging.
|
|
180
169
|
if (outRawResults) {
|
|
181
170
|
for (const r of chunkResults)
|
|
182
171
|
outRawResults.push(r);
|
|
183
172
|
}
|
|
173
|
+
return chunkResults;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Dispatch SEVERAL parse-cache chunks as one pool round and return their raw
|
|
177
|
+
* results, one array per input group in input order.
|
|
178
|
+
*
|
|
179
|
+
* `WorkerPool.dispatch` is a barrier, so one round-trip per chunk leaves most
|
|
180
|
+
* slots idle whenever a chunk is smaller than the pool — which stable
|
|
181
|
+
* `(language, hash(path) % 128)` packs usually are. Batching chunks into one
|
|
182
|
+
* `dispatchGroups` call removes those barriers; jobs are still cut at chunk
|
|
183
|
+
* boundaries, so every result stays attributable to the chunk whose cache key
|
|
184
|
+
* owns it.
|
|
185
|
+
*/
|
|
186
|
+
export const dispatchChunkParseRound = async (groups, workerPool, onFileProgress) => {
|
|
187
|
+
const dispatchGroups = groups.map((group) => {
|
|
188
|
+
const items = [];
|
|
189
|
+
for (const file of group.items) {
|
|
190
|
+
const lang = getLanguageForFileContent(file.path, file.content);
|
|
191
|
+
if (lang)
|
|
192
|
+
items.push({ path: file.path, content: file.content });
|
|
193
|
+
}
|
|
194
|
+
return { items, chunkHash: group.chunkHash };
|
|
195
|
+
});
|
|
196
|
+
const total = groups.reduce((sum, group) => sum + group.items.length, 0);
|
|
197
|
+
if (dispatchGroups.every((group) => group.items.length === 0))
|
|
198
|
+
return groups.map(() => []);
|
|
199
|
+
const perGroup = await workerPool.dispatchGroups(dispatchGroups, (filesProcessed) => {
|
|
200
|
+
onFileProgress?.(Math.min(filesProcessed, total), total, 'Parsing...');
|
|
201
|
+
});
|
|
202
|
+
const chunkResults = perGroup.flat();
|
|
184
203
|
// Skipped-language telemetry (worker output, independent of the merge).
|
|
185
204
|
const skippedLanguages = new Map();
|
|
186
205
|
for (const result of chunkResults) {
|
|
@@ -238,7 +257,7 @@ chunkHash) => {
|
|
|
238
257
|
logger.warn(` Sanitized ${skippedPaths.length} file(s) with non-serializable parse output: ${shown}${more}`);
|
|
239
258
|
}
|
|
240
259
|
onFileProgress?.(total, total, 'done');
|
|
241
|
-
return
|
|
260
|
+
return perGroup;
|
|
242
261
|
};
|
|
243
262
|
// ============================================================================
|
|
244
263
|
// Public API
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { BindingAccumulator } from '../binding-accumulator.js';
|
|
18
18
|
import { type ExportedTypeMap } from '../call-processor.js';
|
|
19
19
|
import { type MutableSemanticModel } from '../model/index.js';
|
|
20
|
-
import { type PipelineProgress } from '../../../_shared/index.js';
|
|
20
|
+
import { type PipelineProgress, SupportedLanguages } from '../../../_shared/index.js';
|
|
21
21
|
import type { ExtractedDecoratorRoute, ExtractedFetchCall, ExtractedORMQuery, ExtractedRoute, ExtractedToolDef, FetchWrapperDef } from '../workers/parse-worker.js';
|
|
22
22
|
import type { ModuleConstants } from '../route-extractors/constant-resolver.js';
|
|
23
23
|
import type { KnowledgeGraph } from '../../graph/types.js';
|
|
@@ -104,6 +104,14 @@ export declare function runChunkedParseAndResolve(graph: KnowledgeGraph, scanned
|
|
|
104
104
|
* cache analyze run can skip the dominant `extractParsedFile` cost
|
|
105
105
|
* (otherwise ~58s on a 1000-file repo). */
|
|
106
106
|
parsedFiles: import('../../../_shared/index.js').ParsedFile[];
|
|
107
|
+
/**
|
|
108
|
+
* Content-derived language decisions for extension-ambiguous files.
|
|
109
|
+
*
|
|
110
|
+
* The source text used to classify these paths is released before parsing
|
|
111
|
+
* begins. Scope resolution consumes this snapshot instead of reading the
|
|
112
|
+
* same files again just to repeat classification.
|
|
113
|
+
*/
|
|
114
|
+
contentLanguageByPath: ReadonlyMap<string, SupportedLanguages | null>;
|
|
107
115
|
/** Repo-wide harvested constants, already prepared per provider. See
|
|
108
116
|
* `ParseOutput.moduleConstants` for why this leaves the parse phase. */
|
|
109
117
|
moduleConstants: ReadonlyMap<string, ModuleConstants>;
|