feat(graph): index Hacklang (.hack/.hhi) via a native tree-sitter-hack grammar - #348
feat(graph): index Hacklang (.hack/.hhi) via a native tree-sitter-hack grammar#348mmissey wants to merge 3 commits into
Conversation
…ute C) Add depth-tier extraction for Hack (`.hack`/`.hhi`) using its own vendored tree-sitter grammar and a dedicated node-kind mapping — higher fidelity than reusing the PHP grammar, and no `<?hh` shim (tagless Hack parses natively). - vendor/tree-sitter-hack: upstream Hack grammar sources, re-bound with node-addon-api so the language object passes tree-sitter@0.21's type-tag check. build/ and node_modules/ are git-ignored (rebuilt on npm install). - extract.ts: `hack` language, `.hack`/`.hhi` extensions, HACK_KINDS (incl. `enum_class_declaration`), call/heritage/import handling for Hack's node shapes (single call_expression, direct extends/implements clauses, trait_use_clause, use_clause). - bindings.ts: typed-parameter and `new`-assignment receiver-type bindings. - resolve.ts: trait-method resolution now spans .hack/.hhi, not just .php. - test/graph-hack.test.ts: nodes, edges, trait use, param binding, enum class. Smoke-tested on 275 real webapp .hack files: 0 extraction throws, 1.1% file-only (all genuinely symbol-free), receiver types on ~19% of call edges. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
…of vendoring
Replace the `file:vendor/tree-sitter-hack` dependency (an ~11MB committed
parser.c plus a node-addon-api rebind) with an npm alias:
"tree-sitter-hack": "npm:@mmissey/tree-sitter-hacklang@^0.1.0"
This mirrors the existing `tree-sitter-r` -> `@davisvaughan/tree-sitter-r`
alias, so the `import Hack from "tree-sitter-hack"` in extract.ts is unchanged.
@mmissey/tree-sitter-hacklang is the same grammar re-bound with node-addon-api
for tree-sitter@0.21+, now published with prebuilt binaries (no C toolchain
needed on supported platforms). The whole vendor/ tree is removed.
Hack extraction tests: 6/6 pass against the published package.
Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
0.1.1 is the first release shipping prebuilt binaries for all four platforms (linux-x64, darwin-arm64, darwin-x64, win32-x64), so installs no longer need a local C toolchain on any of them. Pins the lockfile to 0.1.1 and updates the @lavamoat/allow-scripts key to match. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
🌱 graft blast radius1 area changed → 3 areas can be affected. 5 dependent symbols, depth 2. flowchart TB
A0(("Graph Building<br/>2 symbols"))
A1(("Pull Request Review<br/>2 symbols"))
A2(("Graph Representation<br/>1 symbol"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2 reached;
Who knows this code — 5 people across 4 areas
Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no All 5 dependent symbols, grouped by areaGraph Building — 2 symbols in 2 files
Pull Request Review — 2 symbols in 2 files
Graph Representation — 1 symbol in 1 file
Test signal per changed area — 1 ⚠Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.
35 test suites also reference this code38 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.
Open the interactive graph → — click an area to see the code that changed, and the line that reaches it. |
What
Adds first-class Hacklang (
.hack/.hhi) support to the code graph, using a nativetree-sitter-hackgrammar with its own node-kind mapping (higher fidelity than reusing the PHP grammar).The grammar is distributed as a published npm package,
@mmissey/tree-sitter-hacklang, aliased to the baretree-sitter-hackimport — mirroring the existingtree-sitter-r→@davisvaughan/tree-sitter-ralias pattern. No vendored parser blob; nothing new to build locally.Why a fork of the grammar
slackhq/tree-sitter-hack(MIT, © 2020 Antonio de Jesus Ochoa Solano; archived) ships a workingparser.c/scanner.cbut is built with the legacynanbindings, whichtree-sitter@0.21+rejects at runtime as an "Invalid language object" (0.21 validates anapi_type_tagon the language External thatnandoesn't set). The fork re-binds it withnode-addon-apiso it satisfies 0.21, and ships prebuilt N-API binaries for linux-x64, darwin-arm64, darwin-x64, and win32-x64 (viaprebuildify+node-gyp-build), so consumers need no C toolchain. Falls back to a source build only where no prebuild matches. LICENSE is preserved verbatim.Changes
src/graph/extract.ts— addhackto theLanguageunion, extensions (.hack,.hhi), kind/call-type maps, and grammar registration; Hack-specific heritage (extends_clause/implements_clauseas direct children), callee resolution (selection_expression/scoped_identifier), imports (use_statement/use_clause), andtrait_use_clause→ implements.src/graph/bindings.ts—handleHackfor typed parameters and$x = new Foo()receiver binding, plus HackdefNamehandling.src/graph/resolve.ts— extend theclassTraitsmap to.hack/.hhiso$this->traitMethod()resolves.package.json— depend on@mmissey/tree-sitter-hacklangvia the npm alias (no vendored grammar).test/graph-hack.test.ts— 6 extraction tests (classes/methods/interface/trait/enum/function, call+extends+implements edges, trait use + typed-parameter receiver binding,newconstructor binding,enum class,.hhiindexing).Verification
npm installresolves@mmissey/tree-sitter-hacklang@0.1.1from npm with the prebuilt binary;npm run build(tsc) passes.test/graph-hack.test.ts— 6/6 pass. PHP suite unaffected..hackfiles: 0 throws, receiver types recovered on ~19% of call edges.Open question for maintainers
Happy to adjust the distribution approach — e.g. transfer/co-own the grammar package under a Trail-owned scope, or vendor it — whichever you prefer. Opening as a draft to get direction on that before finalizing.
Supersedes #331 (closed).