feat(frameworks): add Drupal 8/9/10/11 support#271
Merged
colbymchenry merged 5 commits intoMay 21, 2026
Conversation
Adds Drupal as a supported framework with route extraction from *.routing.yml files and hook detection. Extends language support with yaml and twig (file-level tracking only). Registers Drupal-specific file extensions (.module, .install, .theme, .inc) and excludes core/contrib paths from indexing.
4de45e5 to
6c51025
Compare
nanofatdog
added a commit
to nanofatdog/codegraph_hermes
that referenced
this pull request
May 22, 2026
Upstream changes (colbymchenry/codegraph v0.9.1): - Self-contained distribution (bundle Node + node:sqlite, colbymchenry#282) - Zero-config .gitignore-driven indexing (colbymchenry#283) - Drupal 8/9/10/11 framework support (colbymchenry#271) - Security fix: refuse symlinks for /tmp session marker (colbymchenry#280) - Fix installer: strip stale auto-sync hooks (colbymchenry#278) - Hermes Agent target added upstream (colbymchenry#274) - MCP tools: improved codegraph_explore budget - Better SQLite backend (node:sqlite) Our additions KEPT: ✅ AGENTS.md — Hermes dev guide ✅ skills/codegraph/SKILL.md — Hermes skill ✅ scripts/hermes-setup.sh — one-command setup ✅ README.md — Hermes-optimized ✅ server-instructions.ts — Hermes delegate_task section hermes.ts: merged upstream (platform_toolsets.cli + cleaner YAML) + kept our skill installation + wireProjectSurfaces
andreinknv
added a commit
to andreinknv/codegraph
that referenced
this pull request
May 27, 2026
…ML language + FrameworkResolver.extract() interface extension
Ships full Drupal 8/9/10/11 support to this fork. Three coupled
additions that together unlock the previously-deferred Drupal port:
1. **YAML language** (`src/extraction/languages/yaml.ts`).
tree-sitter-yaml grammar vendored from npm
`@tree-sitter-grammars/tree-sitter-yaml@0.7.1` (ships a pre-
built 189KB ABI-14 compatible wasm — no emcc needed). Minimal
`yamlExtractor` (every type-list empty) so the default tree-
sitter walk runs but emits nothing -- YAML has no functions /
classes / etc. to extract universally. The grammar is loaded
so framework resolvers can walk YAML ASTs directly.
2. **FrameworkResolver.extract() interface extension** -- backward-
compatible additive change in `src/resolution/types.ts`.
Existing resolvers (express, swift/Vapor, etc.) keep their
`extractNodes(): Node[]` hook unchanged. Resolvers that need
to emit cross-file references (Drupal's routing.yml -> handler
class) implement the new `extract(): {nodes, references}`
hook. Orchestrator dispatches to `extract` first when present;
the orchestrator does NOT call both for the same file.
Mirrors the optional-extension precedent set by
`ResolutionContext.getProjectAliases?()` / `getReExports?()`.
3. **Drupal framework resolver** (`src/resolution/frameworks/
drupal.ts`). Adapted from upstream 5b71a89 (PR colbymchenry#271) with
audit corrections applied at port time:
- **Tree-sitter-yaml AST walk** for routing.yml parsing
(upstream used regex on source -- avoided by walking
`block_mapping_pair` children, dodging the YAML anchors /
multi-line-value / comment-collision bug class).
- **Content-hash route node IDs** via `generateNodeId({kind:
'route', name: 'routeName::path', ordinal: 0})` -- upstream
used `route:${filePath}:${lineNum}:${path}`, violating this
fork's G7 stable-node-id contract (line numbers move when
unrelated content shifts).
- **Hook strategy B name-pattern fallback** limited to the
specific module's prefix (upstream scanned every function
in the file, broadening the false-positive surface).
4. **PHP_DEF extends to `.module/.install/.theme/.inc`**. Drupal
ships hook implementations in PHP files with non-standard
extensions. Registering them on PHP_DEF means the tree-sitter
PHP grammar parses them and the Drupal resolver's hook
detection runs on the resulting function nodes.
Drupal feature surface (validated end-to-end via 6 tests):
- **Detection**: composer.json `drupal/*` dep gate.
- **routing.yml extraction**: one `route` node per top-level
mapping pair; `references` from each route to its
`_controller` / `_form` / `_entity_form` / `_entity_list` /
`_entity_view` handler FQCN.
- **Hook detection**: docblock `@Implements hook_X()` (precise)
+ name-pattern `{moduleName}_{hookSuffix}` (best-effort).
- **Resolution**: `_controller: '\Drupal\\…\Foo::bar'` resolves
to method `bar` on class `Foo` (or class fallback with reduced
confidence); `_form: '\Drupal\\…\MyForm'` resolves to class;
`hook_X` resolves to first matching `*_X` function in any
hook file.
Cross-pipeline assumption documented in drupal.ts header: hook refs
use `generateNodeId({filePath, kind: 'function', name, ordinal: 0})`
to match the PHP extractor's first-occurrence function node ID. If
`generateNodeId`'s contract ever changes, the hook edges break
silently -- documented inline so a future audit catches it.
v1 scope (deferred to follow-ups):
- `*.services.yml` service definitions
- Plugin annotations (`@Block`, `@FormElement`, …)
- Twig template scanning
- Virtual `hook_*` nodes when Drupal core isn't indexed
Tests (`__tests__/drupal-extraction.test.ts`, 6 cases):
- YAML language registration
- .yml/.yaml/.routing.yml detection
- Drupal detection: positive (drupal/*) + negative (laravel)
- End-to-end: routing.yml -> controller method edge
- End-to-end: .module file with docblock hook implementation
Gates: check 0/0/0, typecheck clean. Drupal suite 6/6 + ObjC
6/6 + extraction 459/459 + resolution 75/75 unchanged. F#60
staleness-banner tests show known parallel-load flakiness (10/10
in isolation; pre-existing pattern from memory).
Dependencies: zero runtime additions. tree-sitter-yaml's pre-built
wasm vendored at `src/extraction/wasm/yaml.wasm`; transient npm
install at port time produced only the artifact, no package.json
or package-lock.json changes. Updates B7 backlog entry's "deferred"
status to shipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements a Drupal framework resolver, closing #268.
*.routing.ymlfiles and emitsroutenodes linked byreferencesedges to the_controller,_form, or entity-handler class/method. Querying a controller method viacodegraph_callersnow surfaces the URL route that binds it..module,.install,.theme, and.incfiles for hook implementations using two strategies — docblock (@Implements hook_X(), zero false positives) and name-prefix pattern ({moduleName}_{hookSuffix}, fallback). Each implementation emits areferencesedge to the canonicalhook_Xname socodegraph_callers("hook_form_alter")returns every implementation across all modules..module,.install,.theme,.inc(extracted with the existing PHP tree-sitter grammar);*.routing.yml(YAML, route extraction only);*.twig(Twig templates, file-level tracking — no symbol extraction in v1).yamlandtwigadded to the language registry; both appear incodegraph_files.yamlalso allows framework extractors to run on YAML files.web/core/**,web/modules/contrib/**, andweb/themes/contrib/**excluded by default to focus indexing on custom code.drupal/*dependency incomposer.json(requireorrequire-dev).What's deferred to future iterations
*.services.ymlextraction (class → service-id edges)@Block,@FormElement,@Field, etc.hook_*nodes socodegraph_callersworks even when Drupal core is not indexedTest plan
npm testpasses (new__tests__/drupal.test.tscovers detection, route extraction, hook detection, and FQCN resolution)codegraph_callers("hook_form_alter")returns all implementing functionscodegraph_callerson a controller method surfaces its*.routing.ymlroute nodeweb/core/**andweb/modules/contrib/**are excluded from the index🤖 Generated with Claude Code