Skip to content

Commit bcb5531

Browse files
committed
docs: add spec for #201 circular dep fix in controller.ts
#201
1 parent f8a4df0 commit bcb5531

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
issue: "#201"
3+
date: 2026-05-17
4+
slug: fix-201-circular-dep-controller
5+
plan: docs/plans/2026-05-17-fix-201-circular-dep-controller.md
6+
---
7+
8+
# Spec: Fix circular dependency in `src/util/controller.ts` (R5)
9+
10+
## Goal
11+
12+
Break the direct circular import loop between `src/util/controller.ts` and `src/index.ts` by replacing the barrel import with explicit relative imports.
13+
14+
## Why now
15+
16+
`controller.ts` is the service locator used by every command and provider. It imports from `src/index.ts` (the root barrel), but `src/index.ts` itself re-exports `src/util/` — which contains `controller.ts`. This creates a direct cycle:
17+
18+
```
19+
src/index.ts → src/util/index.ts → controller.ts → src/index.ts
20+
```
21+
22+
Node.js resolves circular imports by returning the partially-initialized module, which can cause `undefined` values on first access (initialization order sensitive). Beyond runtime risk, the cycle blocks tree-shaking, degrades IDE navigation, and makes unit-testing `Ctrl` in isolation impossible without loading the full barrel. This fix aligns with PLAN.md Phase 2.3 ("Replace `import * as J from '..'` Pattern").
23+
24+
## In scope
25+
26+
- `src/util/controller.ts`: replace `import * as J from '../.'` with 8 direct relative imports; update all usages of `J.*` references in that file.
27+
28+
## Out of scope
29+
30+
- `src/actions/parser.ts`, `writer.ts`, `reader.ts`, `inject.ts` — these also use the barrel import; they are separate Phase 2.3 work items.
31+
- No changes to `src/ext/`, `src/model/`, `src/provider/`, or test files.
32+
- No behavior changes — this is a pure refactor of import paths.
33+
34+
## Acceptance criteria
35+
36+
1. `controller.ts` contains no `import * as J from` line.
37+
2. `npm run compile` passes with no errors.
38+
3. `npm test` passes with no regressions (all existing tests green).
39+
4. `npm run lint` passes with no new warnings.
40+
5. No new `import * as` barrel usage introduced.
41+
42+
## Entities / contracts
43+
44+
Direct imports that replace `import * as J from '../.'`:
45+
46+
| Old reference | New import |
47+
|---|---|
48+
| `J.Extension.Configuration` | `import { Configuration } from '../ext/conf'` |
49+
| `J.Extension.Dialogues` | `import { Dialogues } from '../ext/dialogues'` |
50+
| `J.Actions.Parser` | `import { Parser } from '../actions/parser'` |
51+
| `J.Actions.Writer` | `import { Writer } from '../actions/writer'` |
52+
| `J.Actions.Reader` | `import { Reader } from '../actions/reader'` |
53+
| `J.Actions.Inject` | `import { Inject } from '../actions/inject'` |
54+
| `J.Util.Logger` | `import { Logger } from './logger'` |
55+
| `J.Util.isNullOrUndefined` | `import { isNullOrUndefined } from './util'` |
56+
57+
The `controller.ts` field and parameter types use these classes/interfaces directly; the only change is how they are referenced (qualified `J.*` → bare name).
58+
59+
## Constraints
60+
61+
- Must not change public API of `Ctrl` (no getter/setter signature changes).
62+
- Must not introduce new barrel imports (`import * as X from '...'`) in the file.
63+
- ESLint flat config requires `camelCase`/`PascalCase` import names — all direct imports satisfy this.
64+
65+
## Open questions
66+
67+
None.
68+
69+
## Related issues
70+
71+
- PLAN.md Phase 2.3: broader named-imports refactor across all action modules (separate work).

0 commit comments

Comments
 (0)