ts-reviewer 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/ts-reviewer/SKILL.md
CHANGED
|
@@ -122,7 +122,7 @@ workflow:
|
|
|
122
122
|
12. identify the entry points: `index.ts`, `main.ts`, the `exports` of `package.json`
|
|
123
123
|
13. collect the context files named in `scope:` when the scope mode is scoped
|
|
124
124
|
14. map the module relationships when Architecture is active: circular imports, deep relative imports, barrel-file cycles, feature slices, public entry points
|
|
125
|
-
15. scan `docs/adr/` for architectural decisions before proposing a change, and skip it silently when
|
|
125
|
+
15. scan `docs/adr/`, `doc/adr/`, `adr/`, and `docs/decisions/` for architectural decisions before proposing a change, and skip it silently when none of them exists
|
|
126
126
|
16. report the discovery summary in the shape of `discovery_summary`
|
|
127
127
|
17. run `npx tsc --noEmit 2>&1 | head -200` over the full project, and report only the errors in the scoped files
|
|
128
128
|
18. run the linter: `npx eslint [files] --format json` or `npx biome check [files] --reporter json`
|
|
@@ -278,17 +278,7 @@ report_format:
|
|
|
278
278
|
|
|
279
279
|
## Architecture Opportunities
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
- **Files:** relative/path/a.ts, relative/path/b.ts
|
|
284
|
-
- **Problem:** why this causes friction now
|
|
285
|
-
- **Proposed deepening:** what would change
|
|
286
|
-
- **Interface shape:** rough sketch of new interface
|
|
287
|
-
- **Dependency category:** in-process | local-substitutable | remote-owned | true-external
|
|
288
|
-
- **Test strategy:** how tests improve
|
|
289
|
-
- **Benefits:** locality, leverage, test impact
|
|
290
|
-
- **Trade-offs:** what gets harder
|
|
291
|
-
- **Fixability:** auto | needs-confirm | report-only
|
|
281
|
+
<1 entry per candidate, in the shape the `report_format` block of references/architecture.md gives>
|
|
292
282
|
|
|
293
283
|
---
|
|
294
284
|
````
|
|
@@ -5,6 +5,8 @@ purpose:
|
|
|
5
5
|
scope:
|
|
6
6
|
- circular imports and deep relative imports are also flagged by the Code Quality domain in every scan mode, and this file adds the refactoring guidance behind them
|
|
7
7
|
- a wire type reaching a domain module is also a `references/boundary-validation.md` check
|
|
8
|
+
- state modelling, a discriminated union, and a branded type belong to `references/type-safety.md`, and this file names only the module that owns the state
|
|
9
|
+
- the module-scope singleton and the import-time side effect belong to `references/code-quality.md`, and the composition-root check here names where an adapter is built
|
|
8
10
|
|
|
9
11
|
glossary:
|
|
10
12
|
- use these terms in every architecture finding, and do not substitute "component", "service", "API", or "boundary"
|
|
@@ -17,6 +19,14 @@ glossary:
|
|
|
17
19
|
- `leverage` — what a caller gets from depth: more capability per unit of interface it has to learn
|
|
18
20
|
- locality — what a maintainer gets from depth: change, bugs, and knowledge concentrated in 1 place
|
|
19
21
|
|
|
22
|
+
confidence_scale:
|
|
23
|
+
|
|
24
|
+
| Confidence | Criteria |
|
|
25
|
+
|---|---|
|
|
26
|
+
| strong | the pain repeats, the owning module is named, and the fix path is safe |
|
|
27
|
+
| worth-exploring | the problem is confirmed, and the interface or the migration needs its own design |
|
|
28
|
+
| speculative | a signal with no call, history, or test evidence behind it |
|
|
29
|
+
|
|
20
30
|
read_first:
|
|
21
31
|
- depth is a property of the interface and not of the implementation: a deep module can be internally complex, and what counts is how small its interface is against what it hides
|
|
22
32
|
- the deletion test: imagine deleting the module, and if the complexity vanishes it was a pass-through, while if it reappears across the callers it was earning its keep
|
|
@@ -24,25 +34,41 @@ read_first:
|
|
|
24
34
|
- depth is missing as often as it is overdone, so flag a missing abstraction where it already hurts
|
|
25
35
|
- dependency direction matters more than layer count: the domain owns the logic, and transport and storage are injected or isolated at the edge
|
|
26
36
|
- 1 adapter is a hypothetical seam and 2 adapters are a real seam: do not introduce a port until at least 2 adapters are justified, production and test at the minimum
|
|
37
|
+
- an architecture finding rests on evidence: named files and symbols, an import or call direction, a repeated change path in `git log`, a duplicated rule, or a test no correct seam can reach
|
|
38
|
+
- state the observation apart from the inference drawn from it, and mark a candidate with no evidence behind it as speculative rather than reporting it as a defect
|
|
39
|
+
- a defect no test can reach through a correct seam is an architecture finding, and not a reason to write a test past the interface
|
|
40
|
+
- before proposing a module, a port, or a container, check in order: drop the need, an existing module in the repository, the standard library, a platform feature, an installed dependency
|
|
41
|
+
- design a hard-to-reverse proposal twice: compare 2 different interfaces on caller knowledge, seam placement, and migration cost, then recommend 1
|
|
42
|
+
- a cycle is unclear ownership and not a bad graph: move the type or the rule to its owner, and `import type` or a lazy import hides the direction rather than fixing it
|
|
43
|
+
- a path alias shortens an import path and is not an architecture boundary: ownership and a controlled export list are
|
|
44
|
+
- pick the simplest form a deepened module can take: a pure function for a transformation, a reducer for events over 1 state, a state machine when a command is valid only in some states, a class only when it owns long-lived state
|
|
27
45
|
|
|
28
46
|
workflow:
|
|
29
|
-
1.
|
|
30
|
-
2.
|
|
31
|
-
3. treat
|
|
32
|
-
4.
|
|
33
|
-
5.
|
|
34
|
-
6.
|
|
47
|
+
1. trace 1 typical scenario end to end before naming a finding: entry point, orchestration, domain rule, storage or external call, response
|
|
48
|
+
2. grep for feature-module imports inside the `shared`, `common`, `core`, and `utils` directories, which is the inverted direction
|
|
49
|
+
3. list the importers of each module, and treat a module whose every export has exactly 1 importer as a pass-through candidate for the deletion test
|
|
50
|
+
4. treat an interface or type re-exported unchanged through 3+ files as a pass-through chain
|
|
51
|
+
5. check whether the exports of a utility file imported by most modules share 1 domain concept
|
|
52
|
+
6. read `git log --name-only` and use it twice: a feature whose commits consistently touch 4+ directories is scattered logic, and the directories changing most often are where to start
|
|
53
|
+
7. name the module owning the rule and the module owning the state for each candidate, and mark the candidate speculative when neither is identifiable
|
|
54
|
+
8. run these checks rather than guessing from file names
|
|
35
55
|
|
|
36
56
|
checks:
|
|
37
57
|
- shallow modules — understanding 1 concept requires bouncing across many tiny modules: Medium
|
|
38
58
|
- shallow modules — a module interface nearly as complex as its implementation: Medium
|
|
39
59
|
- shallow modules — a pass-through wrapper, manager, helper, or service that hides no complexity: Medium, apply the deletion test
|
|
40
60
|
- shallow modules — pure functions extracted for testability alone while the real bugs sit in the orchestration: Medium, the extraction bought no locality
|
|
61
|
+
- shallow modules — a DTO type, a domain type, and a mapper between them, where this repository owns both types and their shapes and meanings are identical: Low, the mapper is a pass-through
|
|
62
|
+
- shallow modules — note: a mapper for a type an external contract owns is not a pass-through, whatever the shapes match, and the dependency direction check below owns that case
|
|
41
63
|
- coupling and seams — coupling leaking across a module interface, where callers have to know implementation details: High
|
|
64
|
+
- coupling and seams — retry, ordering, or compensation decided inside a pure domain computation instead of the orchestrator owning the side effects: Medium
|
|
42
65
|
- coupling and seams — tests that reach into module internals, or that mock many neighbours to test 1 thing: High
|
|
43
66
|
- coupling and seams — a public API exporting implementation details, config, ordering constraints, or internal error modes: Medium, a caller should not need them
|
|
44
67
|
- import and module structure — a barrel-file cycle or a circular import chain that reordering cannot resolve: High
|
|
45
68
|
- import and module structure — a deep relative import, `../../../`, marking a module not co-located with what it depends on: Low, suggest a path alias or co-location
|
|
69
|
+
- import and module structure — an import reaching into the internal files of another package instead of its declared entry point: Medium, import from the path `package.json#exports` names
|
|
70
|
+
- import and module structure — a barrel re-exporting a whole tree with `export *`, so the module owning a symbol is not identifiable at the import: Low, name the exports explicitly
|
|
71
|
+
- import and module structure — note: a barrel that also closes a cycle is the barrel-file cycle check above, at High, and it is reported once and not twice
|
|
46
72
|
- locality — a shared utility module mixing unrelated domain concepts: Medium
|
|
47
73
|
- locality — feature logic split by technical layer, a controller, service, and repo per feature, so that 1 feature change touches 4+ files: Medium
|
|
48
74
|
- under-engineering — 1 business rule, the same constants and branching, implemented in 2+ modules: Medium, deepen 1 module to own the rule
|
|
@@ -51,6 +77,18 @@ checks:
|
|
|
51
77
|
- dependency direction — a domain or computation module importing IO directly, `node:fs`, `node:http`, a DB client, or `fetch`, where the classification puts that IO behind a seam: Medium
|
|
52
78
|
- dependency direction — a shared or leaf module, `utils/`, `types/`, or `core/`, importing from a feature module: High, the inverted direction is how import cycles start
|
|
53
79
|
- dependency direction — a wire or DTO type from an external API imported deep into a domain module instead of mapped at the seam that owns the external contract: Medium
|
|
80
|
+
- state ownership — 2+ modules mutating 1 entity, cache, or record with no single owning module: High, the write paths cannot be tested or reasoned about apart
|
|
81
|
+
- state ownership — fix: a shared mutable entity, by naming 1 owning module and turning each write into a named command on it
|
|
82
|
+
- composition root — an infrastructure adapter, an HTTP client, a DB client, or a config read, constructed inside a domain module instead of passed in from the entry point: Medium
|
|
83
|
+
- composition root — a service locator or a DI container wiring 1 dependency graph: Low, pass the value or the function the module needs
|
|
84
|
+
- distributed side effects — a multi-step write path with no idempotency key, no ordering rule, and no compensation, where a retry leaves the effects partly applied: High
|
|
85
|
+
- distributed side effects — note: flag it from a named failure scenario, a retry, a timeout, or a crash between 2 steps, and not from the shape of the code
|
|
86
|
+
|
|
87
|
+
non_findings:
|
|
88
|
+
- a module with exactly 1 importer that hides an ordering, an invariant, or a decision: 1 importer starts the deletion test and is not a finding by itself
|
|
89
|
+
- a layer count: the direction of the dependencies is the finding, and a layer holding a real rule is not
|
|
90
|
+
- a port with 1 production adapter whose test double checks the same contract: the double is the second adapter
|
|
91
|
+
- formatting, import ordering, and file naming: `references/code-quality.md` owns them, and they are not architecture findings
|
|
54
92
|
|
|
55
93
|
forbidden_behaviors:
|
|
56
94
|
- do not invent a domain term: use a function, type, file, or package name that already exists, and prefer one used in adjacent code
|
|
@@ -59,6 +97,12 @@ forbidden_behaviors:
|
|
|
59
97
|
- do not expose an internal seam through the interface because a test wants it
|
|
60
98
|
- do not accept a test that has to change whenever the implementation changes: it is testing past the interface
|
|
61
99
|
- do not touch code for a `needs-confirm` change before showing a diff or a migration plan and getting an explicit go-ahead
|
|
100
|
+
- do not recommend microservices, event sourcing, CQRS, hexagonal architecture, or DDD tactical patterns without a named defect, change scenario, or failure the current shape caused
|
|
101
|
+
- do not propose a rewrite when a staged migration reaches the same shape
|
|
102
|
+
- do not leave a new structure standing beside the old one: every proposal names the step deleting what it replaces
|
|
103
|
+
- do not propose a change contradicting a decision under `docs/adr/` silently: name the ADR and the conflict, and leave the decision to the operator
|
|
104
|
+
- do not report architecture candidates without naming 1 top recommendation and the reason it goes first
|
|
105
|
+
- do not add an import-linting dependency for 1 rule: use `package.json#exports`, the linter the project already runs, or the workspace layout
|
|
62
106
|
|
|
63
107
|
dependency_classification:
|
|
64
108
|
|
|
@@ -90,13 +134,17 @@ report_format:
|
|
|
90
134
|
```md
|
|
91
135
|
### TITLE — Severity
|
|
92
136
|
|
|
137
|
+
- **Confidence:** strong | worth-exploring | speculative
|
|
93
138
|
- **Files:** relative/path/a.ts, relative/path/b.ts
|
|
94
139
|
- **Problem:** why this causes friction now (not just a pattern name)
|
|
140
|
+
- **Evidence:** the imports, callers, `git log` path, or test the finding rests on
|
|
95
141
|
- **Proposed deepening:** plain-English description of what would change
|
|
96
142
|
- **Interface shape:** rough sketch of the new interface (types, methods, key invariants)
|
|
97
143
|
- **Dependency category:** in-process | local-substitutable | remote-owned | true-external
|
|
98
144
|
- **Test strategy:** how tests would improve (what tests survive, what gets deleted, what's new)
|
|
145
|
+
- **Migration:** prefactor | vertical slices | expand-contract, and the step deleting the replaced code
|
|
99
146
|
- **Benefits:** locality gained, leverage gained, test impact
|
|
100
147
|
- **Trade-offs:** what gets harder, what is genuinely uncertain
|
|
101
148
|
- **Fixability:** auto | needs-confirm | report-only
|
|
149
|
+
- **Top recommendation:** on exactly 1 entry in the report, the reason this candidate goes first
|
|
102
150
|
```
|