feat(drupal): extract service-container wiring and plugin definitions#1077
Open
mikedamoiseau wants to merge 1 commit into
Open
feat(drupal): extract service-container wiring and plugin definitions#1077mikedamoiseau wants to merge 1 commit into
mikedamoiseau wants to merge 1 commit into
Conversation
Fills the two open TODOs in the Drupal framework resolver. Services (*.services.yml): - emit a component node per service id (qualifiedName service:<id>) - references edge service -> its class: FQCN - references edges service -> each @service argument (inline AND block-list forms), so codegraph_explore can trace Drupal's DI container - skip DI directive keys (_defaults/_instanceof); strip trailing comments; argument resolution is scoped to refs originating in *.services.yml so it cannot hijack a routing.yml entity-handler ref sharing a dotted name Plugins (PHP): - emit a component node per plugin id (qualifiedName plugin:<Type>:<id>) - references edge plugin -> the decorated class - handle BOTH Drupal 11 PHP 8 attributes (#[Block(id: 'foo')], #[FieldType...]) and legacy docblock annotations (@block(id = "foo"), @FieldType...) - balanced-paren body scan so an id following a nested @translation(...) is still captured; bounded forward class search so a stray plugin-shaped token does not bind to an unrelated later class Validated on a real Drupal 11 codebase (53 services, 27 plugins): all plugin and in-index service class edges resolve; no node-count explosion. Tests: 28 new cases in __tests__/drupal.test.ts (services.yml extract/resolve, plugin attributes + annotations, and code-review regression cases).
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.
What
Fills the first two open TODOs in the Drupal framework resolver
(
src/resolution/frameworks/drupal.ts): service-container wiring andplugin definitions. Both were explicitly listed as "TODOs for future
iterations" in the resolver's header docblock and are now implemented,
extending the existing composer/
.info.ymldetection,*.routing.ymlroute resolution, and hook detection.
Supports Drupal 8/9/10/11. No new dependencies; hand-rolled line-based parsing
mirroring the existing
extractDrupalRoutes()shape.Nodes & edges now emitted
Drupal has no dedicated
service/pluginNodeKind, so both reuse thegeneric
componentkind (as routes useroute), staying distinguishable byqualifiedNameprefix.1. Service definitions —
*.services.ymlcomponentnode per service id —qualifiedName=…::service:<id>referencesedge: service → itsclass:FQCN (resolved to the class node)referencesedges: service → each@serviceargument (service → service,wiring the DI graph) — handles both the inline
['@a', '@b']form and themulti-line block-list form
_defaults,_instanceof) are skipped; trailing commentsare stripped; argument resolution is scoped to refs originating in a
*.services.ymlfile so it can't hijack arouting.ymlentity-handler refthat happens to share a dotted name.
This makes Drupal's dependency injection — previously invisible — traceable via
codegraph_explore.2. Plugin definitions — PHP
Drupal 11 is attribute-first, but a large body of contrib/legacy code still uses
docblock annotations, so both are parsed:
componentnode per plugin id —qualifiedName=…::plugin:<Type>:<id>referencesedge: plugin → the decorated classideven when it follows a nested@Translation(...)(common in core, e.g.labelbeforeid)or comment) from binding to an unrelated later class
DRUPAL_PLUGIN_TYPES), so unrelatedattributes like PHPUnit's
#[DataProvider]/#[Group]are ignored.Deliberately left out
DRUPAL_PLUGIN_TYPESis the commoncore+contrib set; an unlisted custom plugin type is ignored (silent beats
wrong / false plugins). Easy to extend.
idis captured — other attribute/annotation arguments(
admin_label,label,default_widget, …) are intentionally not extracted.Drupal\My\Service: ~) — a rareSymfony form; documented as a known gap.
Tests
28 new cases in
__tests__/drupal.test.ts, TDD (failing first):services.ymlextract: node per id,qualifiedNameshape, service→classedge, service→service
@argumentedges, ignores the top-levelserviceskey, empty file.
services.ymledge cases (from a thorough code-review pass): multi-lineblock-list arguments,
_defaults/_instanceofskipped, trailing comment onthe id line, no
@tokencapture from a trailing comment.resolve(): bare class FQCN, dotted and dotless service-arg ids,and a regression test that a
routing.ymlentity-handler ref is notmis-resolved to a same-named service.
#[Block], single-line single-quote,#[FieldType], ignores#[DataProvider].@Block,@FieldType,idafter a nested@Translation(...), nested annotation not treated as a plugin, no binding ofa stray token to a far-away class.
Validation
npm testgreen (Drupal suite 53/53; full suite unaffected). Validated againsta real Drupal 11 codebase (~23 custom modules): 53 services, 27 plugins
extracted; all 27 plugin→class edges and all in-index service→class edges
resolve; service→service DI edges resolve for services present in the index
(core-service args correctly stay unresolved in a modules-only index); node
count stable; 0 bogus
_defaults/_instanceofnodes.The TODOs these address are an open maintainer invitation in the resolver
docblock — the header has been updated to reflect what's now implemented and
the remaining
TwigTODO.