gitnexus 1.6.8-rc.2 → 1.6.8-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/README.md +20 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +4 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/ai-context.js +1 -0
- package/dist/cli/analyze-config.js +40 -0
- package/dist/cli/analyze.d.ts +22 -0
- package/dist/cli/analyze.js +36 -6
- package/dist/cli/clean.d.ts +1 -0
- package/dist/cli/clean.js +43 -1
- package/dist/cli/eval-server.js +43 -0
- package/dist/cli/help-i18n.js +11 -0
- package/dist/cli/i18n/en.d.ts +13 -0
- package/dist/cli/i18n/en.js +13 -0
- package/dist/cli/i18n/resources.d.ts +26 -0
- package/dist/cli/i18n/zh-CN.d.ts +13 -0
- package/dist/cli/i18n/zh-CN.js +13 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/list.js +12 -0
- package/dist/cli/optional-grammars.d.ts +6 -8
- package/dist/cli/optional-grammars.js +8 -11
- package/dist/cli/skill-gen.js +1 -0
- package/dist/cli/status.js +26 -5
- package/dist/cli/tool.d.ts +12 -1
- package/dist/cli/tool.js +41 -1
- package/dist/core/embeddings/embedder.js +4 -0
- package/dist/core/embeddings/embedding-pipeline.js +27 -16
- package/dist/core/embeddings/onnxruntime-common-resolver.d.ts +6 -0
- package/dist/core/embeddings/onnxruntime-common-resolver.js +130 -0
- package/dist/core/graph/import-cycles.d.ts +10 -0
- package/dist/core/graph/import-cycles.js +103 -0
- package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
- package/dist/core/group/extractors/http-patterns/java.js +3 -50
- package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
- package/dist/core/group/extractors/include-extractor.js +7 -7
- package/dist/core/ingestion/cfg/cfg-builder.d.ts +64 -0
- package/dist/core/ingestion/cfg/cfg-builder.js +129 -0
- package/dist/core/ingestion/cfg/collect.d.ts +30 -0
- package/dist/core/ingestion/cfg/collect.js +34 -0
- package/dist/core/ingestion/cfg/control-flow-context.d.ts +97 -0
- package/dist/core/ingestion/cfg/control-flow-context.js +113 -0
- package/dist/core/ingestion/cfg/emit.d.ts +144 -0
- package/dist/core/ingestion/cfg/emit.js +315 -0
- package/dist/core/ingestion/cfg/reaching-defs.d.ts +90 -0
- package/dist/core/ingestion/cfg/reaching-defs.js +364 -0
- package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
- package/dist/core/ingestion/cfg/traversal-result.js +2 -0
- package/dist/core/ingestion/cfg/types.d.ts +231 -0
- package/dist/core/ingestion/cfg/types.js +13 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +144 -0
- package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1032 -0
- package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
- package/dist/core/ingestion/cfg/visitors/typescript.js +584 -0
- package/dist/core/ingestion/language-provider.d.ts +36 -2
- package/dist/core/ingestion/languages/c-cpp.js +11 -4
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +6 -2
- package/dist/core/ingestion/languages/cpp/captures.js +24 -1
- package/dist/core/ingestion/languages/cpp/query.js +23 -0
- package/dist/core/ingestion/languages/java.js +3 -0
- package/dist/core/ingestion/languages/kotlin/query.js +3 -2
- package/dist/core/ingestion/languages/kotlin.js +5 -1
- package/dist/core/ingestion/languages/typescript.js +5 -0
- package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
- package/dist/core/ingestion/method-extractors/generic.js +1 -0
- package/dist/core/ingestion/method-types.d.ts +2 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +1 -0
- package/dist/core/ingestion/parsing-processor.js +22 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
- package/dist/core/ingestion/pipeline-phases/routes.js +64 -14
- package/dist/core/ingestion/pipeline.d.ts +57 -0
- package/dist/core/ingestion/route-extractors/spring-shared.d.ts +50 -0
- package/dist/core/ingestion/route-extractors/spring-shared.js +80 -0
- package/dist/core/ingestion/route-extractors/spring.d.ts +35 -0
- package/dist/core/ingestion/route-extractors/spring.js +136 -0
- package/dist/core/ingestion/scope-extractor.js +3 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +12 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +145 -24
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +6 -0
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +21 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +207 -0
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/taint/emit.d.ts +124 -0
- package/dist/core/ingestion/taint/emit.js +204 -0
- package/dist/core/ingestion/taint/match.d.ts +153 -0
- package/dist/core/ingestion/taint/match.js +278 -0
- package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
- package/dist/core/ingestion/taint/path-codec.js +190 -0
- package/dist/core/ingestion/taint/propagate.d.ts +216 -0
- package/dist/core/ingestion/taint/propagate.js +664 -0
- package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
- package/dist/core/ingestion/taint/site-safety.js +98 -0
- package/dist/core/ingestion/taint/source-sink-config.d.ts +94 -23
- package/dist/core/ingestion/taint/source-sink-config.js +11 -11
- package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
- package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
- package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
- package/dist/core/ingestion/taint/typescript-model.js +102 -0
- package/dist/core/ingestion/utils/method-props.js +1 -0
- package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
- package/dist/core/ingestion/workers/clone-safety.js +465 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +11 -0
- package/dist/core/ingestion/workers/parse-worker.js +70 -53
- package/dist/core/ingestion/workers/post-result.d.ts +22 -0
- package/dist/core/ingestion/workers/post-result.js +87 -0
- package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
- package/dist/core/ingestion/workers/result-merge.js +43 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +15 -0
- package/dist/core/ingestion/workers/worker-pool.js +33 -16
- package/dist/core/lbug/lbug-adapter.d.ts +19 -0
- package/dist/core/lbug/lbug-adapter.js +56 -1
- package/dist/core/run-analyze.d.ts +87 -0
- package/dist/core/run-analyze.js +280 -25
- package/dist/core/tree-sitter/parser-loader.js +5 -4
- package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
- package/dist/core/tree-sitter/vendored-grammars.js +57 -0
- package/dist/mcp/core/embedder.js +4 -0
- package/dist/mcp/local/local-backend.d.ts +86 -2
- package/dist/mcp/local/local-backend.js +657 -27
- package/dist/mcp/resources.js +1 -0
- package/dist/mcp/tools.d.ts +9 -0
- package/dist/mcp/tools.js +109 -0
- package/dist/server/analyze-launch.d.ts +29 -0
- package/dist/server/analyze-launch.js +137 -0
- package/dist/server/analyze-upload.d.ts +33 -0
- package/dist/server/analyze-upload.js +123 -0
- package/dist/server/analyze-worker-ipc.d.ts +58 -0
- package/dist/server/analyze-worker-ipc.js +16 -0
- package/dist/server/analyze-worker.d.ts +17 -1
- package/dist/server/analyze-worker.js +7 -1
- package/dist/server/api.js +46 -140
- package/dist/server/git-clone.d.ts +1 -0
- package/dist/server/git-clone.js +1 -1
- package/dist/server/middleware.d.ts +11 -0
- package/dist/server/middleware.js +27 -0
- package/dist/server/upload-ingest.d.ts +56 -0
- package/dist/server/upload-ingest.js +276 -0
- package/dist/server/upload-paths.d.ts +31 -0
- package/dist/server/upload-paths.js +51 -0
- package/dist/server/upload-sweep.d.ts +20 -0
- package/dist/server/upload-sweep.js +57 -0
- package/dist/storage/branch-index.d.ts +52 -0
- package/dist/storage/branch-index.js +65 -0
- package/dist/storage/git.d.ts +11 -0
- package/dist/storage/git.js +28 -0
- package/dist/storage/parse-cache.d.ts +22 -1
- package/dist/storage/parse-cache.js +32 -10
- package/dist/storage/repo-manager.d.ts +122 -10
- package/dist/storage/repo-manager.js +162 -21
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +42 -8
- package/hooks/claude/gitnexus-hook.cjs +36 -8
- package/hooks/claude/hook-db-lock-probe.cjs +123 -2
- package/package.json +4 -2
- package/scripts/assert-publish-grammar-coverage.cjs +31 -0
- package/scripts/build-tree-sitter-grammars.cjs +16 -10
- package/skills/gitnexus-guide.md +11 -0
- package/vendor/tree-sitter-c/package.json +1 -1
- package/vendor/tree-sitter-dart/package.json +1 -1
- package/vendor/tree-sitter-kotlin/package.json +1 -1
- package/vendor/tree-sitter-proto/package.json +1 -1
- package/vendor/tree-sitter-swift/package.json +1 -1
- package/web/assets/{agent-CKPMqImC.js → agent-ay4LD70X.js} +1 -1
- package/web/assets/{architectureDiagram-UL44E2DR-D1EXI0zA.js → architectureDiagram-UL44E2DR-Dc-viYhd.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-4rpojOyj.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-BnOy944n.js} +1 -1
- package/web/assets/{classDiagram-KGZ6W3CR-Bv93af_b.js → classDiagram-KGZ6W3CR-Bsgpy98Q.js} +1 -1
- package/web/assets/{classDiagram-v2-72OJOZXJ-CLfEqHUa.js → classDiagram-v2-72OJOZXJ-D5atDGjc.js} +1 -1
- package/web/assets/{diagram-3NCE3AQN-BqAtKUpW.js → diagram-3NCE3AQN-Cz1OEMVi.js} +1 -1
- package/web/assets/{diagram-GF46GFSD-CaBG6n6o.js → diagram-GF46GFSD-CWYwzfP8.js} +1 -1
- package/web/assets/{diagram-QXG6HAR7-CZ-O3rcV.js → diagram-QXG6HAR7-DtBObr8L.js} +1 -1
- package/web/assets/{diagram-WEQXMOUZ-P4lSL4GH.js → diagram-WEQXMOUZ-BUV44Ov_.js} +1 -1
- package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-Ds9s-sRF.js} +1 -1
- package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-CupStHQb.js} +1 -1
- package/web/assets/index-COMMmbxW.css +2 -0
- package/web/assets/{index-CG6q8eTs.js → index-Do8AE5yF.js} +85 -85
- package/web/assets/{infoDiagram-3YFTVSEB-DmLICZx1.js → infoDiagram-3YFTVSEB-DPTXSbgu.js} +1 -1
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CeK-Qhet.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-D4tx6QQ-.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-Bcto_kGa.js} +1 -1
- package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-DPIeBTG6.js} +1 -1
- package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-DDGXjVKO.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-BzDqpcVW.js} +1 -1
- package/web/assets/{stateDiagram-7D4R322I-CB2nABwH.js → stateDiagram-7D4R322I-Bx__als3.js} +1 -1
- package/web/assets/{stateDiagram-v2-36443NZ5-COBGd2RL.js → stateDiagram-v2-36443NZ5-QqOh2yO-.js} +1 -1
- package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-C1eogTOG.js} +1 -1
- package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-D20F4rSW.js} +1 -1
- package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-BeBHg7ST.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-CdOWeoNI.js} +1 -1
- package/web/index.html +2 -2
- package/scripts/materialize-vendor-grammars.cjs +0 -97
- package/web/assets/index-BKWA-m7o.css +0 -2
|
@@ -19,7 +19,10 @@ import type { MethodExtractor } from './method-types.js';
|
|
|
19
19
|
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
|
+
import type { CfgVisitor } from './cfg/types.js';
|
|
22
23
|
import type { NodeLabel } from '../../_shared/index.js';
|
|
24
|
+
import type Parser from 'tree-sitter';
|
|
25
|
+
import type { ExtractedDecoratorRoute } from './workers/parse-worker.js';
|
|
23
26
|
/** Tree-sitter query captures: capture name → AST node (or undefined if not captured). */
|
|
24
27
|
export type CaptureMap = Record<string, SyntaxNode | undefined>;
|
|
25
28
|
/** Configuration for AST-based framework detection patterns. */
|
|
@@ -145,6 +148,12 @@ interface LanguageProviderConfig {
|
|
|
145
148
|
* `undefined` when no constraints exist / the node isn't a templated
|
|
146
149
|
* function. Languages without SFINAE / concept semantics leave this
|
|
147
150
|
* undefined and the disambiguation is a pass-through.
|
|
151
|
+
*
|
|
152
|
+
* Cloneability contract: the returned payload crosses the worker boundary
|
|
153
|
+
* via structured clone, so it MUST be structured-clone-safe (no functions,
|
|
154
|
+
* symbols, or tree-sitter `SyntaxNode`s — only plain data). Wrap the return
|
|
155
|
+
* with `assertCloneable` from `workers/clone-safety.ts` so a future leak is a
|
|
156
|
+
* compile error at the source instead of a runtime DataCloneError (#2143).
|
|
148
157
|
*/
|
|
149
158
|
readonly extractTemplateConstraints?: (definitionNode: SyntaxNode) => unknown;
|
|
150
159
|
/** Override the default node label for definition.function captures.
|
|
@@ -185,6 +194,17 @@ interface LanguageProviderConfig {
|
|
|
185
194
|
* When true, the worker extracts routes via the language's route extraction logic.
|
|
186
195
|
* Default: undefined (no route files). */
|
|
187
196
|
readonly isRouteFile?: (filePath: string) => boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Extract decorator-style route annotations from a parsed file.
|
|
199
|
+
*
|
|
200
|
+
* When defined, the parse worker calls this after per-file capture processing
|
|
201
|
+
* to extract framework route definitions that require AST-level analysis beyond
|
|
202
|
+
* generic `@decorator` captures (e.g., Java Spring class-level prefix joining,
|
|
203
|
+
* multi-class handling). The returned routes are appended to `decoratorRoutes`.
|
|
204
|
+
*
|
|
205
|
+
* Default: undefined (no language-specific decorator route extraction).
|
|
206
|
+
*/
|
|
207
|
+
readonly extractDecoratorRoutes?: (tree: Parser.Tree, filePath: string, lineOffset: number) => ExtractedDecoratorRoute[];
|
|
188
208
|
/** Built-in/stdlib names that should be filtered from the call graph for this language.
|
|
189
209
|
* Default: undefined (no language-specific filtering). */
|
|
190
210
|
readonly builtInNames?: ReadonlySet<string>;
|
|
@@ -255,12 +275,26 @@ interface LanguageProviderConfig {
|
|
|
255
275
|
* disk store WITHOUT a main-thread re-parse. The main thread restores them
|
|
256
276
|
* via the matching `ScopeResolver.applyCaptureSideChannel` hook.
|
|
257
277
|
*
|
|
258
|
-
* MUST return plain data (objects / arrays /
|
|
259
|
-
*
|
|
278
|
+
* Cloneability contract: MUST return plain data (objects / arrays /
|
|
279
|
+
* primitives — no functions, symbols, or tree-sitter `SyntaxNode`s) so it
|
|
280
|
+
* survives BOTH the worker→main structured clone AND `JSON.stringify` + the
|
|
281
|
+
* parsedfile-store interning reviver. Wrap the return with `assertCloneable`
|
|
282
|
+
* from `workers/clone-safety.ts` so a future non-serializable leak is a
|
|
283
|
+
* compile error at the source instead of a runtime DataCloneError (#2143).
|
|
260
284
|
*
|
|
261
285
|
* Default: undefined (provider has no capture-time module-level side effects).
|
|
262
286
|
*/
|
|
263
287
|
readonly collectCaptureSideChannel?: (filePath: string) => unknown;
|
|
288
|
+
/**
|
|
289
|
+
* Per-language control-flow-graph builder (#2081 M1, PDG/taint substrate).
|
|
290
|
+
* Invoked IN THE PARSE WORKER (where the AST lives) for each function node,
|
|
291
|
+
* gated on the `--pdg` opt-in; the resulting per-function CFGs are serialized
|
|
292
|
+
* onto `ParsedFile.cfgSideChannel` and emitted as BasicBlock nodes + CFG
|
|
293
|
+
* edges during scope-resolution. `TNode` is `SyntaxNode` for the tree-sitter
|
|
294
|
+
* languages. Default: undefined (language has no CFG support yet — TS/JS are
|
|
295
|
+
* the M1 set).
|
|
296
|
+
*/
|
|
297
|
+
readonly cfgVisitor?: CfgVisitor<SyntaxNode>;
|
|
264
298
|
/**
|
|
265
299
|
* Interpret a raw `@import.statement` capture group into a `ParsedImport`.
|
|
266
300
|
* The central finalize algorithm resolves `ParsedImport.targetRaw` to a
|
|
@@ -38,7 +38,8 @@ import { cCallConfig, cppCallConfig } from '../call-extractors/configs/c-cpp.js'
|
|
|
38
38
|
import { stripUeMacros } from '../cpp-ue-preprocessor.js';
|
|
39
39
|
import { emitCScopeCaptures, interpretCImport, interpretCTypeBinding, cArityCompatibility, cBindingScopeFor, cImportOwningScope, cReceiverBinding, collectCStaticLinkageSideChannel, } from './c/index.js';
|
|
40
40
|
import { emitCppScopeCaptures, interpretCppImport, interpretCppTypeBinding, cppArityCompatibility, cppBindingScopeFor, cppImportOwningScope, cppReceiverBinding, collectCppCaptureSideChannel, } from './cpp/index.js';
|
|
41
|
-
import { extractCppTemplateConstraints } from './cpp/constraint-extractor.js';
|
|
41
|
+
import { extractCppTemplateConstraints, } from './cpp/constraint-extractor.js';
|
|
42
|
+
import { assertCloneable } from '../workers/clone-safety.js';
|
|
42
43
|
const C_BUILT_INS = new Set([
|
|
43
44
|
'printf',
|
|
44
45
|
'fprintf',
|
|
@@ -358,7 +359,10 @@ export const cProvider = defineLanguage({
|
|
|
358
359
|
// `static` functions look non-file-local on the main thread and leak into
|
|
359
360
|
// cross-file global free-call resolution / wildcard imports. See
|
|
360
361
|
// `c/capture-side-channel.ts`.
|
|
361
|
-
|
|
362
|
+
// `assertCloneable` is a runtime identity; it makes a future non-serializable
|
|
363
|
+
// value in the side-channel payload a compile error here, at the source, rather
|
|
364
|
+
// than a DataCloneError at the worker boundary (#2143).
|
|
365
|
+
collectCaptureSideChannel: (filePath) => assertCloneable(collectCStaticLinkageSideChannel(filePath)),
|
|
362
366
|
interpretImport: interpretCImport,
|
|
363
367
|
interpretTypeBinding: interpretCTypeBinding,
|
|
364
368
|
bindingScopeFor: cBindingScopeFor,
|
|
@@ -431,7 +435,7 @@ export const cppProvider = defineLanguage({
|
|
|
431
435
|
// just populated for this file into plain data on `ParsedFile.captureSideChannel`,
|
|
432
436
|
// so the main thread can restore them via `applyCaptureSideChannel` WITHOUT a
|
|
433
437
|
// re-parse (#1983). See `cpp/capture-side-channel.ts`.
|
|
434
|
-
collectCaptureSideChannel: collectCppCaptureSideChannel,
|
|
438
|
+
collectCaptureSideChannel: (filePath) => assertCloneable(collectCppCaptureSideChannel(filePath)),
|
|
435
439
|
interpretImport: interpretCppImport,
|
|
436
440
|
interpretTypeBinding: interpretCppTypeBinding,
|
|
437
441
|
bindingScopeFor: cppBindingScopeFor,
|
|
@@ -482,5 +486,8 @@ function extractCppTemplateConstraintsForProvider(definitionNode) {
|
|
|
482
486
|
}
|
|
483
487
|
break;
|
|
484
488
|
}
|
|
485
|
-
|
|
489
|
+
// Guard the boundary at the source: a future non-cloneable member of the
|
|
490
|
+
// constraint payload becomes a compile error here, not a runtime
|
|
491
|
+
// DataCloneError at the worker post (#2143).
|
|
492
|
+
return assertCloneable(extractCppTemplateConstraints(templateDecl, declarator));
|
|
486
493
|
}
|
|
@@ -193,8 +193,12 @@ function findFuncDeclarator(node) {
|
|
|
193
193
|
}
|
|
194
194
|
return null;
|
|
195
195
|
}
|
|
196
|
-
// Unwrap
|
|
197
|
-
|
|
196
|
+
// Unwrap declarator wrappers. Deleted free functions are represented as
|
|
197
|
+
// `init_declarator(function_declarator, delete_expression)` by
|
|
198
|
+
// tree-sitter-cpp 0.23.
|
|
199
|
+
while (decl.type === 'pointer_declarator' ||
|
|
200
|
+
decl.type === 'reference_declarator' ||
|
|
201
|
+
decl.type === 'init_declarator') {
|
|
198
202
|
const next = decl.childForFieldName('declarator');
|
|
199
203
|
if (next === null) {
|
|
200
204
|
// reference_declarator may not use field name
|
|
@@ -113,6 +113,9 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
|
|
|
113
113
|
if (hasExplicitSpecifier(fnNode)) {
|
|
114
114
|
grouped['@declaration.is-explicit'] = syntheticCapture('@declaration.is-explicit', fnNode, 'true');
|
|
115
115
|
}
|
|
116
|
+
if (hasDeletedMethodClause(fnNode, grouped['@declaration.name']?.text)) {
|
|
117
|
+
grouped['@declaration.is-deleted'] = syntheticCapture('@declaration.is-deleted', fnNode, 'true');
|
|
118
|
+
}
|
|
116
119
|
// Detect static storage class (file-local linkage)
|
|
117
120
|
if (hasStaticStorageClass(fnNode)) {
|
|
118
121
|
const nameText = grouped['@declaration.name']?.text;
|
|
@@ -1562,8 +1565,11 @@ function extractDeclaratorLeafName(node) {
|
|
|
1562
1565
|
let cur = node;
|
|
1563
1566
|
let safety = 16;
|
|
1564
1567
|
while (safety-- > 0) {
|
|
1565
|
-
if (cur.type === 'identifier' ||
|
|
1568
|
+
if (cur.type === 'identifier' ||
|
|
1569
|
+
cur.type === 'type_identifier' ||
|
|
1570
|
+
cur.type === 'operator_name') {
|
|
1566
1571
|
return cur.text;
|
|
1572
|
+
}
|
|
1567
1573
|
// Common wrapper nodes — follow the 'declarator' field when present.
|
|
1568
1574
|
const next = cur.childForFieldName('declarator') ??
|
|
1569
1575
|
// parenthesized_declarator: single named child
|
|
@@ -1590,6 +1596,23 @@ function hasExplicitSpecifier(node) {
|
|
|
1590
1596
|
}
|
|
1591
1597
|
return /\bexplicit\b/.test(node.text.slice(0, 128));
|
|
1592
1598
|
}
|
|
1599
|
+
function hasDeletedMethodClause(node, callableName) {
|
|
1600
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
1601
|
+
const child = node.namedChild(i);
|
|
1602
|
+
if (child?.type === 'delete_method_clause')
|
|
1603
|
+
return true;
|
|
1604
|
+
// tree-sitter-cpp 0.23 parses a deleted free-function declaration as
|
|
1605
|
+
// `declaration > init_declarator > delete_expression`, while class
|
|
1606
|
+
// members use the dedicated `delete_method_clause`.
|
|
1607
|
+
if (child?.type === 'init_declarator' &&
|
|
1608
|
+
child.childForFieldName('value')?.type === 'delete_expression' &&
|
|
1609
|
+
callableName !== undefined &&
|
|
1610
|
+
extractDeclaratorLeafName(child.childForFieldName('declarator') ?? child) === callableName) {
|
|
1611
|
+
return true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1593
1616
|
/**
|
|
1594
1617
|
* Check if a C++ function_definition or declaration has `static` storage class.
|
|
1595
1618
|
*/
|
|
@@ -193,6 +193,29 @@ const CPP_SCOPE_QUERY = `
|
|
|
193
193
|
declarator: (function_declarator
|
|
194
194
|
declarator: (identifier) @declaration.name)) @declaration.function
|
|
195
195
|
|
|
196
|
+
;; tree-sitter-cpp 0.23 represents a deleted free function as an
|
|
197
|
+
;; init_declarator whose value is a delete_expression.
|
|
198
|
+
(declaration
|
|
199
|
+
declarator: (init_declarator
|
|
200
|
+
declarator: (function_declarator
|
|
201
|
+
declarator: (identifier) @declaration.name)
|
|
202
|
+
value: (delete_expression))) @declaration.function
|
|
203
|
+
|
|
204
|
+
;; Deleted free operator declaration.
|
|
205
|
+
(declaration
|
|
206
|
+
declarator: (init_declarator
|
|
207
|
+
declarator: (function_declarator
|
|
208
|
+
declarator: (operator_name) @declaration.name)
|
|
209
|
+
value: (delete_expression))) @declaration.function
|
|
210
|
+
|
|
211
|
+
;; Deleted free function with a pointer return type.
|
|
212
|
+
(declaration
|
|
213
|
+
declarator: (init_declarator
|
|
214
|
+
declarator: (pointer_declarator
|
|
215
|
+
declarator: (function_declarator
|
|
216
|
+
declarator: (identifier) @declaration.name))
|
|
217
|
+
value: (delete_expression))) @declaration.function
|
|
218
|
+
|
|
196
219
|
;; Free operator prototype: std::ostream& operator<<(std::ostream&, T)
|
|
197
220
|
(declaration
|
|
198
221
|
declarator: (function_declarator
|
|
@@ -11,6 +11,7 @@ import { createClassExtractor } from '../class-extractors/generic.js';
|
|
|
11
11
|
import { javaClassConfig } from '../class-extractors/configs/jvm.js';
|
|
12
12
|
import { defineLanguage } from '../language-provider.js';
|
|
13
13
|
import { javaTypeConfig } from '../type-extractors/jvm.js';
|
|
14
|
+
import { extractSpringRoutes } from '../route-extractors/spring.js';
|
|
14
15
|
import { javaExportChecker } from '../export-detection.js';
|
|
15
16
|
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
|
16
17
|
import { javaImportConfig } from '../import-resolvers/configs/jvm.js';
|
|
@@ -103,4 +104,6 @@ export const javaProvider = defineLanguage({
|
|
|
103
104
|
arityCompatibility: javaArityCompatibility,
|
|
104
105
|
resolveImportTarget: resolveJavaImportTarget,
|
|
105
106
|
orderSameNameTypeCandidates: orderJavaSameNameTypeCandidates,
|
|
107
|
+
// ── Route extraction ──
|
|
108
|
+
extractDecoratorRoutes: extractSpringRoutes,
|
|
106
109
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Parser from 'tree-sitter';
|
|
2
2
|
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
3
|
-
// `tree-sitter-kotlin` is
|
|
4
|
-
//
|
|
3
|
+
// `tree-sitter-kotlin` is a vendored grammar (loaded from vendor/ by absolute
|
|
4
|
+
// path, never node_modules — vendored-grammars.ts / #2111) that may be absent on
|
|
5
|
+
// a platform without a matching prebuild. Loaded lazily + guarded via parser-loader
|
|
5
6
|
// rather than statically imported: this module is pulled onto the main thread
|
|
6
7
|
// eagerly by the scope-resolution registry and the language-provider index, so
|
|
7
8
|
// a top-level `import Kotlin from 'tree-sitter-kotlin'` would throw
|
|
@@ -10,6 +10,7 @@ import { SupportedLanguages } from '../../../_shared/index.js';
|
|
|
10
10
|
import { createClassExtractor } from '../class-extractors/generic.js';
|
|
11
11
|
import { kotlinClassConfig } from '../class-extractors/configs/jvm.js';
|
|
12
12
|
import { defineLanguage } from '../language-provider.js';
|
|
13
|
+
import { assertCloneable } from '../workers/clone-safety.js';
|
|
13
14
|
import { kotlinTypeConfig } from '../type-extractors/jvm.js';
|
|
14
15
|
import { kotlinExportChecker } from '../export-detection.js';
|
|
15
16
|
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
|
@@ -166,7 +167,10 @@ export const kotlinProvider = defineLanguage({
|
|
|
166
167
|
// so the main thread can restore them via `applyCaptureSideChannel` WITHOUT a
|
|
167
168
|
// re-parse (#1983). Without this, companion/static dispatch emits no CALLS
|
|
168
169
|
// edges on the worker path. See `kotlin/capture-side-channel.ts`.
|
|
169
|
-
|
|
170
|
+
// `assertCloneable` is a runtime identity; it makes a future non-serializable
|
|
171
|
+
// value in the side-channel payload a compile error here, at the source, rather
|
|
172
|
+
// than a DataCloneError at the worker boundary (#2143).
|
|
173
|
+
collectCaptureSideChannel: (filePath) => assertCloneable(collectKotlinCaptureSideChannel(filePath)),
|
|
170
174
|
interpretImport: interpretKotlinImport,
|
|
171
175
|
interpretTypeBinding: interpretKotlinTypeBinding,
|
|
172
176
|
bindingScopeFor: kotlinBindingScopeFor,
|
|
@@ -9,6 +9,7 @@ import { SupportedLanguages } from '../../../_shared/index.js';
|
|
|
9
9
|
import { defineLanguage } from '../language-provider.js';
|
|
10
10
|
import { createClassExtractor } from '../class-extractors/generic.js';
|
|
11
11
|
import { typescriptClassConfig, javascriptClassConfig, } from '../class-extractors/configs/typescript-javascript.js';
|
|
12
|
+
import { createTypeScriptCfgVisitor } from '../cfg/visitors/typescript.js';
|
|
12
13
|
import { typeConfig as typescriptConfig } from '../type-extractors/typescript.js';
|
|
13
14
|
import { tsExportChecker } from '../export-detection.js';
|
|
14
15
|
import { createImportResolver } from '../import-resolvers/resolver-factory.js';
|
|
@@ -293,6 +294,8 @@ export const typescriptProvider = defineLanguage({
|
|
|
293
294
|
// canonical capture vocabulary in ./typescript/query.ts
|
|
294
295
|
// (TYPESCRIPT_SCOPE_QUERY constant).
|
|
295
296
|
emitScopeCaptures: emitTsScopeCaptures,
|
|
297
|
+
// CFG/PDG substrate (#2081 M1) — runs in the worker on a --pdg run.
|
|
298
|
+
cfgVisitor: createTypeScriptCfgVisitor(),
|
|
296
299
|
interpretImport: interpretTsImport,
|
|
297
300
|
interpretTypeBinding: interpretTsTypeBinding,
|
|
298
301
|
bindingScopeFor: tsBindingScopeFor,
|
|
@@ -352,6 +355,8 @@ export const javascriptProvider = defineLanguage({
|
|
|
352
355
|
// JSDoc type bindings) live in ./javascript/captures.ts.
|
|
353
356
|
// See ./javascript/index.ts for the full per-module rationale.
|
|
354
357
|
emitScopeCaptures: emitJsScopeCaptures,
|
|
358
|
+
// CFG/PDG substrate (#2081 M1) — TS and JS share the same grammar family.
|
|
359
|
+
cfgVisitor: createTypeScriptCfgVisitor(),
|
|
355
360
|
interpretImport: interpretJsImport,
|
|
356
361
|
interpretTypeBinding: interpretJsTypeBinding,
|
|
357
362
|
bindingScopeFor: jsBindingScopeFor,
|
|
@@ -33,18 +33,12 @@ function findFunctionDeclarator(node) {
|
|
|
33
33
|
}
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
* These are not callable methods and should be suppressed from extraction.
|
|
39
|
-
* tree-sitter-cpp ^0.23.4 emits `delete_method_clause` / `default_method_clause`
|
|
40
|
-
* as named children of the function_definition node.
|
|
41
|
-
*/
|
|
42
|
-
function isDeletedOrDefaulted(node) {
|
|
36
|
+
/** Detect a C++ special member clause by its tree-sitter node type. */
|
|
37
|
+
function hasSpecialMethodClause(node, clauseType) {
|
|
43
38
|
for (let i = 0; i < node.namedChildCount; i++) {
|
|
44
39
|
const child = node.namedChild(i);
|
|
45
|
-
if (child?.type ===
|
|
40
|
+
if (child?.type === clauseType)
|
|
46
41
|
return true;
|
|
47
|
-
}
|
|
48
42
|
}
|
|
49
43
|
return false;
|
|
50
44
|
}
|
|
@@ -57,10 +51,6 @@ function extractCppMethodName(node) {
|
|
|
57
51
|
const funcDecl = findFunctionDeclarator(node);
|
|
58
52
|
if (!funcDecl)
|
|
59
53
|
return undefined;
|
|
60
|
-
// Suppress `= delete` and `= default` special members — these are not callable
|
|
61
|
-
// methods and should not appear in HAS_METHOD edges.
|
|
62
|
-
if (isDeletedOrDefaulted(node))
|
|
63
|
-
return undefined;
|
|
64
54
|
const nameNode = funcDecl.childForFieldName('declarator');
|
|
65
55
|
if (!nameNode)
|
|
66
56
|
return undefined;
|
|
@@ -360,6 +350,9 @@ export const cppMethodConfig = {
|
|
|
360
350
|
}
|
|
361
351
|
return false;
|
|
362
352
|
},
|
|
353
|
+
isDeleted(node) {
|
|
354
|
+
return hasSpecialMethodClause(node, 'delete_method_clause');
|
|
355
|
+
},
|
|
363
356
|
};
|
|
364
357
|
// ---------------------------------------------------------------------------
|
|
365
358
|
// C config (minimal — C has no classes/methods, only struct function pointers)
|
|
@@ -198,6 +198,7 @@ function buildMethod(node, ownerNode, context, config) {
|
|
|
198
198
|
...(config.isAsync?.(node) ? { isAsync: true } : {}),
|
|
199
199
|
...(config.isPartial?.(node) ? { isPartial: true } : {}),
|
|
200
200
|
...(config.isConst?.(node) ? { isConst: true } : {}),
|
|
201
|
+
...(config.isDeleted?.(node) ? { isDeleted: true } : {}),
|
|
201
202
|
annotations: config.extractAnnotations?.(node) ?? [],
|
|
202
203
|
sourceFile: context.filePath,
|
|
203
204
|
line: node.startPosition.row + 1,
|
|
@@ -27,6 +27,7 @@ export interface MethodInfo {
|
|
|
27
27
|
isAsync?: boolean;
|
|
28
28
|
isPartial?: boolean;
|
|
29
29
|
isConst?: boolean;
|
|
30
|
+
isDeleted?: boolean;
|
|
30
31
|
annotations: string[];
|
|
31
32
|
sourceFile: string;
|
|
32
33
|
line: number;
|
|
@@ -74,6 +75,7 @@ export interface MethodExtractionConfig {
|
|
|
74
75
|
isAsync?: (node: SyntaxNode) => boolean;
|
|
75
76
|
isPartial?: (node: SyntaxNode) => boolean;
|
|
76
77
|
isConst?: (node: SyntaxNode) => boolean;
|
|
78
|
+
isDeleted?: (node: SyntaxNode) => boolean;
|
|
77
79
|
/** Owner node types where member functions are effectively static (e.g.
|
|
78
80
|
* Ruby singleton_class, Kotlin companion_object / object_declaration).
|
|
79
81
|
* When the ownerNode matches one of these types, isStatic is forced true. */
|
|
@@ -136,6 +136,7 @@ export const createSymbolTable = () => {
|
|
|
136
136
|
? { templateArguments: metadata.templateArguments }
|
|
137
137
|
: {}),
|
|
138
138
|
...(metadata?.ownerId !== undefined ? { ownerId: metadata.ownerId } : {}),
|
|
139
|
+
...(metadata?.isDeleted === true ? { isDeleted: true } : {}),
|
|
139
140
|
};
|
|
140
141
|
// A. File Index — unconditional.
|
|
141
142
|
if (!fileIndex.has(filePath)) {
|
|
@@ -49,6 +49,7 @@ export const mergeChunkResults = (graph, symbolTable, chunkResults, exportedType
|
|
|
49
49
|
templateArguments: sym.templateArguments,
|
|
50
50
|
ownerId: sym.ownerId,
|
|
51
51
|
qualifiedName: sym.qualifiedName,
|
|
52
|
+
isDeleted: sym.isDeleted,
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
55
|
if (exportedTypeMap) {
|
|
@@ -144,6 +145,27 @@ chunkHash) => {
|
|
|
144
145
|
.join(', ');
|
|
145
146
|
logger.warn(` Skipped unsupported languages: ${summary}`);
|
|
146
147
|
}
|
|
148
|
+
// Clone-safety telemetry (#2112): files whose parse output carried a value
|
|
149
|
+
// the structured-clone algorithm couldn't serialize across the worker
|
|
150
|
+
// boundary. The worker sanitized/dropped the offending value so the run
|
|
151
|
+
// could complete; surface the (rare) data loss so it's visible and the
|
|
152
|
+
// offending extractor can be fixed at source.
|
|
153
|
+
const skippedPaths = [];
|
|
154
|
+
for (const result of chunkResults) {
|
|
155
|
+
for (const entry of result.skippedPaths ?? [])
|
|
156
|
+
skippedPaths.push(entry);
|
|
157
|
+
}
|
|
158
|
+
if (skippedPaths.length > 0) {
|
|
159
|
+
// Keep the per-file reason ("stripped N value(s) from nodes" /
|
|
160
|
+
// "dropped non-serializable parsedFiles entry") — it distinguishes a
|
|
161
|
+
// recoverable strip from a whole-record drop, which a path-only line loses.
|
|
162
|
+
const shown = skippedPaths
|
|
163
|
+
.slice(0, 10)
|
|
164
|
+
.map((e) => `${e.path} (${e.reason})`)
|
|
165
|
+
.join(', ');
|
|
166
|
+
const more = skippedPaths.length > 10 ? ` …and ${skippedPaths.length - 10} more` : '';
|
|
167
|
+
logger.warn(` Sanitized ${skippedPaths.length} file(s) with non-serializable parse output: ${shown}${more}`);
|
|
168
|
+
}
|
|
147
169
|
onFileProgress?.(total, total, 'done');
|
|
148
170
|
return chunkResults;
|
|
149
171
|
};
|
|
@@ -18,6 +18,7 @@ import { BindingAccumulator, enrichExportedTypeMap, } from '../binding-accumulat
|
|
|
18
18
|
import { mergeChunkResults, dispatchChunkParse } from '../parsing-processor.js';
|
|
19
19
|
import { fileContentHash, computeChunkHash, loadParseCacheChunk, persistParseCacheChunk, PARSE_CACHE_VERSION, } from '../../../storage/parse-cache.js';
|
|
20
20
|
import { clearParsedFileStore, persistParsedFileChunk, getDurableParsedFileDir, loadDurableParsedFileIndex, restoreDurableParsedFileShard, } from '../../../storage/parsedfile-store.js';
|
|
21
|
+
import { DEFAULT_PDG_MAX_FUNCTION_LINES } from '../cfg/collect.js';
|
|
21
22
|
import { processRoutesFromExtracted, buildExportedTypeMapFromGraph, } from '../call-processor.js';
|
|
22
23
|
import { createSemanticModel } from '../model/index.js';
|
|
23
24
|
import { getLanguageFromFilename, } from '../../../_shared/index.js';
|
|
@@ -319,6 +320,10 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
|
|
|
319
320
|
// Initialized below before the chunk loop (same deferred-init pattern
|
|
320
321
|
// as `parsedFileStorePath`); this closure only runs from the loop.
|
|
321
322
|
durableParsedFileStoragePath: durableParsedFileDir,
|
|
323
|
+
// CFG/PDG opt-in (#2081 M1) — baked into each worker's workerData so the
|
|
324
|
+
// worker builds + attaches cfgSideChannel. Off by default.
|
|
325
|
+
pdg: options?.pdg === true,
|
|
326
|
+
pdgMaxFunctionLines: options?.pdgMaxFunctionLines,
|
|
322
327
|
// Fan each chunk across the whole pool (#worker-idle): without this a
|
|
323
328
|
// chunk smaller than the 8 MB sub-batch cap became a single job on a
|
|
324
329
|
// single worker. Honors an explicit `subBatchMaxBytes` / env override.
|
|
@@ -566,7 +571,19 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
|
|
|
566
571
|
filePath: f.path,
|
|
567
572
|
contentHash: fileContentHash(f.content),
|
|
568
573
|
}));
|
|
569
|
-
chunkHash = computeChunkHash(entries
|
|
574
|
+
chunkHash = computeChunkHash(entries,
|
|
575
|
+
// Only worker-visible pdg config participates in the key —
|
|
576
|
+
// pdgMaxEdgesPerFunction is emit-time-only and deliberately
|
|
577
|
+
// excluded (see PdgCacheKey in parse-cache.ts; #2099 F3). The line
|
|
578
|
+
// cap is RESOLVED to the worker's default before folding so an
|
|
579
|
+
// explicit-default run shares the default run's keys (the worker
|
|
580
|
+
// output is byte-identical either way).
|
|
581
|
+
options?.pdg === true
|
|
582
|
+
? {
|
|
583
|
+
pdg: true,
|
|
584
|
+
maxFunctionLines: options?.pdgMaxFunctionLines ?? DEFAULT_PDG_MAX_FUNCTION_LINES,
|
|
585
|
+
}
|
|
586
|
+
: false);
|
|
570
587
|
}
|
|
571
588
|
const cachedRaw = chunkHash && parseCache ? await loadParseCacheChunk(parseCache, chunkHash) : undefined;
|
|
572
589
|
// Track every chunk hash we touched so the orchestrator can
|
|
@@ -297,22 +297,72 @@ export const routesPhase = {
|
|
|
297
297
|
// scan JS/TS consumer files for calls to those wrapper functions with
|
|
298
298
|
// URL-like string arguments and add them to allFetchCalls so
|
|
299
299
|
// processNextjsFetchRoutes can create FETCHES edges.
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
// Wrapper names come from two sources: functions the parse phase
|
|
301
|
+
// auto-detected as calling the bare global `fetch()`, plus any names the
|
|
302
|
+
// user declared in `.gitnexusrc` `fetchWrappers` (#1589/#1852 residual).
|
|
303
|
+
// Config names let an axios/custom-client wrapper — or one named outside the
|
|
304
|
+
// built-in convention — still produce route_map consumers; without them it
|
|
305
|
+
// silently falls back to `consumers: []`. Configured names alone are enough
|
|
306
|
+
// to run the scan even when nothing was auto-detected.
|
|
307
|
+
// Configured names are already validated/trimmed/de-duped/capped by
|
|
308
|
+
// analyze-config.ts — trusted as-is (#1589/#1852 review F9, dropped the
|
|
309
|
+
// redundant re-trim/re-filter). The single filter below guards only the
|
|
310
|
+
// auto-detected `functionName`s, which have no shape guarantee.
|
|
311
|
+
const configuredWrappers = ctx.options?.fetchWrappers ?? [];
|
|
312
|
+
const wrapperNames = new Set([...(allFetchWrapperDefs ?? []).map((d) => d.functionName), ...configuredWrappers].filter((n) => typeof n === 'string' && n.trim().length > 0));
|
|
313
|
+
if (wrapperNames.size > 0 && routeRegistry.size > 0) {
|
|
302
314
|
const jsFiles = allPaths.filter((p) => /\.[jt]sx?$/.test(p));
|
|
303
|
-
if (jsFiles.length > 0
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
+
if (jsFiles.length > 0) {
|
|
316
|
+
// Reuse contents already read for handler extraction; only read the
|
|
317
|
+
// remainder (mirrors the Expo block above). Avoids a second full read of
|
|
318
|
+
// files we already have in memory.
|
|
319
|
+
const unreadJsFiles = jsFiles.filter((p) => !handlerContents?.has(p));
|
|
320
|
+
const extraContents = unreadJsFiles.length > 0
|
|
321
|
+
? await readFileContents(ctx.repoPath, unreadJsFiles)
|
|
322
|
+
: new Map();
|
|
323
|
+
// One alternation regex over every wrapper name per file — O(files), not
|
|
324
|
+
// O(files × wrappers) (#1852 review F3). Names are escaped and grouped
|
|
325
|
+
// non-capturing so capture group 1 stays the URL. The left boundary is a
|
|
326
|
+
// negative lookbehind, not `\b`: a bare configured name like `get` must
|
|
327
|
+
// match the free call `get('/x')` but NOT a member access `client.get(`
|
|
328
|
+
// (a `.get(` on an unrelated object), and `apiFetch` must not match
|
|
329
|
+
// `myApiFetch`. Member-style wrappers are configured with the dot
|
|
330
|
+
// (`client.get`), where the `.` is part of the pattern. The `u` flag +
|
|
331
|
+
// Unicode property classes make the boundary cover non-ASCII identifier
|
|
332
|
+
// characters too — ASCII `\w` would let `caféget('/x')` match `get`
|
|
333
|
+
// (#1852 review F10).
|
|
334
|
+
const alternation = [...wrapperNames].map(escapeRegex).join('|');
|
|
335
|
+
const wrapperCallRegex = new RegExp(`(?<![.\\p{L}\\p{N}_$])(?:${alternation})\\s*\\(\\s*['"\`](/[^'"\`\\s)]+)['"\`]`, 'gu');
|
|
336
|
+
const scanContent = (filePath, content) => {
|
|
337
|
+
wrapperCallRegex.lastIndex = 0;
|
|
338
|
+
// 1-based line number via a running newline counter: matches arrive in
|
|
339
|
+
// ascending index, so accumulate newlines incrementally instead of
|
|
340
|
+
// re-allocating `content.substring(0, match.index).split('\n')` on
|
|
341
|
+
// every match (#1852 review F12). Output is identical.
|
|
342
|
+
let line = 1;
|
|
343
|
+
let scanned = 0;
|
|
344
|
+
let match;
|
|
345
|
+
while ((match = wrapperCallRegex.exec(content)) !== null) {
|
|
346
|
+
for (; scanned < match.index; scanned++) {
|
|
347
|
+
if (content.charCodeAt(scanned) === 10 /* '\n' */)
|
|
348
|
+
line++;
|
|
315
349
|
}
|
|
350
|
+
allFetchCalls.push({
|
|
351
|
+
filePath,
|
|
352
|
+
fetchURL: match[1],
|
|
353
|
+
lineNumber: line,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
for (const [filePath, content] of extraContents)
|
|
358
|
+
scanContent(filePath, content);
|
|
359
|
+
// Also scan already-read JS/TS handler files (a handler can itself
|
|
360
|
+
// consume another route through a wrapper).
|
|
361
|
+
if (handlerContents) {
|
|
362
|
+
for (const p of jsFiles) {
|
|
363
|
+
const cached = handlerContents.get(p);
|
|
364
|
+
if (cached !== undefined)
|
|
365
|
+
scanContent(p, cached);
|
|
316
366
|
}
|
|
317
367
|
}
|
|
318
368
|
}
|
|
@@ -25,6 +25,54 @@ export interface PipelineOptions {
|
|
|
25
25
|
* to retain those nodes under `skipGraphPhases`.
|
|
26
26
|
*/
|
|
27
27
|
skipGraphPhases?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Build the control-flow-graph / PDG substrate (#2081 M1, opt-in via `--pdg`).
|
|
30
|
+
* Off by default: workers skip all CFG work and emit no `cfgSideChannel`, and
|
|
31
|
+
* scope-resolution emits no BasicBlock nodes or CFG edges — so the default
|
|
32
|
+
* graph is byte-identical to a pre-#2081 run. Folded into the parse-cache key
|
|
33
|
+
* so a pdg-off warm cache is not reused on a `--pdg` run.
|
|
34
|
+
*/
|
|
35
|
+
pdg?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Per-function source-line cap for worker-side CFG construction.
|
|
38
|
+
* `undefined` ⇒ the worker applies `DEFAULT_PDG_MAX_FUNCTION_LINES`; `0` ⇒ no
|
|
39
|
+
* cap (unlimited). Bounds the cost of a pathological mega-function; over-cap
|
|
40
|
+
* functions are skipped (no CFG emitted for them). No CLI flag in M1 —
|
|
41
|
+
* programmatic / server analyze-worker path only.
|
|
42
|
+
*/
|
|
43
|
+
pdgMaxFunctionLines?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Per-function CFG edge cap for the scope-resolution emit step.
|
|
46
|
+
* `undefined` ⇒ `DEFAULT_MAX_CFG_EDGES_PER_FUNCTION`; `0` ⇒ no cap (unlimited).
|
|
47
|
+
* Over-cap functions stop at the cap and log a structured drop warning (no
|
|
48
|
+
* silent truncation). No CLI flag in M1 — programmatic / server path only.
|
|
49
|
+
*/
|
|
50
|
+
pdgMaxEdgesPerFunction?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Per-function REACHING_DEF edge cap for the scope-resolution emit step
|
|
53
|
+
* (#2082 M2). `undefined` ⇒ `DEFAULT_PDG_MAX_REACHING_DEF_EDGES_PER_FUNCTION`
|
|
54
|
+
* (4000); `0` ⇒ no cap (unlimited). Emit-time-only — NOT folded into the
|
|
55
|
+
* parse-cache chunk key (the worker never sees it); recorded in
|
|
56
|
+
* `RepoMeta.pdg` so a cap change forces a full writeback. No CLI flag —
|
|
57
|
+
* programmatic / server path only, like the M1 caps.
|
|
58
|
+
*/
|
|
59
|
+
pdgMaxReachingDefEdgesPerFunction?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Per-function taint findings cap for the scope-resolution taint pass
|
|
62
|
+
* (#2083 M3). `undefined` ⇒ `DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION`
|
|
63
|
+
* (200); `0` ⇒ no cap (unlimited). Emit-time-only — NOT folded into the
|
|
64
|
+
* parse-cache chunk key; recorded resolved in `RepoMeta.pdg` so a cap
|
|
65
|
+
* change forces a full writeback. No CLI flag or rc key (KTD8) —
|
|
66
|
+
* programmatic / server path only, like the other pdg caps.
|
|
67
|
+
*/
|
|
68
|
+
pdgMaxTaintFindingsPerFunction?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Per-finding taint hop cap (#2083 M3, KTD6 — bounds the persisted
|
|
71
|
+
* hop-encoded `reason`). `undefined` ⇒ `DEFAULT_PDG_MAX_TAINT_HOPS` (32);
|
|
72
|
+
* `0` ⇒ no cap (unlimited). Same emit-time-only / RepoMeta-stamped /
|
|
73
|
+
* no-CLI-flag discipline as `pdgMaxTaintFindingsPerFunction`.
|
|
74
|
+
*/
|
|
75
|
+
pdgMaxTaintHops?: number;
|
|
28
76
|
/**
|
|
29
77
|
* Request parsing with the worker pool disabled. The sequential parser was
|
|
30
78
|
* removed — the worker pool is the sole parse path — so setting this now
|
|
@@ -104,6 +152,15 @@ export interface PipelineOptions {
|
|
|
104
152
|
* `process.env` state across invocations. When undefined, the env var decides.
|
|
105
153
|
*/
|
|
106
154
|
keepLocalValueSymbols?: boolean;
|
|
155
|
+
/**
|
|
156
|
+
* Extra fetch-wrapper function names to treat as HTTP consumers, threaded
|
|
157
|
+
* from `.gitnexusrc` `fetchWrappers` via `AnalyzeOptions` (#1589/#1852
|
|
158
|
+
* residual). The routes phase unions these with the auto-detected `fetch()`
|
|
159
|
+
* wrappers when scanning for `route_map` consumers, so a wrapper named outside
|
|
160
|
+
* the built-in convention (or built on axios / a custom client) is still
|
|
161
|
+
* traced. Empty/undefined leaves behavior unchanged.
|
|
162
|
+
*/
|
|
163
|
+
fetchWrappers?: readonly string[];
|
|
107
164
|
}
|
|
108
165
|
/**
|
|
109
166
|
* All pipeline phases with their dependency relationships.
|