@backbencher/brain 0.0.0-stage → 0.1.1
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/CHANGELOG.md +298 -0
- package/EMBEDDINGS.md +355 -0
- package/LICENSE +21 -0
- package/README.md +415 -2
- package/bin/bb +13 -0
- package/dist/analysis-exclusions-7ZJDXOVZ.js +35 -0
- package/dist/brain-index-health-Q5APTJQL.js +17 -0
- package/dist/brain-relationship-enrichment-MYR2AM4F.js +558 -0
- package/dist/brain.sql-EIM4WS4D.js +29 -0
- package/dist/chunk-22V37YTK.js +1758 -0
- package/dist/chunk-2BSKD7O3.js +40 -0
- package/dist/chunk-2DE27DVC.js +1314 -0
- package/dist/chunk-2RRBMNBQ.js +322 -0
- package/dist/chunk-2WXYNLBA.js +29 -0
- package/dist/chunk-3CTFIJJB.js +17 -0
- package/dist/chunk-3ZTOHHSW.js +2104 -0
- package/dist/chunk-4H22TLOT.js +543 -0
- package/dist/chunk-5BVAH26D.js +340 -0
- package/dist/chunk-62DHLYW6.js +3427 -0
- package/dist/chunk-7AN7U5IZ.js +371 -0
- package/dist/chunk-7DRPNVIN.js +782 -0
- package/dist/chunk-7MBYT777.js +174 -0
- package/dist/chunk-AHDWGM7Q.js +236 -0
- package/dist/chunk-B5GEAAYF.js +818 -0
- package/dist/chunk-BEIZZ73B.js +1479 -0
- package/dist/chunk-BQ3OVQ3P.js +125 -0
- package/dist/chunk-D2Q4Y47A.js +53 -0
- package/dist/chunk-DIYAGQJL.js +34 -0
- package/dist/chunk-DWKXZ6IF.js +336 -0
- package/dist/chunk-DYM4FQEE.js +90 -0
- package/dist/chunk-ENW4BTBA.js +930 -0
- package/dist/chunk-EWMWK7WN.js +75 -0
- package/dist/chunk-EY5ZZUUA.js +626 -0
- package/dist/chunk-GBI7V7KY.js +69 -0
- package/dist/chunk-GEFFO6O2.js +152 -0
- package/dist/chunk-HJEWO5EV.js +247 -0
- package/dist/chunk-HQSPJDHI.js +613 -0
- package/dist/chunk-KAET47ZL.js +125 -0
- package/dist/chunk-KCDECRJY.js +440 -0
- package/dist/chunk-L5TDYKYK.js +76 -0
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/chunk-NO3U3FJQ.js +201 -0
- package/dist/chunk-OWISBAOF.js +61 -0
- package/dist/chunk-QKTRECYS.js +1119 -0
- package/dist/chunk-QLK6ED4Q.js +235 -0
- package/dist/chunk-R2GW4F6R.js +19 -0
- package/dist/chunk-RCMTFSEF.js +87 -0
- package/dist/chunk-RM3PY6TG.js +376 -0
- package/dist/chunk-ROMM6KMC.js +433 -0
- package/dist/chunk-SGGCSHAX.js +12050 -0
- package/dist/chunk-SK6YVHFZ.js +211 -0
- package/dist/chunk-SM7RFQRO.js +214 -0
- package/dist/chunk-UGR4QIGS.js +67 -0
- package/dist/chunk-UQNQZXHY.js +711 -0
- package/dist/chunk-UUNHHX4M.js +13 -0
- package/dist/chunk-VL52PL2T.js +71 -0
- package/dist/chunk-WIG36E67.js +196 -0
- package/dist/chunk-XHK3WWGB.js +7436 -0
- package/dist/chunk-XTQM2IP3.js +2863 -0
- package/dist/chunk-ZE2LG76D.js +1296 -0
- package/dist/chunk-ZETTGPAW.js +6950 -0
- package/dist/cli/index.js +37 -0
- package/dist/config-HZAAYDP3.js +10 -0
- package/dist/content-search-7XIP555Q.js +593 -0
- package/dist/database-76RP44JG.js +9 -0
- package/dist/doctor-ANGETYMN.js +395 -0
- package/dist/edit-engine-CG72LDZD.js +51 -0
- package/dist/engine-BKEOGN7N.js +11 -0
- package/dist/engine-VIW6NSKO.js +18 -0
- package/dist/fingerprint-OBLIMZLP.js +33 -0
- package/dist/framework-intelligence-3LORTPOX.js +860 -0
- package/dist/freshness-3K6VU5OT.js +174 -0
- package/dist/graph-engine-HBSQNPTB.js +21 -0
- package/dist/graph_request-Q6NKB6N2.js +350 -0
- package/dist/impact_request-LYP672WE.js +68 -0
- package/dist/index-space-IUUN5WYV.js +15 -0
- package/dist/index-status-7OVGYSGW.js +34 -0
- package/dist/index.js +159 -0
- package/dist/instance-FO6QZRLH.js +19 -0
- package/dist/language-detection-DFCAU5DZ.js +11 -0
- package/dist/lsp/server.js +4301 -0
- package/dist/mcp/server.js +132 -0
- package/dist/onboard-DIQZV2NW.js +161 -0
- package/dist/override-companion-pass-XR7MHTP7.js +117 -0
- package/dist/parallel-indexer-FK2XKZXY.js +88 -0
- package/dist/pool-worker.js +1153 -0
- package/dist/project-health-6XPENVAA.js +94 -0
- package/dist/project-index-5SDPHITE.js +57 -0
- package/dist/project-registry-ZJ3DVUGO.js +355 -0
- package/dist/real-bash-analyzer-EJAU5LW5.js +2201 -0
- package/dist/real-c-analyzer-HBD3FNNH.js +5942 -0
- package/dist/real-clean-analyzer-4EEZLPV5.js +3470 -0
- package/dist/real-clojure-analyzer-Q55EBOO2.js +2818 -0
- package/dist/real-cpp-analyzer-IVVOD25R.js +4101 -0
- package/dist/real-csharp-analyzer-ZBNLNJZJ.js +3298 -0
- package/dist/real-css-analyzer-6XRQLUN7.js +15 -0
- package/dist/real-dart-analyzer-OLR72EFW.js +3944 -0
- package/dist/real-elixir-analyzer-MQWGAH2I.js +2192 -0
- package/dist/real-erlang-analyzer-7BVPQEHO.js +1731 -0
- package/dist/real-fsharp-analyzer-C2UPFNOA.js +2390 -0
- package/dist/real-go-analyzer-UKGI43YS.js +4126 -0
- package/dist/real-graphql-analyzer-VE2EEFII.js +1442 -0
- package/dist/real-groovy-analyzer-W26VACFW.js +2285 -0
- package/dist/real-haskell-analyzer-5CVVAJRX.js +2533 -0
- package/dist/real-hcl-analyzer-5ZT4U43N.js +725 -0
- package/dist/real-html-analyzer-JWNX3C6I.js +1759 -0
- package/dist/real-java-analyzer-GU42VBGQ.js +4677 -0
- package/dist/real-javascript-analyzer-QA4QOJ6W.js +14 -0
- package/dist/real-json-analyzer-MPA6PRXL.js +1640 -0
- package/dist/real-julia-analyzer-22CWYQMN.js +2085 -0
- package/dist/real-kotlin-analyzer-QDZJLXXU.js +3956 -0
- package/dist/real-lua-analyzer-G7NHLYKS.js +1957 -0
- package/dist/real-makefile-analyzer-OCY3GT5N.js +920 -0
- package/dist/real-markdown-analyzer-TEJK2JXJ.js +1215 -0
- package/dist/real-matlab-analyzer-Q5SWLN7Z.js +480 -0
- package/dist/real-nim-analyzer-YLXSK563.js +3603 -0
- package/dist/real-objective-c-analyzer-D23ACC2R.js +1518 -0
- package/dist/real-perl-analyzer-WWTRHYDT.js +1865 -0
- package/dist/real-php-analyzer-JNKJHTCL.js +9368 -0
- package/dist/real-powershell-analyzer-XRSNQERV.js +2915 -0
- package/dist/real-protobuf-analyzer-3OKUCZ7T.js +867 -0
- package/dist/real-python-analyzer-VXAFWI72.js +4880 -0
- package/dist/real-r-analyzer-ZGAIDVI4.js +2596 -0
- package/dist/real-ruby-analyzer-X2KTLVBH.js +2429 -0
- package/dist/real-rust-analyzer-OFFHPL2A.js +3359 -0
- package/dist/real-scala-analyzer-TSTW27J6.js +3293 -0
- package/dist/real-scss-analyzer-AVWYPSOQ.js +1515 -0
- package/dist/real-solidity-analyzer-UCI2KWUB.js +2608 -0
- package/dist/real-sql-analyzer-F77ZMQXR.js +3840 -0
- package/dist/real-svelte-analyzer-SF7NRUO5.js +2532 -0
- package/dist/real-swift-analyzer-MN5QT3QN.js +2311 -0
- package/dist/real-toml-analyzer-66L7BDCQ.js +929 -0
- package/dist/real-typescript-analyzer-6KEMVDWQ.js +14 -0
- package/dist/real-vb-analyzer-VICVPOP7.js +3145 -0
- package/dist/real-vba-analyzer-HXLTTHKM.js +466 -0
- package/dist/real-vue-analyzer-QXR56CFV.js +2680 -0
- package/dist/real-xml-analyzer-YL465ZJW.js +2405 -0
- package/dist/real-yaml-analyzer-SUBCBNSI.js +3528 -0
- package/dist/real-zig-analyzer-HIQLZMGY.js +2430 -0
- package/dist/regex-search-NJKHMZNO.js +239 -0
- package/dist/rules-ACHPB7QU.js +152 -0
- package/dist/scoped-path-MJYWJZQX.js +11 -0
- package/dist/setup-show-NT5ZHYNE.js +15 -0
- package/dist/setup-wizard-G5YYR5T6.js +24 -0
- package/dist/symbol-search-GZJIM2J2.js +16 -0
- package/dist/taint-KXUHHPIE.js +202 -0
- package/dist/taint-analyzer-N7YLZU3N.js +163 -0
- package/dist/tool-handlers-OJDC35DI.js +72 -0
- package/dist/tool-registry-BPEJNSZG.js +17 -0
- package/dist/tool-validation-Q57YMMBX.js +32 -0
- package/dist/type-inference-QMT2RMLV.js +13 -0
- package/dist/vector-binary-LMY4QGAN.js +19 -0
- package/dist/version-ABP2TUL2.js +9 -0
- package/dist/wasm-NMWO3WXY.js +16 -0
- package/docs/EMBEDDINGS.md +132 -0
- package/docs/README.md +178 -0
- package/docs/data/m10-baseline.json +602 -0
- package/docs/data/m10-benchmark-baseline.json +57 -0
- package/docs/data/m10-benchmark-last-run.json +127 -0
- package/docs/data/m10-final-audit.json +215 -0
- package/docs/data/m12-final-audit.json +138 -0
- package/docs/data/m12-surface-matrix.json +50 -0
- package/docs/data/public-tools.json +1902 -0
- package/docs/indexing/DEAD-ASSETS.md +88 -0
- package/docs/indexing/INDEXER-REVIEW.md +634 -0
- package/docs/indexing/PERFORMANCE-FINDINGS.md +106 -0
- package/docs/indexing/README.md +427 -0
- package/docs/indexing/discovery-matrix.md +41 -0
- package/docs/indexing/embeddings.md +325 -0
- package/docs/indexing/environment-variables.md +77 -0
- package/docs/indexing/performance.md +323 -0
- package/docs/indexing/resume.md +345 -0
- package/docs/indexing/troubleshooting.md +391 -0
- package/docs/man/bb.1 +190 -0
- package/docs/tools/bb_analyze.md +147 -0
- package/docs/tools/bb_annotate.md +110 -0
- package/docs/tools/bb_annotations.md +106 -0
- package/docs/tools/bb_ask.md +101 -0
- package/docs/tools/bb_cross_language.md +103 -0
- package/docs/tools/bb_doc.md +169 -0
- package/docs/tools/bb_edit.md +185 -0
- package/docs/tools/bb_graph.md +169 -0
- package/docs/tools/bb_health.md +156 -0
- package/docs/tools/bb_impact.md +117 -0
- package/docs/tools/bb_index.md +108 -0
- package/docs/tools/bb_migrate.md +135 -0
- package/docs/tools/bb_patterns.md +140 -0
- package/docs/tools/bb_search.md +150 -0
- package/docs/tools/bb_security.md +100 -0
- package/docs/tools/bb_visualize.md +184 -0
- package/grammars/README.md +57 -0
- package/grammars/THIRD-PARTY-NOTICES.md +50 -0
- package/grammars/tree-sitter-c/LICENSE +21 -0
- package/grammars/tree-sitter-clojure/LICENSE.md +21 -0
- package/grammars/tree-sitter-cpp/LICENSE +21 -0
- package/grammars/tree-sitter-csharp/LICENSE +21 -0
- package/grammars/tree-sitter-css/LICENSE +21 -0
- package/grammars/tree-sitter-css/README.md +21 -0
- package/grammars/tree-sitter-dart/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/LICENSE +20 -0
- package/grammars/tree-sitter-dart-upstream/README.md +18 -0
- package/grammars/tree-sitter-elixir/LICENSE +176 -0
- package/grammars/tree-sitter-elixir/README.md +11 -0
- package/grammars/tree-sitter-fsharp/LICENSE +21 -0
- package/grammars/tree-sitter-fsharp/README.md +45 -0
- package/grammars/tree-sitter-graphql/LICENSE +21 -0
- package/grammars/tree-sitter-graphql/README.md +106 -0
- package/grammars/tree-sitter-groovy/LICENSE +21 -0
- package/grammars/tree-sitter-groovy/README.md +4 -0
- package/grammars/tree-sitter-haskell/LICENSE +21 -0
- package/grammars/tree-sitter-haskell/README.md +394 -0
- package/grammars/tree-sitter-hcl/CHANGELOG.md +102 -0
- package/grammars/tree-sitter-hcl/LICENSE +201 -0
- package/grammars/tree-sitter-hcl/README.md +39 -0
- package/grammars/tree-sitter-html/LICENSE +21 -0
- package/grammars/tree-sitter-html/README.md +21 -0
- package/grammars/tree-sitter-julia/LICENSE +21 -0
- package/grammars/tree-sitter-julia/README.md +24 -0
- package/grammars/tree-sitter-kotlin/LICENSE +9 -0
- package/grammars/tree-sitter-lua/LICENSE.md +21 -0
- package/grammars/tree-sitter-lua/README.md +29 -0
- package/grammars/tree-sitter-make/LICENSE +21 -0
- package/grammars/tree-sitter-matlab/LICENSE +19 -0
- package/grammars/tree-sitter-matlab/README.md +99 -0
- package/grammars/tree-sitter-nim/LICENSE +373 -0
- package/grammars/tree-sitter-nim/README.md +46 -0
- package/grammars/tree-sitter-objc/LICENSE +21 -0
- package/grammars/tree-sitter-objc/README.md +20 -0
- package/grammars/tree-sitter-perl/LICENSE +7 -0
- package/grammars/tree-sitter-perl/README.md +100 -0
- package/grammars/tree-sitter-powershell/LICENSE +21 -0
- package/grammars/tree-sitter-powershell/README.md +7 -0
- package/grammars/tree-sitter-proto/LICENSE +21 -0
- package/grammars/tree-sitter-proto/README.md +105 -0
- package/grammars/tree-sitter-r/LICENSE +9 -0
- package/grammars/tree-sitter-r/README.md +66 -0
- package/grammars/tree-sitter-ruby/LICENSE +22 -0
- package/grammars/tree-sitter-scss/LICENSE +21 -0
- package/grammars/tree-sitter-scss/README.md +17 -0
- package/grammars/tree-sitter-solidity/LICENSE +7 -0
- package/grammars/tree-sitter-sql/LICENSE +21 -0
- package/grammars/tree-sitter-typescript/LICENSE +21 -0
- package/grammars/tree-sitter-vba/LICENSE +21 -0
- package/grammars/tree-sitter-vba/README.md +738 -0
- package/grammars/tree-sitter-vbnet/LICENSE +21 -0
- package/grammars/tree-sitter-vbnet/README.md +322 -0
- package/grammars/tree-sitter-xml/LICENSE +19 -0
- package/grammars/tree-sitter-yaml/LICENSE +20 -0
- package/grammars/tree-sitter-yaml/README.md +21 -0
- package/package.json +184 -4
- package/wasm/dart.wasm +0 -0
- package/wasm/tree-sitter-bash.wasm +0 -0
- package/wasm/tree-sitter-c.wasm +0 -0
- package/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/wasm/tree-sitter-clean.wasm +0 -0
- package/wasm/tree-sitter-clojure.wasm +0 -0
- package/wasm/tree-sitter-core_schema.wasm +0 -0
- package/wasm/tree-sitter-cpp.wasm +0 -0
- package/wasm/tree-sitter-css.wasm +0 -0
- package/wasm/tree-sitter-dart.wasm +0 -0
- package/wasm/tree-sitter-elisp.wasm +0 -0
- package/wasm/tree-sitter-elixir.wasm +0 -0
- package/wasm/tree-sitter-elm.wasm +0 -0
- package/wasm/tree-sitter-embedded_template.wasm +0 -0
- package/wasm/tree-sitter-erlang.wasm +0 -0
- package/wasm/tree-sitter-fsharp.wasm +0 -0
- package/wasm/tree-sitter-fsharp_signature.wasm +0 -0
- package/wasm/tree-sitter-go.wasm +0 -0
- package/wasm/tree-sitter-graphql.wasm +0 -0
- package/wasm/tree-sitter-groovy.wasm +0 -0
- package/wasm/tree-sitter-haskell.wasm +0 -0
- package/wasm/tree-sitter-hcl.wasm +0 -0
- package/wasm/tree-sitter-html.wasm +0 -0
- package/wasm/tree-sitter-java.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-json.wasm +0 -0
- package/wasm/tree-sitter-json_schema.wasm +0 -0
- package/wasm/tree-sitter-julia.wasm +0 -0
- package/wasm/tree-sitter-kotlin.wasm +0 -0
- package/wasm/tree-sitter-lua.wasm +0 -0
- package/wasm/tree-sitter-make.wasm +0 -0
- package/wasm/tree-sitter-markdown.wasm +0 -0
- package/wasm/tree-sitter-markdown_inline.wasm +0 -0
- package/wasm/tree-sitter-matlab.wasm +0 -0
- package/wasm/tree-sitter-nim.wasm +0 -0
- package/wasm/tree-sitter-objc.wasm +0 -0
- package/wasm/tree-sitter-ocaml.wasm +0 -0
- package/wasm/tree-sitter-perl.wasm +0 -0
- package/wasm/tree-sitter-php.wasm +0 -0
- package/wasm/tree-sitter-php_only.wasm +0 -0
- package/wasm/tree-sitter-powershell.wasm +0 -0
- package/wasm/tree-sitter-protobuf.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-ql.wasm +0 -0
- package/wasm/tree-sitter-r.wasm +0 -0
- package/wasm/tree-sitter-rescript.wasm +0 -0
- package/wasm/tree-sitter-ruby.wasm +0 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
- package/wasm/tree-sitter-scala.wasm +0 -0
- package/wasm/tree-sitter-scss.wasm +0 -0
- package/wasm/tree-sitter-solidity.wasm +0 -0
- package/wasm/tree-sitter-sql.wasm +0 -0
- package/wasm/tree-sitter-svelte.wasm +0 -0
- package/wasm/tree-sitter-swift.wasm +0 -0
- package/wasm/tree-sitter-systemrdl.wasm +0 -0
- package/wasm/tree-sitter-terraform.wasm +0 -0
- package/wasm/tree-sitter-tlaplus.wasm +0 -0
- package/wasm/tree-sitter-toml.wasm +0 -0
- package/wasm/tree-sitter-tsx.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
- package/wasm/tree-sitter-vba.wasm +0 -0
- package/wasm/tree-sitter-vbnet.wasm +0 -0
- package/wasm/tree-sitter-vue.wasm +0 -0
- package/wasm/tree-sitter-xml.wasm +0 -0
- package/wasm/tree-sitter-yaml.wasm +0 -0
- package/wasm/tree-sitter-zig.wasm +0 -0
- package/wasm/tree-sitter.wasm +0 -0
- package/wasm/tsx.wasm +0 -0
- package/wasm/typescript.wasm +0 -0
|
@@ -0,0 +1,1153 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import {
|
|
3
|
+
BINDING_SEP,
|
|
4
|
+
decodeSourceText
|
|
5
|
+
} from "./chunk-KAET47ZL.js";
|
|
6
|
+
import {
|
|
7
|
+
detectLanguageFromPath
|
|
8
|
+
} from "./chunk-KCDECRJY.js";
|
|
9
|
+
import "./chunk-MLKGABMK.js";
|
|
10
|
+
|
|
11
|
+
// src/ast/pool-worker.ts
|
|
12
|
+
import { createHash } from "crypto";
|
|
13
|
+
import { createRequire } from "module";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
var require2 = createRequire(import.meta.url);
|
|
17
|
+
if (!process.env.BB_LOG_LEVEL) {
|
|
18
|
+
process.env.BB_LOG_LEVEL = "error";
|
|
19
|
+
}
|
|
20
|
+
function bbDiagnosticsLogPath(name) {
|
|
21
|
+
const dataDir = process.env.BB_DATA_DIR || path.join(process.env.HOME || process.env.USERPROFILE || "/tmp", ".bb");
|
|
22
|
+
const logsDir = path.join(dataDir, "logs");
|
|
23
|
+
try {
|
|
24
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
return path.join(logsDir, name);
|
|
28
|
+
}
|
|
29
|
+
function log(..._args) {
|
|
30
|
+
}
|
|
31
|
+
var startupDiagnostics = [];
|
|
32
|
+
var reportedStartupProblems = /* @__PURE__ */ new Set();
|
|
33
|
+
function reportStartupProblem(what, error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
const line = `${what}: ${message}`;
|
|
36
|
+
if (reportedStartupProblems.has(line)) return;
|
|
37
|
+
reportedStartupProblems.add(line);
|
|
38
|
+
process.stderr.write(`[BB-WORKER-STARTUP] ${line}
|
|
39
|
+
`);
|
|
40
|
+
startupDiagnostics.push(line.slice(0, 300));
|
|
41
|
+
}
|
|
42
|
+
function safeSend(message) {
|
|
43
|
+
try {
|
|
44
|
+
if (typeof process.send !== "function") return false;
|
|
45
|
+
if (process.connected === false) return false;
|
|
46
|
+
process.send(message);
|
|
47
|
+
return true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function extractBasicSymbols(content, language) {
|
|
53
|
+
const symbols = [];
|
|
54
|
+
const lines = content.split("\n");
|
|
55
|
+
const patterns = {
|
|
56
|
+
typescript: [
|
|
57
|
+
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)/,
|
|
58
|
+
/^(?:export\s+)?class\s+(\w+)/,
|
|
59
|
+
/^(?:export\s+)?interface\s+(\w+)/,
|
|
60
|
+
/^(?:export\s+)?type\s+(\w+)/,
|
|
61
|
+
/^(?:export\s+)?(?:const|let|var)\s+(\w+)/,
|
|
62
|
+
/^\s*(?:public|private|protected)?\s*(?:async\s+)?(\w+)\s*\(/
|
|
63
|
+
],
|
|
64
|
+
javascript: [
|
|
65
|
+
/^(?:export\s+)?(?:async\s+)?function\s+(\w+)/,
|
|
66
|
+
/^(?:export\s+)?class\s+(\w+)/,
|
|
67
|
+
/^(?:export\s+)?(?:const|let|var)\s+(\w+)/
|
|
68
|
+
],
|
|
69
|
+
python: [/^(?:async\s+)?def\s+(\w+)/, /^class\s+(\w+)/],
|
|
70
|
+
svelte: [
|
|
71
|
+
/^\s*export\s+let\s+(\w+)/,
|
|
72
|
+
/^\s*\$:.*?\s*=\s*(.+)/,
|
|
73
|
+
/^\s*const\s+(\w+)\s*=\s*\$state/,
|
|
74
|
+
/^\s*const\s+(\w+)\s*=\s*\$derived/,
|
|
75
|
+
/^\s*\$effect\s*\(/,
|
|
76
|
+
/^\s*\$props\s*\(/,
|
|
77
|
+
/^\s*function\s+(\w+)/,
|
|
78
|
+
/^\s*class\s+(\w+)/
|
|
79
|
+
],
|
|
80
|
+
go: [/^func\s+(?:\([^)]+\)\s+)?(\w+)/, /^type\s+(\w+)\s+struct/, /^type\s+(\w+)\s+interface/],
|
|
81
|
+
rust: [
|
|
82
|
+
/^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/,
|
|
83
|
+
/^(?:pub\s+)?struct\s+(\w+)/,
|
|
84
|
+
/^(?:pub\s+)?trait\s+(\w+)/,
|
|
85
|
+
/^(?:pub\s+)?impl(?:\s+\w+)?\s+(?:for\s+)?(\w+)/
|
|
86
|
+
],
|
|
87
|
+
java: [
|
|
88
|
+
/^(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?class\s+(\w+)/,
|
|
89
|
+
/^(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?interface\s+(\w+)/,
|
|
90
|
+
/^(?:public|private|protected)?\s*(?:static\s+)?(?:\w+\s+)+(\w+)\s*\(/
|
|
91
|
+
],
|
|
92
|
+
kotlin: [
|
|
93
|
+
/^(?:fun|suspend\s+fun)\s+(\w+)/,
|
|
94
|
+
/^(?:class|data\s+class|sealed\s+class|object)\s+(\w+)/,
|
|
95
|
+
/^interface\s+(\w+)/
|
|
96
|
+
],
|
|
97
|
+
swift: [/^(?:func|class\s+func|static\s+func)\s+(\w+)/, /^(?:class|struct|protocol|enum)\s+(\w+)/],
|
|
98
|
+
ruby: [/^def\s+(\w+)/, /^class\s+(\w+)/, /^module\s+(\w+)/],
|
|
99
|
+
php: [
|
|
100
|
+
/^(?:public|private|protected)?\s*function\s+(\w+)/,
|
|
101
|
+
/^class\s+(\w+)/,
|
|
102
|
+
/^interface\s+(\w+)/,
|
|
103
|
+
/^trait\s+(\w+)/
|
|
104
|
+
],
|
|
105
|
+
csharp: [
|
|
106
|
+
/^(?:public|private|protected|internal)?\s*(?:static\s+)?(?:async\s+)?(?:\w+\s+)+(\w+)\s*\(/,
|
|
107
|
+
/^(?:public|private|protected|internal)?\s*(?:partial\s+)?class\s+(\w+)/,
|
|
108
|
+
/^(?:public|private|protected|internal)?\s*interface\s+(\w+)/
|
|
109
|
+
]
|
|
110
|
+
};
|
|
111
|
+
const langPatterns = patterns[language] || patterns.javascript || [];
|
|
112
|
+
for (let i = 0; i < lines.length; i++) {
|
|
113
|
+
const line = lines[i].trim();
|
|
114
|
+
for (const pattern of langPatterns) {
|
|
115
|
+
const match = line.match(pattern);
|
|
116
|
+
if (match && match[1]) {
|
|
117
|
+
const name = match[1];
|
|
118
|
+
if (["if", "for", "while", "switch", "catch", "return", "new", "this", "super"].includes(name)) continue;
|
|
119
|
+
let type = "function";
|
|
120
|
+
if (/class\s/.test(line)) type = "class";
|
|
121
|
+
else if (/interface\s/.test(line)) type = "interface";
|
|
122
|
+
else if (/struct\s/.test(line)) type = "class";
|
|
123
|
+
else if (/trait\s/.test(line) || /protocol\s/.test(line)) type = "interface";
|
|
124
|
+
else if (/type\s/.test(line)) type = "type";
|
|
125
|
+
else if (/const\s|let\s|var\s/.test(line)) type = "variable";
|
|
126
|
+
else if (/module\s/.test(line) || /namespace\s/.test(line)) type = "module";
|
|
127
|
+
else if (language === "svelte") {
|
|
128
|
+
if (/export\s+let/.test(line)) type = "prop";
|
|
129
|
+
else if (/^\$:\s/.test(line)) type = "reactive";
|
|
130
|
+
else if (/\$state/.test(line)) type = "rune";
|
|
131
|
+
else if (/\$derived/.test(line)) type = "rune";
|
|
132
|
+
else if (/\$effect\(/.test(line)) type = "rune";
|
|
133
|
+
else if (/\$props\(/.test(line)) type = "rune";
|
|
134
|
+
}
|
|
135
|
+
let byteOffset = 0;
|
|
136
|
+
for (let j = 0; j < i; j++) byteOffset += lines[j].length + 1;
|
|
137
|
+
const lineLen = lines[i].length;
|
|
138
|
+
symbols.push({
|
|
139
|
+
name,
|
|
140
|
+
type,
|
|
141
|
+
startLine: i + 1,
|
|
142
|
+
endLine: i + 1
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return symbols;
|
|
149
|
+
}
|
|
150
|
+
function extractBasicImports(content, language) {
|
|
151
|
+
const imports = [];
|
|
152
|
+
const lines = content.split("\n");
|
|
153
|
+
const patterns = {
|
|
154
|
+
typescript: [
|
|
155
|
+
/import\s+(?:{([^}]+)}|(\w+))\s+from\s+['"]([^'"]+)['"]/,
|
|
156
|
+
/import\s+\*\s+as\s+(\w+)\s+from\s+['"]([^'"]+)['"]/
|
|
157
|
+
],
|
|
158
|
+
javascript: [/import\s+(?:{([^}]+)}|(\w+))\s+from\s+['"]([^'"]+)['"]/, /require\s*\(\s*['"]([^'"]+)['"]\s*\)/],
|
|
159
|
+
python: [/^from\s+([\w.]+)\s+import\s+(.+)$/, /^import\s+([\w.]+)/],
|
|
160
|
+
go: [/import\s+(?:"([^"]+)"|(\w+)\s+"([^"]+)")/],
|
|
161
|
+
rust: [/use\s+([\w:]+)(?:::\{([^}]+)\})?/],
|
|
162
|
+
java: [/import\s+(?:static\s+)?([\w.]+)/]
|
|
163
|
+
};
|
|
164
|
+
const GROUP_ROLES = {
|
|
165
|
+
typescript: { module: 3, items: 1 },
|
|
166
|
+
javascript: { module: 3, items: 1 },
|
|
167
|
+
python: { module: 1, items: 2 },
|
|
168
|
+
go: { module: 3, items: 1 },
|
|
169
|
+
rust: { module: 1, items: 2 },
|
|
170
|
+
java: { module: 1, items: 1 }
|
|
171
|
+
};
|
|
172
|
+
const langPatterns = patterns[language] || patterns.javascript || [];
|
|
173
|
+
for (let i = 0; i < lines.length; i++) {
|
|
174
|
+
const line = lines[i].trim();
|
|
175
|
+
for (const pattern of langPatterns) {
|
|
176
|
+
const match = line.match(pattern);
|
|
177
|
+
if (match) {
|
|
178
|
+
const roles = GROUP_ROLES[language] ?? GROUP_ROLES.javascript;
|
|
179
|
+
const path2 = String(match[roles.module] ?? "");
|
|
180
|
+
const names = String(match[roles.items] ?? "");
|
|
181
|
+
if (!path2) continue;
|
|
182
|
+
const isExternal = !path2.startsWith(".") && !path2.startsWith("/");
|
|
183
|
+
const items = names.split(",").map((s) => s.trim()).filter(Boolean);
|
|
184
|
+
if (items.length === 0) items.push(path2.split("/").pop() || path2);
|
|
185
|
+
for (const name of items) {
|
|
186
|
+
const asMatch = name.match(/^(\S+)\s+as\s+(\S+)$/);
|
|
187
|
+
imports.push({
|
|
188
|
+
name: asMatch ? asMatch[1] : name,
|
|
189
|
+
alias: asMatch ? asMatch[2] : void 0,
|
|
190
|
+
path: path2,
|
|
191
|
+
type: "named",
|
|
192
|
+
isExternal,
|
|
193
|
+
line: i + 1
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return imports;
|
|
201
|
+
}
|
|
202
|
+
function extractBasicRelationships(content, _language, symbols, imports = []) {
|
|
203
|
+
const rels = [];
|
|
204
|
+
const knownNames = new Set(symbols.map((s) => s.name));
|
|
205
|
+
for (const imp of imports) {
|
|
206
|
+
knownNames.add(imp.name);
|
|
207
|
+
}
|
|
208
|
+
const knownFunctions = new Set(
|
|
209
|
+
symbols.filter((s) => s.type === "function" || s.type === "method").map((s) => s.name)
|
|
210
|
+
);
|
|
211
|
+
const lines = content.split("\n");
|
|
212
|
+
const callPattern = /(\w+)\s*\(/g;
|
|
213
|
+
const methodCallPattern = /(\w+)\.(\w+)\s*\(/g;
|
|
214
|
+
const newPattern = /new\s+(\w+)\s*[\(<]/g;
|
|
215
|
+
for (let i = 0; i < lines.length; i++) {
|
|
216
|
+
const line = lines[i];
|
|
217
|
+
let nmatch;
|
|
218
|
+
while ((nmatch = newPattern.exec(line)) !== null) {
|
|
219
|
+
const className = nmatch[1];
|
|
220
|
+
if (className.length < 2) continue;
|
|
221
|
+
if (className === className.toUpperCase()) continue;
|
|
222
|
+
if (knownNames.has(className)) {
|
|
223
|
+
rels.push({
|
|
224
|
+
source: "this",
|
|
225
|
+
target: className,
|
|
226
|
+
type: "instantiates",
|
|
227
|
+
confidence: 0.6,
|
|
228
|
+
metadata: { line: i + 1, method: "regex", isNew: true }
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
newPattern.lastIndex = 0;
|
|
233
|
+
let match;
|
|
234
|
+
while ((match = methodCallPattern.exec(line)) !== null) {
|
|
235
|
+
const target = match[2];
|
|
236
|
+
if (knownFunctions.has(target) || knownNames.has(target)) {
|
|
237
|
+
rels.push({
|
|
238
|
+
source: match[1],
|
|
239
|
+
// object name (approximate)
|
|
240
|
+
target,
|
|
241
|
+
type: "calls",
|
|
242
|
+
confidence: 0.4,
|
|
243
|
+
// Lower confidence: regex-based, may have false positives
|
|
244
|
+
metadata: { line: i + 1, method: "regex" }
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
methodCallPattern.lastIndex = 0;
|
|
249
|
+
while ((match = callPattern.exec(line)) !== null) {
|
|
250
|
+
const target = match[1];
|
|
251
|
+
if ([
|
|
252
|
+
"if",
|
|
253
|
+
"for",
|
|
254
|
+
"while",
|
|
255
|
+
"switch",
|
|
256
|
+
"catch",
|
|
257
|
+
"return",
|
|
258
|
+
"new",
|
|
259
|
+
"this",
|
|
260
|
+
"super",
|
|
261
|
+
"function",
|
|
262
|
+
"class",
|
|
263
|
+
"import",
|
|
264
|
+
"export",
|
|
265
|
+
"const",
|
|
266
|
+
"let",
|
|
267
|
+
"var",
|
|
268
|
+
"typeof",
|
|
269
|
+
"instanceof",
|
|
270
|
+
"throw",
|
|
271
|
+
"else",
|
|
272
|
+
"case",
|
|
273
|
+
"default",
|
|
274
|
+
"break",
|
|
275
|
+
"continue",
|
|
276
|
+
"delete",
|
|
277
|
+
"void"
|
|
278
|
+
].includes(target)) continue;
|
|
279
|
+
if (target.length < 2) continue;
|
|
280
|
+
if (target === target.toUpperCase() && target.length > 3) continue;
|
|
281
|
+
if (target.startsWith("_") && target.length < 3) continue;
|
|
282
|
+
if (knownFunctions.has(target) || knownNames.has(target)) {
|
|
283
|
+
rels.push({
|
|
284
|
+
source: "this",
|
|
285
|
+
target,
|
|
286
|
+
type: "calls",
|
|
287
|
+
confidence: 0.5,
|
|
288
|
+
metadata: { line: i + 1, method: "regex" }
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
callPattern.lastIndex = 0;
|
|
293
|
+
}
|
|
294
|
+
const seen = /* @__PURE__ */ new Set();
|
|
295
|
+
return rels.filter((r) => {
|
|
296
|
+
const key = `${r.source}:${r.target}:${r.type}`;
|
|
297
|
+
if (seen.has(key)) return false;
|
|
298
|
+
seen.add(key);
|
|
299
|
+
return true;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function extractFallback(content, language, hash, sizeBytes, lastModified) {
|
|
303
|
+
const symbols = extractBasicSymbols(content, language);
|
|
304
|
+
const imports = extractBasicImports(content, language);
|
|
305
|
+
const relationships = filterNoiseRelationships(
|
|
306
|
+
extractBasicRelationships(content, language, symbols, imports),
|
|
307
|
+
language,
|
|
308
|
+
new Set(symbols.map((s) => String(s?.name ?? "")).filter(Boolean))
|
|
309
|
+
);
|
|
310
|
+
return {
|
|
311
|
+
success: true,
|
|
312
|
+
language,
|
|
313
|
+
framework: null,
|
|
314
|
+
fileHash: hash,
|
|
315
|
+
sizeBytes,
|
|
316
|
+
lastModified,
|
|
317
|
+
symbols,
|
|
318
|
+
imports,
|
|
319
|
+
relationships,
|
|
320
|
+
errors: [],
|
|
321
|
+
fallback: true
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
var NOISE_TARGETS = /* @__PURE__ */ new Set([
|
|
325
|
+
// Tree-sitter AST internals
|
|
326
|
+
"namedChild",
|
|
327
|
+
"childForFieldName",
|
|
328
|
+
"namedChildren",
|
|
329
|
+
"childCount",
|
|
330
|
+
"namedChildCount",
|
|
331
|
+
"type",
|
|
332
|
+
"text",
|
|
333
|
+
"startIndex",
|
|
334
|
+
"endIndex",
|
|
335
|
+
"startPosition",
|
|
336
|
+
"endPosition",
|
|
337
|
+
"nextSibling",
|
|
338
|
+
"previousSibling",
|
|
339
|
+
"firstChild",
|
|
340
|
+
"lastChild",
|
|
341
|
+
"parent",
|
|
342
|
+
// CSS properties that leak into relationships (hyphenated names)
|
|
343
|
+
"font-size",
|
|
344
|
+
"background-color",
|
|
345
|
+
"align-items",
|
|
346
|
+
"justify-content",
|
|
347
|
+
"flex-direction",
|
|
348
|
+
"border-radius",
|
|
349
|
+
"font-weight",
|
|
350
|
+
"line-height",
|
|
351
|
+
"margin-bottom",
|
|
352
|
+
"min-width",
|
|
353
|
+
// Test-framework boilerplate (NOT valid production targets)
|
|
354
|
+
"setUp",
|
|
355
|
+
"tearDown",
|
|
356
|
+
"setUpBeforeClass",
|
|
357
|
+
"tearDownAfterClass",
|
|
358
|
+
"beforeEach",
|
|
359
|
+
"afterEach"
|
|
360
|
+
]);
|
|
361
|
+
function isDeclarationShaped(s) {
|
|
362
|
+
const r = s?.range ?? {};
|
|
363
|
+
const st = Number(r.startIndex ?? s?.startIndex);
|
|
364
|
+
const en = Number(r.endIndex ?? s?.endIndex);
|
|
365
|
+
const sl = Number(r.startLine ?? s?.startLine);
|
|
366
|
+
const el = Number(r.endLine ?? s?.endLine);
|
|
367
|
+
return Number.isFinite(st) && Number.isFinite(en) && en > st && Number.isFinite(sl) && sl >= 1 && Number.isFinite(el) && el >= sl;
|
|
368
|
+
}
|
|
369
|
+
function keepSymbol(s, lang) {
|
|
370
|
+
const name = s.name || "";
|
|
371
|
+
if (s.qualifiedName?.startsWith("__global__")) return false;
|
|
372
|
+
if (lang === "json" || lang === "yaml" || lang === "xml" || lang === "make" || lang === "markdown") return true;
|
|
373
|
+
const JS_FAMILY = /* @__PURE__ */ new Set(["javascript", "typescript", "tsx", "vue", "svelte"]);
|
|
374
|
+
const JS_GLOBALS = /* @__PURE__ */ new Set([
|
|
375
|
+
"window",
|
|
376
|
+
"document",
|
|
377
|
+
"console",
|
|
378
|
+
"process",
|
|
379
|
+
"global",
|
|
380
|
+
"__dirname",
|
|
381
|
+
"__filename",
|
|
382
|
+
"module",
|
|
383
|
+
"exports",
|
|
384
|
+
"default",
|
|
385
|
+
"globalThis"
|
|
386
|
+
]);
|
|
387
|
+
if (JS_FAMILY.has(lang) && JS_GLOBALS.has(name)) return isDeclarationShaped(s);
|
|
388
|
+
const UNIVERSAL = /* @__PURE__ */ new Set([
|
|
389
|
+
// Reserved in essentially every language parsed here. Kept unconditionally
|
|
390
|
+
// because no lane produced a legitimate declaration of any of them.
|
|
391
|
+
"this",
|
|
392
|
+
"super",
|
|
393
|
+
// Synthetic artifact names the analyzers themselves mint. These are OURS, not
|
|
394
|
+
// the language's, so no user program can declare them.
|
|
395
|
+
"SCSS_FILE_SCOPE",
|
|
396
|
+
"GlobalScope",
|
|
397
|
+
"module_declaration",
|
|
398
|
+
"package_manifest"
|
|
399
|
+
// REMOVED, each with a lane and a count — see the comment above:
|
|
400
|
+
// self, Self deleted R/Python/Zig `self`; lua declares `local this`
|
|
401
|
+
// me, My legitimate in every language (graphql `me`, lua `me`)
|
|
402
|
+
// destructor a real method name in C++/Rust/Go
|
|
403
|
+
// root lua `local root` at lazy.nvim/lua/lazy/core/loader.lua:497
|
|
404
|
+
// program a legal SQL column name
|
|
405
|
+
// source_file an ordinary R function
|
|
406
|
+
// unknown hcl files declare a variable literally named `unknown`
|
|
407
|
+
//
|
|
408
|
+
// `unknown` is the one that cannot simply be deleted: R7 counts it as a
|
|
409
|
+
// PLACEHOLDER, and 46 registered placeholder sites depend on that. It now moves
|
|
410
|
+
// to RESERVED below rather than being dropped, so a placeholder is still refused
|
|
411
|
+
// while a declared `unknown` survives.
|
|
412
|
+
]);
|
|
413
|
+
if (lang === "julia" && name === "this") return true;
|
|
414
|
+
if (UNIVERSAL.has(name)) return false;
|
|
415
|
+
const RESERVED = {
|
|
416
|
+
// `self` is reserved in PHP and Python 2-style declarations but a LEGAL variable
|
|
417
|
+
// in Lua, Python 3, Rust and Zig, all of which are parsed here.
|
|
418
|
+
php: /* @__PURE__ */ new Set(["self", "parent"]),
|
|
419
|
+
// `program` is reserved in Haskell/Elm-ish contexts; it is a SQL column name.
|
|
420
|
+
sql: /* @__PURE__ */ new Set(["program"])
|
|
421
|
+
};
|
|
422
|
+
if (RESERVED[lang]?.has(name)) {
|
|
423
|
+
const PHP_MEMBER_KINDS = /* @__PURE__ */ new Set(["method", "property", "constant", "enum_member"]);
|
|
424
|
+
const isPhpMember = lang === "php" && PHP_MEMBER_KINDS.has(String(s.kind)) && Boolean(s.ownerName);
|
|
425
|
+
if (!isPhpMember) return false;
|
|
426
|
+
}
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
function nameTheSymbolRule(s, lang) {
|
|
430
|
+
const name = s.name || "";
|
|
431
|
+
if (s.qualifiedName?.startsWith("__global__")) return "qualifiedName is the __global__ sentinel";
|
|
432
|
+
if (["json", "yaml", "xml", "make", "markdown"].includes(lang)) return "language-exempt (kept)";
|
|
433
|
+
if ((/* @__PURE__ */ new Set(["javascript", "typescript", "tsx", "vue", "svelte"])).has(lang) && (/* @__PURE__ */ new Set([
|
|
434
|
+
"window",
|
|
435
|
+
"document",
|
|
436
|
+
"console",
|
|
437
|
+
"process",
|
|
438
|
+
"global",
|
|
439
|
+
"__dirname",
|
|
440
|
+
"__filename",
|
|
441
|
+
"module",
|
|
442
|
+
"exports",
|
|
443
|
+
"default",
|
|
444
|
+
"globalThis"
|
|
445
|
+
])).has(name)) return "JS-family global name";
|
|
446
|
+
return "UNIVERSAL denylist (a keyword or a synthetic tree-sitter artifact name)";
|
|
447
|
+
}
|
|
448
|
+
var JS_FAMILY_LANGUAGES = /* @__PURE__ */ new Set(["javascript", "typescript", "tsx", "vue", "svelte"]);
|
|
449
|
+
var CSS_FAMILY_LANGUAGES = /* @__PURE__ */ new Set(["css", "scss", "sass", "less"]);
|
|
450
|
+
var NOISE_TARGET_FAMILIES = {};
|
|
451
|
+
for (const n of [
|
|
452
|
+
"namedChild",
|
|
453
|
+
"childForFieldName",
|
|
454
|
+
"namedChildren",
|
|
455
|
+
"childCount",
|
|
456
|
+
"namedChildCount",
|
|
457
|
+
"type",
|
|
458
|
+
"text",
|
|
459
|
+
"startIndex",
|
|
460
|
+
"endIndex",
|
|
461
|
+
"startPosition",
|
|
462
|
+
"endPosition",
|
|
463
|
+
"nextSibling",
|
|
464
|
+
"previousSibling",
|
|
465
|
+
"firstChild",
|
|
466
|
+
"lastChild",
|
|
467
|
+
"parent"
|
|
468
|
+
]) {
|
|
469
|
+
NOISE_TARGET_FAMILIES[n] = JS_FAMILY_LANGUAGES;
|
|
470
|
+
}
|
|
471
|
+
for (const n of [
|
|
472
|
+
"font-size",
|
|
473
|
+
"background-color",
|
|
474
|
+
"align-items",
|
|
475
|
+
"justify-content",
|
|
476
|
+
"flex-direction",
|
|
477
|
+
"border-radius",
|
|
478
|
+
"font-weight",
|
|
479
|
+
"line-height",
|
|
480
|
+
"margin-bottom",
|
|
481
|
+
"min-width"
|
|
482
|
+
]) {
|
|
483
|
+
NOISE_TARGET_FAMILIES[n] = CSS_FAMILY_LANGUAGES;
|
|
484
|
+
}
|
|
485
|
+
function importBindingNames(imports) {
|
|
486
|
+
const names = /* @__PURE__ */ new Set();
|
|
487
|
+
const add = (raw) => {
|
|
488
|
+
if (typeof raw !== "string") return;
|
|
489
|
+
let s = raw.trim();
|
|
490
|
+
if (!s) return;
|
|
491
|
+
const colon = s.lastIndexOf(":");
|
|
492
|
+
if (colon >= 0) s = s.slice(colon + 1).trim();
|
|
493
|
+
const slash = s.lastIndexOf("/");
|
|
494
|
+
if (slash >= 0) s = s.slice(slash + 1).trim();
|
|
495
|
+
if (!s) return;
|
|
496
|
+
const asAt = s.indexOf(" as ");
|
|
497
|
+
if (asAt > 0) {
|
|
498
|
+
const imported = s.slice(0, asAt).trim();
|
|
499
|
+
const local = s.slice(asAt + 4).trim();
|
|
500
|
+
if (imported) names.add(imported);
|
|
501
|
+
if (local) names.add(local);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
names.add(s);
|
|
505
|
+
};
|
|
506
|
+
for (const i of imports ?? []) {
|
|
507
|
+
if (!i || typeof i !== "object") continue;
|
|
508
|
+
if (Array.isArray(i.items)) for (const it of i.items) add(it);
|
|
509
|
+
add(i.localName);
|
|
510
|
+
add(i.defaultName);
|
|
511
|
+
add(i.alias);
|
|
512
|
+
add(i.namespaceName);
|
|
513
|
+
}
|
|
514
|
+
return names;
|
|
515
|
+
}
|
|
516
|
+
function filterNoiseRelationships(rels, language, declaredNames, boundNames) {
|
|
517
|
+
if (!rels || rels.length === 0) return rels;
|
|
518
|
+
const extractLeaf = (name) => {
|
|
519
|
+
const afterSep = BINDING_SEP.length > 0 && name.includes(BINDING_SEP) ? name.slice(name.lastIndexOf(BINDING_SEP) + BINDING_SEP.length) : name;
|
|
520
|
+
const noLine = afterSep.replace(/:\d+$/, "");
|
|
521
|
+
const segments = noLine.split(":").filter((s) => s.length > 0);
|
|
522
|
+
const last = segments[segments.length - 1] ?? "";
|
|
523
|
+
const dotParts = last.split(".");
|
|
524
|
+
return dotParts[dotParts.length - 1];
|
|
525
|
+
};
|
|
526
|
+
return rels.filter((r) => {
|
|
527
|
+
const target = r.target || r.targetId || r.to || r.toSymbol || "";
|
|
528
|
+
if (!target) return true;
|
|
529
|
+
if (language === "json" || language === "yaml" || language === "hcl" || language === "terraform" || language === "graphql" || language === "toml") return true;
|
|
530
|
+
if ((language === "bash" || language === "toml") && (r.type === "imports" || r.type === "references" || r.relationshipType === "imports" || r.relationshipType === "references")) {
|
|
531
|
+
if (target.length > 200 || target.includes("\n")) return false;
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
if (language === "julia" && target.includes('var"') && (r.type === "contains" || r.type === "calls" || r.type === "references" || r.relationshipType === "contains" || r.relationshipType === "calls" || r.relationshipType === "references")) {
|
|
535
|
+
if (target.includes("\n") || target.includes(" ") || target.includes(" ")) return false;
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
if (language === "julia" && target.trim() === ":" && (r.type === "calls" || r.relationshipType === "calls")) return true;
|
|
539
|
+
if (target.includes("\n")) return false;
|
|
540
|
+
const leaf = extractLeaf(target);
|
|
541
|
+
const lower = leaf.toLowerCase();
|
|
542
|
+
if (leaf.length < 1) return false;
|
|
543
|
+
const SETTER_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*=$/;
|
|
544
|
+
const OPERATOR_NAME = /^[<>=!+\-*/%^&|~\[\]]+$/;
|
|
545
|
+
const CALLABLE_REF = /^@(?:mixin|function)\s+[A-Za-z_$][\w$-]*$/;
|
|
546
|
+
const DERIVED_TEMPLATE_ID = /xsl:template\[[^\]]*\](?:#\d+)?$/;
|
|
547
|
+
const DECLARED_SIGNATURE = /^[A-Za-z_$][A-Za-z0-9_$]*\(\)$/;
|
|
548
|
+
const isDeclaredSignature = DECLARED_SIGNATURE.test(leaf) && ((declaredNames?.has(leaf) ?? false) || (declaredNames?.has(target) ?? false));
|
|
549
|
+
const isDeclaredName = (declaredNames?.has(leaf) ?? false) || (declaredNames?.has(target) ?? false);
|
|
550
|
+
if (/[\s'"(),=]/.test(leaf) && !OPERATOR_NAME.test(leaf) && !SETTER_NAME.test(leaf) && !CALLABLE_REF.test(leaf) && !DERIVED_TEMPLATE_ID.test(target) && !isDeclaredSignature && !isDeclaredName) return false;
|
|
551
|
+
const isOperatorName = /^[<>=!+\-*/%^&|~\[\]]+$/.test(leaf);
|
|
552
|
+
if (!isOperatorName && /[{}`<>\n\r\t]/.test(leaf)) return false;
|
|
553
|
+
if (leaf.startsWith(" ") || leaf.includes(" ")) return false;
|
|
554
|
+
const declaredTarget = !!declaredNames && (declaredNames.has(String(r.target ?? r.to ?? "")) || declaredNames.has(leaf));
|
|
555
|
+
if (NOISE_TARGETS.has(leaf) && !declaredTarget && // UNION: main's second hatch — a name the file BINDS without declaring (an imported binding is
|
|
556
|
+
// not framework noise). Absent here, present there, and the probe taken from main depends on it.
|
|
557
|
+
!(boundNames && boundNames.has(leaf))) {
|
|
558
|
+
const family = NOISE_TARGET_FAMILIES[leaf];
|
|
559
|
+
if (family && !family.has(language)) return true;
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
return true;
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
var SNIPPET_KINDS = /* @__PURE__ */ new Set(["function", "class", "method", "interface", "impl", "struct"]);
|
|
566
|
+
var engineModule = null;
|
|
567
|
+
async function parseFile(filePath, projectPath, context) {
|
|
568
|
+
const stat = await import("fs/promises").then((fs2) => fs2.stat(filePath));
|
|
569
|
+
const sizeBytes = stat.size;
|
|
570
|
+
const lastModified = stat.mtimeMs;
|
|
571
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
572
|
+
const language = detectLanguageFromPath(filePath) ?? "unknown";
|
|
573
|
+
const STRUCTURAL_LIMIT = 5 * 1024 * 1024;
|
|
574
|
+
if (sizeBytes > STRUCTURAL_LIMIT) {
|
|
575
|
+
log(`Skipping file over 5MB: ${filePath} (${sizeBytes} bytes)`);
|
|
576
|
+
return {
|
|
577
|
+
success: true,
|
|
578
|
+
language,
|
|
579
|
+
fileHash: createHash("sha256").update("").digest("hex").slice(0, 16),
|
|
580
|
+
sizeBytes,
|
|
581
|
+
lastModified,
|
|
582
|
+
symbols: [],
|
|
583
|
+
imports: [],
|
|
584
|
+
relationships: [],
|
|
585
|
+
errors: [],
|
|
586
|
+
fallback: true
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const FULL_AST_LIMIT = 1 * 1024 * 1024;
|
|
590
|
+
if (sizeBytes > FULL_AST_LIMIT) {
|
|
591
|
+
const fsModule = await import("fs/promises");
|
|
592
|
+
const fd = await fsModule.open(filePath, "r");
|
|
593
|
+
const buffer = Buffer.alloc(Math.min(sizeBytes, 256 * 1024));
|
|
594
|
+
await fd.read(buffer, 0, buffer.length, 0);
|
|
595
|
+
await fd.close();
|
|
596
|
+
const content2 = decodeSourceText(buffer).text;
|
|
597
|
+
const hash2 = createHash("sha256").update(content2).digest("hex").slice(0, 16);
|
|
598
|
+
log(`Using structural extraction for large file: ${filePath} (${sizeBytes} bytes)`);
|
|
599
|
+
return extractFallback(content2, language, hash2, sizeBytes, lastModified);
|
|
600
|
+
}
|
|
601
|
+
const decoded = decodeSourceText(await import("fs/promises").then((fs2) => fs2.readFile(filePath)));
|
|
602
|
+
const content = decoded.text;
|
|
603
|
+
const hash = createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
604
|
+
if (decoded.encoding !== "utf8" || decoded.inferred) {
|
|
605
|
+
log(`Decoded ${filePath} as ${decoded.encoding}${decoded.inferred ? " (inferred from a NUL pattern, no BOM)" : decoded.hadBom ? " (BOM)" : ""}`);
|
|
606
|
+
}
|
|
607
|
+
try {
|
|
608
|
+
if (!engineModule) {
|
|
609
|
+
engineModule = await import("./engine-VIW6NSKO.js");
|
|
610
|
+
}
|
|
611
|
+
const parsed = await engineModule.ASTEngine.parseFile(filePath, content, context);
|
|
612
|
+
if ((parsed?.symbols?.length || 0) === 0 && (parsed?.errors?.length || 0) > 0) {
|
|
613
|
+
try {
|
|
614
|
+
const errSample = parsed.errors.slice(0, 3).map((e) => e.message).join(" | ");
|
|
615
|
+
fs.appendFileSync(
|
|
616
|
+
bbDiagnosticsLogPath("parse-errors.log"),
|
|
617
|
+
`${(/* @__PURE__ */ new Date()).toISOString()} | ${language} | ${sizeBytes}B | ${filePath} | ENGINE_EMPTY: ${errSample.substring(0, 200)}
|
|
618
|
+
`
|
|
619
|
+
);
|
|
620
|
+
} catch {
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (ext === ".dart") {
|
|
624
|
+
try {
|
|
625
|
+
fs.appendFileSync(
|
|
626
|
+
bbDiagnosticsLogPath("worker-debug.log"),
|
|
627
|
+
`[Worker] ASTEngine.parseFile returned ${parsed?.relationships?.length || 0} relationships for ${filePath}
|
|
628
|
+
`
|
|
629
|
+
);
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const TAINT_ELIGIBLE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
634
|
+
// The languages the engine dispatches to a REAL analyzer AND for which
|
|
635
|
+
// the taint rules are written against a language API (`db.query`,
|
|
636
|
+
// `child_process`, `PreparedStatement`, `cursor.execute`, …).
|
|
637
|
+
"typescript",
|
|
638
|
+
"tsx",
|
|
639
|
+
"javascript",
|
|
640
|
+
"java",
|
|
641
|
+
"kotlin",
|
|
642
|
+
"scala",
|
|
643
|
+
"groovy",
|
|
644
|
+
"python",
|
|
645
|
+
"ruby",
|
|
646
|
+
"php",
|
|
647
|
+
"go",
|
|
648
|
+
"rust",
|
|
649
|
+
"swift",
|
|
650
|
+
"dart",
|
|
651
|
+
"c",
|
|
652
|
+
"cpp",
|
|
653
|
+
"csharp",
|
|
654
|
+
"perl",
|
|
655
|
+
"lua",
|
|
656
|
+
"r",
|
|
657
|
+
"elixir",
|
|
658
|
+
"erlang",
|
|
659
|
+
"clojure",
|
|
660
|
+
"haskell",
|
|
661
|
+
"zig",
|
|
662
|
+
"nim",
|
|
663
|
+
"fsharp",
|
|
664
|
+
"vb",
|
|
665
|
+
"powershell",
|
|
666
|
+
"bash",
|
|
667
|
+
"objective-c"
|
|
668
|
+
// Explicitly EXCLUDED, and each exclusion is load-bearing:
|
|
669
|
+
// markdown json yaml toml xml html css sass scss graphql protobuf
|
|
670
|
+
// make clean hcl terraform svelte vue sql
|
|
671
|
+
// Markdown/JSON/YAML/TOML/XML/HTML/CSS carry prose and data, not code —
|
|
672
|
+
// measured at 326 of 3,190 bb_security findings (10.2%). The rest are
|
|
673
|
+
// schema, query, build and markup formats whose tokens ("select", "exec",
|
|
674
|
+
// "query") collide with the sink rules without ever being a sink.
|
|
675
|
+
]);
|
|
676
|
+
const taintEligible = TAINT_ELIGIBLE_LANGUAGES.has((language || "").toLowerCase());
|
|
677
|
+
try {
|
|
678
|
+
if (taintEligible) {
|
|
679
|
+
const { TaintAnalyzer } = await import("./taint-analyzer-N7YLZU3N.js");
|
|
680
|
+
TaintAnalyzer.enrichSymbols(parsed.symbols, content, language);
|
|
681
|
+
}
|
|
682
|
+
} catch (e) {
|
|
683
|
+
log("Taint extraction failed:", e);
|
|
684
|
+
}
|
|
685
|
+
let snippetLines;
|
|
686
|
+
const identityOf = (s) => {
|
|
687
|
+
const out = [];
|
|
688
|
+
if (s?.name) out.push(String(s.name));
|
|
689
|
+
if (s?.qualifiedName) out.push(String(s.qualifiedName));
|
|
690
|
+
if (typeof s?.metadata?.fqn === "string" && s.metadata.fqn) out.push(String(s.metadata.fqn));
|
|
691
|
+
if (s?.name) {
|
|
692
|
+
out.push(
|
|
693
|
+
s.qualifiedName || s.metadata?.fqn || (s.scope ? `${s.scope}.${s.name}` : String(s.name))
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
return out;
|
|
697
|
+
};
|
|
698
|
+
const keptSymbols = [];
|
|
699
|
+
const keptNames = /* @__PURE__ */ new Set();
|
|
700
|
+
const notKept = [];
|
|
701
|
+
for (const s of parsed.symbols ?? []) {
|
|
702
|
+
if (keepSymbol(s, parsed.language || language)) {
|
|
703
|
+
keptSymbols.push(s);
|
|
704
|
+
for (const id of identityOf(s)) keptNames.add(id);
|
|
705
|
+
} else {
|
|
706
|
+
notKept.push(s);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
const droppedNames = /* @__PURE__ */ new Set();
|
|
710
|
+
for (const s of notKept) {
|
|
711
|
+
for (const id of identityOf(s)) {
|
|
712
|
+
if (!keptNames.has(id)) droppedNames.add(id);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const ret = {
|
|
716
|
+
success: true,
|
|
717
|
+
language: parsed.language || language,
|
|
718
|
+
framework: parsed.metadata?.framework,
|
|
719
|
+
fileHash: hash,
|
|
720
|
+
sizeBytes,
|
|
721
|
+
lastModified,
|
|
722
|
+
symbols: keptSymbols.map((s) => {
|
|
723
|
+
let snippet = "";
|
|
724
|
+
if (SNIPPET_KINDS.has(s.kind)) {
|
|
725
|
+
const lines = snippetLines ?? (snippetLines = content.split("\n"));
|
|
726
|
+
snippet = lines.slice(Math.max(0, s.range.startLine - 1), s.range.endLine).join("\n");
|
|
727
|
+
if (snippet.length > 1e4) snippet = snippet.substring(0, 1e4);
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
name: s.name,
|
|
731
|
+
type: s.kind,
|
|
732
|
+
kind: s.kind,
|
|
733
|
+
qualifiedName: s.qualifiedName || s.metadata?.fqn || (s.scope ? `${s.scope}.${s.name}` : s.name),
|
|
734
|
+
startLine: s.range.startLine,
|
|
735
|
+
endLine: s.range.endLine,
|
|
736
|
+
startIndex: s.range.startIndex,
|
|
737
|
+
endIndex: s.range.endIndex,
|
|
738
|
+
visibility: s.visibility || "public",
|
|
739
|
+
parameters: s.parameters,
|
|
740
|
+
returnType: s.returnType,
|
|
741
|
+
qualifiedCalls: s.qualified_calls,
|
|
742
|
+
complexity: s.complexity || s.metadata?.complexity || 1,
|
|
743
|
+
ownerName: s.ownerName || s.scope,
|
|
744
|
+
ownerKind: s.ownerKind || s.metadata?.ownerKind,
|
|
745
|
+
scope: s.scope,
|
|
746
|
+
taintSources: s.taintSources,
|
|
747
|
+
taintSinks: s.taintSinks,
|
|
748
|
+
decorators: s.decorators,
|
|
749
|
+
genericParameters: s.genericParameters,
|
|
750
|
+
isStatic: s.isStatic,
|
|
751
|
+
isAsync: s.isAsync,
|
|
752
|
+
isAbstract: s.isAbstract,
|
|
753
|
+
// M35 pre-work: carry the analyzer-extracted docstring across the
|
|
754
|
+
// worker boundary. It was dropped here AND never bound in the
|
|
755
|
+
// brain_symbol INSERT, so brain_symbol.docstring was always NULL.
|
|
756
|
+
docstring: s.docstring ?? null,
|
|
757
|
+
// SOL-16. `docstring` alone cannot answer "is this NatSpec, or a stray
|
|
758
|
+
// `//` remark?" — and Solidity's documentation system has THREE forms
|
|
759
|
+
// (`///`, the slash-star block, and a plain line comment), so the kind is
|
|
760
|
+
// the difference between documented code and a comment that happened to sit
|
|
761
|
+
// above a declaration. `docTags` is the structured half: the tags are inside
|
|
762
|
+
// `docstring` already, but a consumer that wants `@param` names should not
|
|
763
|
+
// have to re-parse prose, and `comments` is the per-comment array the
|
|
764
|
+
// TypeScript lane populates for the same job, so a reader of Solidity
|
|
765
|
+
// documentation should not have to learn a second shape.
|
|
766
|
+
//
|
|
767
|
+
// Purely additive, on the same terms as the CSS forwarding above: nothing
|
|
768
|
+
// read these before, so no consumer changes behaviour.
|
|
769
|
+
// SOL-22. A LICENCE is a file-level fact and the module symbol is the only
|
|
770
|
+
// symbol that can carry it, so without this key a Solidity file's licence was
|
|
771
|
+
// in the analyzer's payload and in no consumer's hands — the same seam as
|
|
772
|
+
// `docstring` above, and the same terms: additive, nothing read it before.
|
|
773
|
+
license: s.license ?? s.metadata?.license ?? null,
|
|
774
|
+
// SOL-23: the NatSpec-vs-signature findings, per symbol. Additive on the same
|
|
775
|
+
// terms as the rest of this block.
|
|
776
|
+
undocumentedParameters: s.undocumentedParameters ?? null,
|
|
777
|
+
// Data location (`transient` / `storage` / `memory` / `calldata`). Read by the
|
|
778
|
+
// analyzer from the declaration's `location:` field, and invisible until it is
|
|
779
|
+
// whitelisted here. The CORPUS cannot exercise it — this grammar reports
|
|
780
|
+
// `transient` on the state-variable field rather than as a `layout_specifier`
|
|
781
|
+
// node, and no OpenZeppelin contract at 5.5.0 declares one — so the fixture is
|
|
782
|
+
// the only place this can be gated, which is worth knowing before anyone reads
|
|
783
|
+
// a zero here as a broken path.
|
|
784
|
+
stateLocation: s.stateLocation ?? s.metadata?.stateLocation ?? null,
|
|
785
|
+
overDocumentedParameters: s.overDocumentedParameters ?? null,
|
|
786
|
+
returnDocumentedWithoutReturn: s.returnDocumentedWithoutReturn ?? false,
|
|
787
|
+
docstringKind: s.docstringKind ?? s.metadata?.docstringKind ?? null,
|
|
788
|
+
docTags: s.docTags ?? s.metadata?.docTags ?? null,
|
|
789
|
+
comments: s.comments ?? s.metadata?.comments ?? null,
|
|
790
|
+
// #612 store-phase (same seam class as docstring above and scope_kind
|
|
791
|
+
// below): the declaration/definition fact. c has published
|
|
792
|
+
// `metadata.isDeclaration` since the HC1 review, and cpp/rust/zig
|
|
793
|
+
// publish it as of #612 — but the whole `metadata` object was dropped
|
|
794
|
+
// HERE, so brain_symbol.annotations was NULL for every analyzer
|
|
795
|
+
// symbol and the store had nothing but the NAME to resolve with. The
|
|
796
|
+
// narrow key is carried rather than all of metadata: it is the one
|
|
797
|
+
// metadata fact the store phase reads (a schema column of its own,
|
|
798
|
+
// `is_declaration`), and widening `annotations` for every symbol in
|
|
799
|
+
// every language is a separate, larger change that would need its own
|
|
800
|
+
// measurement round.
|
|
801
|
+
isDeclaration: s.metadata?.isDeclaration === true || void 0,
|
|
802
|
+
// CSS lane (2026-09-26). The same seam as `isDeclaration` above, met
|
|
803
|
+
// from the other side: the store DOES read `symbol.metadata` and
|
|
804
|
+
// serialise it into `brain_symbol.annotations`, but the whole
|
|
805
|
+
// `metadata` object is dropped HERE, so nothing an analyzer puts in it
|
|
806
|
+
// survives the worker boundary. For CSS that silently deleted a
|
|
807
|
+
// payload the lane's own ruling depends on — `declaresProperties`,
|
|
808
|
+
// which replaced 32,654 relationships to CSS property names that are
|
|
809
|
+
// not graph nodes (measured: `uses` resolved at both ends 6.0% of the
|
|
810
|
+
// time, and the production filter then discarded the class outright).
|
|
811
|
+
// Trading a wrong edge for a dead field is not a fix, so the payload is
|
|
812
|
+
// carried.
|
|
813
|
+
//
|
|
814
|
+
// Deliberately NARROW, and deliberately CSS-only, for the reason the
|
|
815
|
+
// comment above gives: widening `annotations` for every symbol in every
|
|
816
|
+
// language is a separate, larger change that needs its own measurement
|
|
817
|
+
// round. The keys below are the ones the CSS lane's F6/F8/CC1 checks
|
|
818
|
+
// read, so the channel carries facts that are consumed rather than
|
|
819
|
+
// facts that are merely produced.
|
|
820
|
+
// Emitted under the name the indexer already reads, so the existing
|
|
821
|
+
// `symbol.metadata -> annotations` INSERT path carries it with no
|
|
822
|
+
// change on the store side.
|
|
823
|
+
metadata: (() => {
|
|
824
|
+
const m = s.metadata;
|
|
825
|
+
if (!m) return void 0;
|
|
826
|
+
const out = {};
|
|
827
|
+
if (Array.isArray(m.declaresProperties)) out.declaresProperties = m.declaresProperties;
|
|
828
|
+
if (typeof m.declaredPropertyCount === "number") out.declaredPropertyCount = m.declaredPropertyCount;
|
|
829
|
+
if (typeof m.isSelector === "boolean") out.isSelector = m.isSelector;
|
|
830
|
+
if (typeof m.isComplex === "boolean") out.isComplex = m.isComplex;
|
|
831
|
+
if (typeof m.isUtility === "boolean") out.isUtility = m.isUtility;
|
|
832
|
+
if (typeof m.isCustomProperty === "boolean") out.isCustomProperty = m.isCustomProperty;
|
|
833
|
+
if (typeof m.isKeyframes === "boolean") out.isKeyframes = m.isKeyframes;
|
|
834
|
+
if (typeof m.isSupports === "boolean") out.isSupports = m.isSupports;
|
|
835
|
+
if (typeof m.isAtRule === "boolean") out.isAtRule = m.isAtRule;
|
|
836
|
+
if (typeof m.isCssModule === "boolean") out.isCssModule = m.isCssModule;
|
|
837
|
+
if (Array.isArray(m.specificity)) out.specificity = m.specificity;
|
|
838
|
+
if (Array.isArray(m.classNames)) out.classNames = m.classNames;
|
|
839
|
+
if (m.selectorComposition) out.selectorComposition = m.selectorComposition;
|
|
840
|
+
if (typeof m.supportsCondition === "string") out.supportsCondition = m.supportsCondition;
|
|
841
|
+
if (typeof m.atKeyword === "string") out.atKeyword = m.atKeyword;
|
|
842
|
+
if (Array.isArray(m.selectorChain)) out.selectorChain = m.selectorChain;
|
|
843
|
+
if (typeof m.nodeType === "string") out.nodeType = m.nodeType;
|
|
844
|
+
if (typeof m.headingLevel === "number") out.headingLevel = m.headingLevel;
|
|
845
|
+
if (typeof m.language === "string") out.language = m.language;
|
|
846
|
+
if (m.isMarkdownHeading === true) out.isMarkdownHeading = m.isMarkdownHeading;
|
|
847
|
+
if (m.isMarkdownTable === true) out.isMarkdownTable = m.isMarkdownTable;
|
|
848
|
+
if (m.isMarkdownTableColumn === true) out.isMarkdownTableColumn = m.isMarkdownTableColumn;
|
|
849
|
+
if (m.isMarkdownCodeBlock === true) out.isMarkdownCodeBlock = m.isMarkdownCodeBlock;
|
|
850
|
+
if (m.isMarkdownFrontMatter === true) out.isMarkdownFrontMatter = m.isMarkdownFrontMatter;
|
|
851
|
+
if (m.isRepeatedSite === true) out.isRepeatedSite = m.isRepeatedSite;
|
|
852
|
+
if (m.isExported === true) out.isExported = m.isExported;
|
|
853
|
+
if (m.isImplicitBinding === true) out.isImplicitBinding = m.isImplicitBinding;
|
|
854
|
+
if (typeof m.bindingSite === "string") out.bindingSite = m.bindingSite;
|
|
855
|
+
if (typeof m.isArray === "boolean") out.isArray = m.isArray;
|
|
856
|
+
if (Array.isArray(m.superTypes) && m.superTypes.length > 0) out.superTypes = m.superTypes;
|
|
857
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
858
|
+
})(),
|
|
859
|
+
snippet
|
|
860
|
+
};
|
|
861
|
+
}),
|
|
862
|
+
imports: (parsed.imports || []).flatMap((i) => {
|
|
863
|
+
const items = Array.isArray(i.items) && i.items.length > 0 ? i.items : [i.localName || i.module || ""];
|
|
864
|
+
const baseType = i.isDefault || i.isDefaultImport ? "default" : i.isNamespace || i.isNamespaceImport ? "namespace" : "named";
|
|
865
|
+
const declared = i.metadata ?? {};
|
|
866
|
+
const external = declared.isSystemInclude === true || declared.isExternal === true || i.isExternal === true ? true : declared.isSystemInclude === false || declared.isExternal === false ? false : typeof i.module === "string" ? !i.module.startsWith(".") && !i.module.startsWith("/") : !!i.isExternal;
|
|
867
|
+
const line = i.range?.startLine ?? i.line ?? i.line_number ?? i.lineNumber ?? 0;
|
|
868
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
869
|
+
for (const b of Array.isArray(i.itemBindings) ? i.itemBindings : []) {
|
|
870
|
+
if (b && typeof b.name === "string" && typeof b.as === "string" && b.name && b.as) {
|
|
871
|
+
bindings.set(b.name, b.as);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
const itemCount = items.length;
|
|
875
|
+
const statementAlias = itemCount === 1 && typeof i.alias === "string" && i.alias ? i.alias : itemCount === 1 && typeof i.localName === "string" && i.localName ? i.localName : void 0;
|
|
876
|
+
return items.filter((name) => typeof name === "string" && name.length > 0).map((name) => {
|
|
877
|
+
const asMatch = name.match(/^(\S+)\s+as\s+(\S+)$/);
|
|
878
|
+
const importedName = asMatch ? asMatch[1] : name;
|
|
879
|
+
const cleanName = importedName.replace(/^type\s+/, "").trim();
|
|
880
|
+
const boundName = asMatch ? asMatch[2] : bindings.get(name) ?? statementAlias;
|
|
881
|
+
return {
|
|
882
|
+
name: cleanName,
|
|
883
|
+
path: i.module || i.path || "",
|
|
884
|
+
...boundName ? { alias: boundName } : {},
|
|
885
|
+
// The analyzer's OWN classification, when it declares one. Five lanes do:
|
|
886
|
+
// makefile `make_include`, objective-c `include`, sql `sql_import`, xml
|
|
887
|
+
// `xml-doctype`, yaml `yaml_tag_include` / `yaml_keyword_include` /
|
|
888
|
+
// `github_action`. The fallback below is the JS/TS idiom
|
|
889
|
+
// (named/default/namespace), and applying it to every language made all
|
|
890
|
+
// 442 of this lane's corpus imports read `named` — so an Ansible
|
|
891
|
+
// `include_tasks: tasks.yml` PROJECT file dependency and a GitHub Actions
|
|
892
|
+
// `uses: actions/checkout@v4` EXTERNAL tool invocation became
|
|
893
|
+
// indistinguishable in the row the file-dependency engine reads. The
|
|
894
|
+
// relationships always carried the distinction; the row did not.
|
|
895
|
+
//
|
|
896
|
+
// Safe to prefer: the stored column is `import_type`, no fixture in the
|
|
897
|
+
// tree pins this field, and the only consumer that branches on an import's
|
|
898
|
+
// `type` (import-pruner.ts) reads JS/TS AST SPECIFIERS — a different
|
|
899
|
+
// structure entirely, not these rows. A lane that sets no `importType`
|
|
900
|
+
// keeps the historical value unchanged.
|
|
901
|
+
type: i.importType ?? (asMatch ? "alias" : baseType),
|
|
902
|
+
isExternal: external,
|
|
903
|
+
line
|
|
904
|
+
};
|
|
905
|
+
});
|
|
906
|
+
}),
|
|
907
|
+
// THE DROPPED-SYMBOL INVARIANT — see `droppedNames` above. An edge that names a symbol
|
|
908
|
+
// this call filtered out is not a weaker edge, it is an edge to nothing, so it goes with
|
|
909
|
+
// the symbol. Applied BEFORE the noise filter so the two are independent and either can
|
|
910
|
+
// be measured alone.
|
|
911
|
+
relationships: filterNoiseRelationships(
|
|
912
|
+
droppedNames.size ? (parsed.relationships ?? []).filter((r) => {
|
|
913
|
+
const type = String(r?.type ?? r?.relationshipType ?? "");
|
|
914
|
+
const src = String(r?.source ?? r?.from ?? "");
|
|
915
|
+
const tgt = String(r?.target ?? r?.to ?? "");
|
|
916
|
+
if ((type === "imports" || type === "exports") && droppedNames.has(src)) return true;
|
|
917
|
+
return !droppedNames.has(src) && !droppedNames.has(tgt);
|
|
918
|
+
}) : parsed.relationships,
|
|
919
|
+
language,
|
|
920
|
+
new Set((parsed.symbols ?? []).map((s) => String(s?.name ?? "")).filter(Boolean))
|
|
921
|
+
),
|
|
922
|
+
// M60 LUA-14: the analyzer's `exports` were never forwarded here, so the
|
|
923
|
+
// entire export surface of every language was invisible to the index. This
|
|
924
|
+
// is the same defect the `metadata` line below already documents for
|
|
925
|
+
// metadata — two entry points that disagreed, with the worker the lossy one
|
|
926
|
+
// — except that nobody had measured the size of it. Now measured, over
|
|
927
|
+
// every Lua file of two pinned corpora: 1,587 exports on kong and 187 on
|
|
928
|
+
// luvit, emitted by the analyzer and returned by nobody. Zero of 1,774
|
|
929
|
+
// reached the product.
|
|
930
|
+
//
|
|
931
|
+
// `ParseResult.exports` was already declared optional and `engine.ts`
|
|
932
|
+
// already forwards it, so this adds no new contract: it makes the worker
|
|
933
|
+
// agree with the engine it wraps. `?? []` rather than a bare field, because
|
|
934
|
+
// `extractFallback` and the size/extension early-returns build their own
|
|
935
|
+
// objects and a consumer must not have to distinguish "no exports" from
|
|
936
|
+
// "this path never set the key".
|
|
937
|
+
exports: parsed.exports ?? [],
|
|
938
|
+
errors: parsed.errors || [],
|
|
939
|
+
// <-- Stage 4: propagate syntax errors from the AST Engine
|
|
940
|
+
// The analyzer's WHOLE `metadata` object was being dropped here, and this
|
|
941
|
+
// is the function `parallel-indexer.ts:889` uses — the production indexing
|
|
942
|
+
// path. `engine.ts` carries it (its own result type is
|
|
943
|
+
// `Omit<ParseResult, "language" | "metadata"> & { metadata?: ... }`), so the
|
|
944
|
+
// two entry points disagreed and the worker was the lossy one. Found by
|
|
945
|
+
// running the bash contract probe through `parseFile` rather than through
|
|
946
|
+
// the analyzer directly: the analyzer reported 10 patterns for
|
|
947
|
+
// `Deploy.sh` — Strict Error Handling, Insecure Pipe Execution, Privilege
|
|
948
|
+
// Escalation, Destructive File Operation — and `parseFile` returned none.
|
|
949
|
+
// Every pattern-based signal in every language was invisible to the index.
|
|
950
|
+
// Purely additive: nothing read this before, so no consumer changes
|
|
951
|
+
// behaviour, and the fields that WERE forwarded (`framework` above) are
|
|
952
|
+
// left exactly as they were.
|
|
953
|
+
metadata: parsed.metadata
|
|
954
|
+
};
|
|
955
|
+
if (ext === ".dart") {
|
|
956
|
+
try {
|
|
957
|
+
fs.appendFileSync(
|
|
958
|
+
bbDiagnosticsLogPath("worker-debug.log"),
|
|
959
|
+
`[Worker] Returning object with ${ret.relationships?.length || 0} relationships for ${filePath}
|
|
960
|
+
`
|
|
961
|
+
);
|
|
962
|
+
} catch {
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return ret;
|
|
966
|
+
} catch (parseError) {
|
|
967
|
+
const errMsg = parseError?.message || String(parseError);
|
|
968
|
+
const isExpected = errMsg.includes("Unsupported file type") || errMsg.includes("Failed to determine WASM path") || errMsg.includes("not yet implemented");
|
|
969
|
+
const lang = detectLanguageFromPath(filePath) ?? "unknown";
|
|
970
|
+
if (!isExpected) {
|
|
971
|
+
process.stderr.write(`[BB-PARSE-ERR] ${lang} | ${filePath} | ${errMsg.substring(0, 300)}
|
|
972
|
+
`);
|
|
973
|
+
}
|
|
974
|
+
return extractFallback(content, lang, hash, sizeBytes, lastModified);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
async function warmUpWorker() {
|
|
978
|
+
let wasm = "ok";
|
|
979
|
+
try {
|
|
980
|
+
const { ensureWasmRegistry } = await import("./wasm-NMWO3WXY.js");
|
|
981
|
+
await ensureWasmRegistry();
|
|
982
|
+
} catch (e) {
|
|
983
|
+
wasm = "unavailable";
|
|
984
|
+
reportStartupProblem("wasm registry unavailable \u2014 tree-sitter grammars may not load", e);
|
|
985
|
+
}
|
|
986
|
+
let engine = "ok";
|
|
987
|
+
try {
|
|
988
|
+
engineModule = await import("./engine-VIW6NSKO.js");
|
|
989
|
+
if (!engineModule?.ASTEngine) {
|
|
990
|
+
engine = "unavailable";
|
|
991
|
+
reportStartupProblem("engine module loaded but exports no ASTEngine", new Error("ASTEngine missing"));
|
|
992
|
+
}
|
|
993
|
+
} catch (e) {
|
|
994
|
+
engine = "unavailable";
|
|
995
|
+
reportStartupProblem("engine module failed to load \u2014 falling back to regex extraction for EVERY file", e);
|
|
996
|
+
}
|
|
997
|
+
return { engine, wasm };
|
|
998
|
+
}
|
|
999
|
+
function persistStartupDiagnostics() {
|
|
1000
|
+
if (startupDiagnostics.length === 0) return;
|
|
1001
|
+
try {
|
|
1002
|
+
fs.appendFileSync(
|
|
1003
|
+
bbDiagnosticsLogPath("worker-startup.log"),
|
|
1004
|
+
`${(/* @__PURE__ */ new Date()).toISOString()} | pid=${process.pid} | node=${process.version} | ${startupDiagnostics.join(" | ")}
|
|
1005
|
+
`
|
|
1006
|
+
);
|
|
1007
|
+
} catch {
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async function runSelfTest() {
|
|
1011
|
+
const { engine, wasm } = await warmUpWorker();
|
|
1012
|
+
persistStartupDiagnostics();
|
|
1013
|
+
const report = {
|
|
1014
|
+
ok: engine === "ok" && wasm === "ok",
|
|
1015
|
+
engine,
|
|
1016
|
+
wasm,
|
|
1017
|
+
node: process.version,
|
|
1018
|
+
pid: process.pid,
|
|
1019
|
+
execPath: process.execPath,
|
|
1020
|
+
diagnostics: startupDiagnostics.slice(0, 5)
|
|
1021
|
+
};
|
|
1022
|
+
process.stdout.write(`[BB-WORKER-SELFTEST] ${JSON.stringify(report)}
|
|
1023
|
+
`);
|
|
1024
|
+
return report.ok ? 0 : 1;
|
|
1025
|
+
}
|
|
1026
|
+
process.on("message", async (msg) => {
|
|
1027
|
+
if (msg.type === "warmup") {
|
|
1028
|
+
const watchdogMs = Number(process.env.BB_WORKER_STARTUP_TIMEOUT_MS || 0) || 3e4;
|
|
1029
|
+
const slowWarmNote = setTimeout(() => {
|
|
1030
|
+
process.stderr.write(
|
|
1031
|
+
`[BB-WORKER-STARTUP] still warming after ${Math.round(watchdogMs / 2)}ms (loading tree-sitter grammars); the parent's watchdog is ${watchdogMs}ms
|
|
1032
|
+
`
|
|
1033
|
+
);
|
|
1034
|
+
}, Math.max(1, Math.round(watchdogMs / 2)));
|
|
1035
|
+
slowWarmNote.unref?.();
|
|
1036
|
+
const { engine: engineStatus, wasm: wasmStatus } = await warmUpWorker();
|
|
1037
|
+
if (engineStatus === "unavailable") {
|
|
1038
|
+
safeSend({ type: "engine_fail", workerId: msg.workerId, error: startupDiagnostics.join(" | ") });
|
|
1039
|
+
}
|
|
1040
|
+
if (process.env.BB_TEST_HOOKS === "1") {
|
|
1041
|
+
const delayReady = Number(process.env.BB_WORKER_DELAY_READY_MS || 0);
|
|
1042
|
+
if (delayReady > 0) await new Promise((r) => setTimeout(r, delayReady));
|
|
1043
|
+
}
|
|
1044
|
+
clearTimeout(slowWarmNote);
|
|
1045
|
+
safeSend({
|
|
1046
|
+
type: "ready",
|
|
1047
|
+
workerId: msg.workerId,
|
|
1048
|
+
pid: process.pid,
|
|
1049
|
+
node: process.version,
|
|
1050
|
+
execPath: process.execPath,
|
|
1051
|
+
engine: engineStatus,
|
|
1052
|
+
wasm: wasmStatus,
|
|
1053
|
+
diagnostics: startupDiagnostics.slice(0, 5)
|
|
1054
|
+
});
|
|
1055
|
+
persistStartupDiagnostics();
|
|
1056
|
+
} else if (msg.type === "parse_batch") {
|
|
1057
|
+
const { batchId, files, projectPath, projectIndexes } = msg;
|
|
1058
|
+
let indexCache = null;
|
|
1059
|
+
if (projectIndexes !== void 0 && projectIndexes !== null) {
|
|
1060
|
+
try {
|
|
1061
|
+
const mod = await import("./project-index-5SDPHITE.js");
|
|
1062
|
+
indexCache = /* @__PURE__ */ new Map();
|
|
1063
|
+
for (const [lang, raw] of Object.entries(projectIndexes)) {
|
|
1064
|
+
const built = mod.deserializeProjectIndex(raw);
|
|
1065
|
+
if (built !== null) {
|
|
1066
|
+
mod.buildResolutionTables(built);
|
|
1067
|
+
indexCache.set(lang, built);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
} catch (e) {
|
|
1071
|
+
log(`[Worker] project index unavailable, continuing per-file: ${e?.message ?? e}`);
|
|
1072
|
+
reportStartupProblem("project index unavailable, indexing per-file", e);
|
|
1073
|
+
indexCache = null;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
const extnameOf = (p) => {
|
|
1077
|
+
const base = p.slice(p.lastIndexOf("/") + 1);
|
|
1078
|
+
const dot = base.lastIndexOf(".");
|
|
1079
|
+
return dot <= 0 ? "" : base.slice(dot).toLowerCase();
|
|
1080
|
+
};
|
|
1081
|
+
const contextFor = (filePath) => {
|
|
1082
|
+
const root = String(projectPath ?? "") || void 0;
|
|
1083
|
+
if (indexCache === null) return root === void 0 ? void 0 : { projectRoot: root };
|
|
1084
|
+
const ext = extnameOf(filePath);
|
|
1085
|
+
const built = indexCache.get(ext);
|
|
1086
|
+
if (built === void 0) return root === void 0 ? void 0 : { projectRoot: root };
|
|
1087
|
+
return { projectIndex: built, projectRoot: root };
|
|
1088
|
+
};
|
|
1089
|
+
const FILE_TIMEOUT_MS = Number(process.env.BB_FILE_TIMEOUT_MS || 45e3);
|
|
1090
|
+
let delayParse = 0;
|
|
1091
|
+
if (process.env.BB_TEST_HOOKS === "1") {
|
|
1092
|
+
if (process.env.BB_WORKER_CRASH_ON_BATCH === "1") {
|
|
1093
|
+
process.stderr.write(`[BB-WORKER-FIXTURE] crashing on parse_batch (batch ${batchId})
|
|
1094
|
+
`);
|
|
1095
|
+
process.exit(1);
|
|
1096
|
+
}
|
|
1097
|
+
delayParse = Number(process.env.BB_WORKER_DELAY_PARSE_MS || 0);
|
|
1098
|
+
}
|
|
1099
|
+
for (const filePath of files) {
|
|
1100
|
+
try {
|
|
1101
|
+
safeSend({ type: "file_start", batchId, filePath });
|
|
1102
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
1103
|
+
if (delayParse > 0) await new Promise((r) => setTimeout(r, delayParse));
|
|
1104
|
+
const fileTimer = setTimeout(() => {
|
|
1105
|
+
log(`Worker self-timeout: killing process after ${FILE_TIMEOUT_MS}ms on ${filePath}`);
|
|
1106
|
+
process.exit(1);
|
|
1107
|
+
}, FILE_TIMEOUT_MS);
|
|
1108
|
+
const result = await parseFile(filePath, projectPath, contextFor(filePath));
|
|
1109
|
+
clearTimeout(fileTimer);
|
|
1110
|
+
safeSend({ type: "file_done", batchId, filePath, result });
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
safeSend({
|
|
1113
|
+
type: "file_error",
|
|
1114
|
+
batchId,
|
|
1115
|
+
filePath,
|
|
1116
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
safeSend({ type: "batch_done", batchId });
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
process.on("disconnect", () => process.exit(0));
|
|
1124
|
+
if (process.connected) {
|
|
1125
|
+
if (process.env.BB_POOL_WORKER !== "1") {
|
|
1126
|
+
process.stderr.write(
|
|
1127
|
+
`[BB-WORKER-STARTUP] forked with BB_POOL_WORKER=${JSON.stringify(process.env.BB_POOL_WORKER ?? null)} rather than "1"; serving anyway \u2014 unset BB_POOL_WORKER to use in-process indexing
|
|
1128
|
+
`
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
setInterval(() => {
|
|
1132
|
+
}, 1 << 30);
|
|
1133
|
+
}
|
|
1134
|
+
if (process.env.BB_POOL_WORKER_SELFTEST === "1" && !process.connected) {
|
|
1135
|
+
runSelfTest().then(
|
|
1136
|
+
(code) => {
|
|
1137
|
+
process.exitCode = code;
|
|
1138
|
+
},
|
|
1139
|
+
(e) => {
|
|
1140
|
+
process.stderr.write(`[BB-WORKER-SELFTEST] failed: ${e?.message ?? String(e)}
|
|
1141
|
+
`);
|
|
1142
|
+
process.exitCode = 1;
|
|
1143
|
+
}
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
export {
|
|
1147
|
+
extractFallback,
|
|
1148
|
+
filterNoiseRelationships,
|
|
1149
|
+
importBindingNames,
|
|
1150
|
+
keepSymbol,
|
|
1151
|
+
nameTheSymbolRule,
|
|
1152
|
+
parseFile
|
|
1153
|
+
};
|