overengineeringstudio / overengineeringstudio/effect-utils
oxlint: expose module graph / resolution to JS plugins (or add transitive reachability rule) for whole-program import-graph lint
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 82
- Forks
- 2
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 121
Description
Summary
oxlint maintains a real project-wide module/import graph internally (it powers import/no-cycle), but that graph is not exposed to JS plugins, and there is no built-in rule for transitive reachability-to-a-target. Together these block an entire class of whole-program import-graph lint rules from being written as oxlint JS plugins — e.g. architectural layering (forbid layer A from transitively importing layer B), dependency-boundary / zone enforcement that is transitive rather than direct-only, "no module in group X may transitively reach module/package Y, with the importer chain reported," and rules that need non-standard module resolution.
This issue tracks the capability gap so we can adopt oxlint for these checks once upstream unblocks it. It is a watch-item, not something we can build today.
The gap — missing capabilities
All observations below were empirically verified on oxlint 1.39.0 (re-verify against current HEAD before acting — oxlint has moved on since).
- The multi-file module graph is not exposed to JS plugin
context— it is built-in-rules-only. In a single oxlint run,import/no-cycle(which proved the graph is live — it traversed cross-file and emitted a cycle chain) ran alongside acontext-dumping plugin, and the plugincontextgained zero graph / module / resolved-import keys. The observedcontextsurface is strictly the ESLint-v9 per-file model (sourceCode,settings, per-file tokens/scope); import nodes carry only the raw unresolved specifier (hasResolvedPath === false). - No custom module-resolver injection for plugins. There is no resolver hook in the plugin /
contextAPI; a plugin sees raw specifiers and would have to re-implement resolution itself. This matters for any non-standard / custom specifier scheme. - No reachability-to-target rule in the catalog. The full
import/*rule set has exactly one graph-consuming rule,no-cycle(fixed cycle policy). There is nono-restricted-paths, nono-unresolved, and no transitive reachability / layering rule. - No type-awareness seam for plugins.
parserServicesis empty, so the type-only vs value import-edge distinction is not available to a plugin.
What would unblock adoption
Either of these upstream oxc capabilities would let whole-program import-graph checks run as oxlint rules:
- (a) A NAPI bridge exposing the resolved module graph / per-file import records (and ideally a customizable resolver) to JS plugin rule
context; or - (b) A built-in, configurable transitive reachability-to-target rule that emits the importer chain.
Upstream tracking
- oxc-project/oxc#19918 — Oxlint JS Plugins Milestone 3: the umbrella milestone for JS plugin work. Neither (a) nor (b) is itemized there as of this writing — there is no dedicated upstream request for exposing the module graph / a resolver to plugins.
- oxc-project/oxc#13789 —
no-restricted-pathsrule suggestion: the closest existing built-in-rule request, but insufficient for (b) —eslint-plugin-import'sno-restricted-pathsis direct-import / zone enforcement, not transitive reachability, and does not emit an importer chain. - oxc-project/oxc#1117 — eslint-plugin-import umbrella: tracks the broader
import/*rule set.
Why we care / adoption trigger
oxlint is already in our lint pipeline. Once either (a) or (b) ships, we would move whole-program import-graph enforcement (architectural layering / dependency-boundary rules) onto oxlint instead of running a separate graph engine. Until then, these checks require an external graph tool. Adopt when one of (a)/(b) lands.
Posted on behalf of @schickling
| field | value |
|---|---|
agent_name |
🪴 cl1-cedar |
agent_session_id |
09847524-673f-4bf4-b1e1-f7d521728bae |
agent_tool |
Claude Code |
agent_tool_version |
2.1.183 |
agent_runtime |
Claude Code 2.1.183 |
agent_model |
opus |
runtime_profile |
/nix/store/8wff2zwb0xvh9i03pky6aas7b4w3a238-coding-agent-runtime-profile/share/coding-agents/profile.json |
skills_manifest |
/nix/store/s25jsgnyfkbkl3flwgajp04nd9ssbx56-agent-skills-corpus/share/agent-skills/manifest.json |
worktree |
effect-utils/schickling-assistant/2026-07-04-genie-bootstrap-research |
machine |
dev3 |
tooling_profile |
dotfiles@1f12ec2 |
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository file, test, or entry point is named because this is a watch-item for upstream oxlint capabilities. Re-verify the documented behavior against current oxlint and review the linked upstream issues first. The work is unblocked when module-graph or resolver access reaches JS plugins, or a transitive reachability rule reports importer chains.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- eslint, javascript, typescript
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100