debtlens 0.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/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +244 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +153 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +10 -0
- package/dist/cli/init.js +18 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/parseList.d.ts +2 -0
- package/dist/cli/parseList.js +29 -0
- package/dist/cli/parseList.js.map +1 -0
- package/dist/config/defaults.d.ts +2 -0
- package/dist/config/defaults.js +40 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loadConfig.d.ts +2 -0
- package/dist/config/loadConfig.js +23 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/config/mergeConfig.d.ts +2 -0
- package/dist/config/mergeConfig.js +26 -0
- package/dist/config/mergeConfig.js.map +1 -0
- package/dist/config/schema.d.ts +7 -0
- package/dist/config/schema.js +63 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/template.d.ts +10 -0
- package/dist/config/template.js +32 -0
- package/dist/config/template.js.map +1 -0
- package/dist/core/baseline.d.ts +23 -0
- package/dist/core/baseline.js +118 -0
- package/dist/core/baseline.js.map +1 -0
- package/dist/core/scan.d.ts +2 -0
- package/dist/core/scan.js +129 -0
- package/dist/core/scan.js.map +1 -0
- package/dist/core/severity.d.ts +7 -0
- package/dist/core/severity.js +26 -0
- package/dist/core/severity.js.map +1 -0
- package/dist/core/types.d.ts +96 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/detectors/deadAbstraction.d.ts +2 -0
- package/dist/detectors/deadAbstraction.js +115 -0
- package/dist/detectors/deadAbstraction.js.map +1 -0
- package/dist/detectors/duplicateLogic.d.ts +2 -0
- package/dist/detectors/duplicateLogic.js +81 -0
- package/dist/detectors/duplicateLogic.js.map +1 -0
- package/dist/detectors/effectComplexity.d.ts +2 -0
- package/dist/detectors/effectComplexity.js +64 -0
- package/dist/detectors/effectComplexity.js.map +1 -0
- package/dist/detectors/index.d.ts +3 -0
- package/dist/detectors/index.js +20 -0
- package/dist/detectors/index.js.map +1 -0
- package/dist/detectors/largeComponent.d.ts +2 -0
- package/dist/detectors/largeComponent.js +46 -0
- package/dist/detectors/largeComponent.js.map +1 -0
- package/dist/detectors/namingDrift.d.ts +10 -0
- package/dist/detectors/namingDrift.js +82 -0
- package/dist/detectors/namingDrift.js.map +1 -0
- package/dist/detectors/propDrilling.d.ts +2 -0
- package/dist/detectors/propDrilling.js +97 -0
- package/dist/detectors/propDrilling.js.map +1 -0
- package/dist/detectors/stateSprawl.d.ts +2 -0
- package/dist/detectors/stateSprawl.js +47 -0
- package/dist/detectors/stateSprawl.js.map +1 -0
- package/dist/detectors/todoComment.d.ts +2 -0
- package/dist/detectors/todoComment.js +45 -0
- package/dist/detectors/todoComment.js.map +1 -0
- package/dist/reporters/index.d.ts +4 -0
- package/dist/reporters/index.js +14 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/reporters/jsonReporter.d.ts +2 -0
- package/dist/reporters/jsonReporter.js +4 -0
- package/dist/reporters/jsonReporter.js.map +1 -0
- package/dist/reporters/markdownReporter.d.ts +2 -0
- package/dist/reporters/markdownReporter.js +52 -0
- package/dist/reporters/markdownReporter.js.map +1 -0
- package/dist/reporters/sarifReporter.d.ts +7 -0
- package/dist/reporters/sarifReporter.js +77 -0
- package/dist/reporters/sarifReporter.js.map +1 -0
- package/dist/reporters/terminalReporter.d.ts +4 -0
- package/dist/reporters/terminalReporter.js +39 -0
- package/dist/reporters/terminalReporter.js.map +1 -0
- package/dist/utils/ast.d.ts +23 -0
- package/dist/utils/ast.js +132 -0
- package/dist/utils/ast.js.map +1 -0
- package/dist/utils/color.d.ts +8 -0
- package/dist/utils/color.js +27 -0
- package/dist/utils/color.js.map +1 -0
- package/dist/utils/createIssue.d.ts +13 -0
- package/dist/utils/createIssue.js +28 -0
- package/dist/utils/createIssue.js.map +1 -0
- package/dist/utils/git.d.ts +15 -0
- package/dist/utils/git.js +68 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/hostComponents.d.ts +12 -0
- package/dist/utils/hostComponents.js +57 -0
- package/dist/utils/hostComponents.js.map +1 -0
- package/dist/utils/identifiers.d.ts +3 -0
- package/dist/utils/identifiers.js +20 -0
- package/dist/utils/identifiers.js.map +1 -0
- package/dist/utils/lines.d.ts +8 -0
- package/dist/utils/lines.js +19 -0
- package/dist/utils/lines.js.map +1 -0
- package/dist/utils/similarity.d.ts +8 -0
- package/dist/utils/similarity.js +63 -0
- package/dist/utils/similarity.js.map +1 -0
- package/docs/architecture.md +68 -0
- package/docs/example-report.md +141 -0
- package/docs/good-first-issues.md +63 -0
- package/docs/rules.md +139 -0
- package/docs/showcase-expensify-app.md +119 -0
- package/package.json +60 -0
- package/schema/debtlens.config.schema.json +116 -0
package/docs/rules.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# DebtLens Rules
|
|
2
|
+
|
|
3
|
+
DebtLens rules are heuristics. They should produce review prompts, not absolute judgments. Every issue includes confidence, evidence, and a suggested maintainer action.
|
|
4
|
+
|
|
5
|
+
## `large-component`
|
|
6
|
+
|
|
7
|
+
Flags React-style PascalCase functions that exceed line, hook, or branch thresholds.
|
|
8
|
+
|
|
9
|
+
Default thresholds:
|
|
10
|
+
|
|
11
|
+
- `large-component.maxLines`: 250
|
|
12
|
+
- `large-component.maxBranches`: 16
|
|
13
|
+
- `large-component.maxHooks`: 10
|
|
14
|
+
|
|
15
|
+
Why it matters: large components often combine rendering, data loading, state coordination, and business rules. AI-assisted edits can make this worse because adding code is easier than preserving boundaries.
|
|
16
|
+
|
|
17
|
+
Good fixes:
|
|
18
|
+
|
|
19
|
+
- extract rendering subcomponents
|
|
20
|
+
- move derived state to `useMemo`
|
|
21
|
+
- move imperative workflows to named hooks
|
|
22
|
+
- split independent features behind composition boundaries
|
|
23
|
+
|
|
24
|
+
## `state-sprawl`
|
|
25
|
+
|
|
26
|
+
Flags components/hooks with many calls to local stateful hooks such as `useState`, `useReducer`, and `useRef`.
|
|
27
|
+
|
|
28
|
+
Default threshold:
|
|
29
|
+
|
|
30
|
+
- `state-sprawl.maxStatefulHooks`: 6
|
|
31
|
+
|
|
32
|
+
Why it matters: many independent state variables usually mean a component is coordinating several workflows. This raises the cost of every future change.
|
|
33
|
+
|
|
34
|
+
Good fixes:
|
|
35
|
+
|
|
36
|
+
- consolidate related transitions in a reducer
|
|
37
|
+
- extract a domain hook
|
|
38
|
+
- move server/cache state into the data layer
|
|
39
|
+
- delete unused state before adding new state
|
|
40
|
+
|
|
41
|
+
## `effect-complexity`
|
|
42
|
+
|
|
43
|
+
Flags long, branchy, or overloaded `useEffect` calls.
|
|
44
|
+
|
|
45
|
+
Default thresholds:
|
|
46
|
+
|
|
47
|
+
- `effect-complexity.maxLines`: 30
|
|
48
|
+
- `effect-complexity.maxDependencies`: 8
|
|
49
|
+
|
|
50
|
+
Why it matters: effects are common hiding places for race conditions, duplicated fetching, stale dependencies, and side effects that should be modeled explicitly.
|
|
51
|
+
|
|
52
|
+
Good fixes:
|
|
53
|
+
|
|
54
|
+
- split unrelated effects
|
|
55
|
+
- replace derived-state effects with memoized values
|
|
56
|
+
- move async workflows into named functions
|
|
57
|
+
- use framework data loading where appropriate
|
|
58
|
+
|
|
59
|
+
## `duplicate-logic`
|
|
60
|
+
|
|
61
|
+
Finds structurally similar functions/components after comments, identifiers, strings, and numeric literals are normalized.
|
|
62
|
+
|
|
63
|
+
Default thresholds:
|
|
64
|
+
|
|
65
|
+
- `duplicate-logic.minSimilarity`: 0.86
|
|
66
|
+
- `duplicate-logic.minLines`: 8
|
|
67
|
+
- `duplicate-logic.maxSnippets`: 450
|
|
68
|
+
|
|
69
|
+
Why it matters: AI assistants can produce plausible variants of the same logic in multiple files. Duplicate implementations make bug fixes and behavior changes harder.
|
|
70
|
+
|
|
71
|
+
Good fixes:
|
|
72
|
+
|
|
73
|
+
- compare the two implementations manually
|
|
74
|
+
- extract shared behavior if the variation is stable
|
|
75
|
+
- delete the weaker duplicate if it was accidental
|
|
76
|
+
- keep duplication only when coupling would be worse than repetition
|
|
77
|
+
|
|
78
|
+
## `dead-abstraction`
|
|
79
|
+
|
|
80
|
+
Flags short wrappers that delegate to one call, return one value, or render one JSX element without meaningful behavior.
|
|
81
|
+
|
|
82
|
+
Default threshold:
|
|
83
|
+
|
|
84
|
+
- `dead-abstraction.maxWrapperLines`: 8
|
|
85
|
+
|
|
86
|
+
Why it matters: unnecessary wrappers create names and files that future maintainers must understand, even when they add no durable boundary.
|
|
87
|
+
|
|
88
|
+
Good fixes:
|
|
89
|
+
|
|
90
|
+
- inline the wrapper
|
|
91
|
+
- keep it only if it is a stable domain boundary
|
|
92
|
+
- add the missing behavior that justifies the abstraction
|
|
93
|
+
|
|
94
|
+
## `prop-drilling`
|
|
95
|
+
|
|
96
|
+
Flags components that forward many props to child components.
|
|
97
|
+
|
|
98
|
+
Default threshold:
|
|
99
|
+
|
|
100
|
+
- `prop-drilling.maxForwardedProps`: 4
|
|
101
|
+
|
|
102
|
+
Why it matters: prop drilling can make components into pass-through plumbing instead of meaningful boundaries.
|
|
103
|
+
|
|
104
|
+
Good fixes:
|
|
105
|
+
|
|
106
|
+
- colocate data ownership closer to consumers
|
|
107
|
+
- use composition slots
|
|
108
|
+
- extract a stable context for cross-cutting values
|
|
109
|
+
- reduce prop surface area
|
|
110
|
+
|
|
111
|
+
## `todo-comment`
|
|
112
|
+
|
|
113
|
+
Flags debt markers in comments, including TODO, FIXME, HACK, temporary, placeholder, and assistant-generation markers.
|
|
114
|
+
|
|
115
|
+
Why it matters: a comment can be a legitimate marker, but untracked markers often become permanent.
|
|
116
|
+
|
|
117
|
+
Good fixes:
|
|
118
|
+
|
|
119
|
+
- create a tracked issue
|
|
120
|
+
- add a removal condition
|
|
121
|
+
- fix the debt before more code depends on it
|
|
122
|
+
- delete stale comments that no longer describe reality
|
|
123
|
+
|
|
124
|
+
## `naming-drift`
|
|
125
|
+
|
|
126
|
+
Flags files where related domain concepts are represented by many competing names.
|
|
127
|
+
|
|
128
|
+
Default threshold:
|
|
129
|
+
|
|
130
|
+
- `naming-drift.minVariants`: 4
|
|
131
|
+
|
|
132
|
+
Why it matters: inconsistent names create translation work for every maintainer and can hide duplicate domain models.
|
|
133
|
+
|
|
134
|
+
Good fixes:
|
|
135
|
+
|
|
136
|
+
- pick one canonical domain term
|
|
137
|
+
- rename adapters at system boundaries
|
|
138
|
+
- document vocabulary in a module README
|
|
139
|
+
- add typed domain models where possible
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Showcase: Maintainability signals in a large production React Native codebase (Expensify/App)
|
|
2
|
+
|
|
3
|
+
This report shows DebtLens running against [Expensify/App](https://github.com/Expensify/App), a large, real-world React Native application. It is a curated sample of the most useful findings, intended to demonstrate the kinds of maintainability signals DebtLens surfaces in a mature production codebase.
|
|
4
|
+
|
|
5
|
+
## Why this repo?
|
|
6
|
+
|
|
7
|
+
- **MIT-licensed and public** — freely available to scan and quote.
|
|
8
|
+
- **Production-scale** — ~6,200 TypeScript/TSX files under `src/` alone.
|
|
9
|
+
- **Actively maintained** — a high-traffic repo with continuous contributions.
|
|
10
|
+
- **Real-world React Native** — exactly the kind of app DebtLens is built for (React Native, TypeScript, hooks-heavy UI).
|
|
11
|
+
|
|
12
|
+
It is a great showcase precisely *because* it is large, active, and well-engineered: maintainability signals in a codebase this size are about managing scale and review burden, not about code quality in any pejorative sense.
|
|
13
|
+
|
|
14
|
+
## Important disclaimer
|
|
15
|
+
|
|
16
|
+
**DebtLens findings are heuristic signals, not proof of defects.** Every item below is a prompt for human review — "this might be worth a look" — not a verdict. Large components, forwarded props, and duplicated structure are often deliberate, justified, and perfectly correct in context. DebtLens does not execute code, does not understand intent, and makes **no claim about how any code was written or generated**. Treat these as conversation starters for maintainers, weighted by the confidence score shown.
|
|
17
|
+
|
|
18
|
+
## How this report was generated
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Cloned Expensify/App and scanned a scoped subset (the component library),
|
|
22
|
+
# not the whole repository.
|
|
23
|
+
debtlens scan src/components --min-severity info --format markdown
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Scope:** `src/components/` only (1,681 files scanned) — a representative slice, not the full repo.
|
|
27
|
+
- **Repo revision:** `c59a4ce` (2026-06-01).
|
|
28
|
+
- **DebtLens:** v0.1, 8 rules, ~3.8s to scan the subset.
|
|
29
|
+
|
|
30
|
+
### Signal volume in the scanned subset
|
|
31
|
+
|
|
32
|
+
| Rule | Count |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| prop-drilling | 361 |
|
|
35
|
+
| large-component | 184 |
|
|
36
|
+
| todo-comment | 144 |
|
|
37
|
+
| effect-complexity | 60 |
|
|
38
|
+
| dead-abstraction | 58 |
|
|
39
|
+
| state-sprawl | 38 |
|
|
40
|
+
| duplicate-logic | 5 |
|
|
41
|
+
| naming-drift | 1 |
|
|
42
|
+
|
|
43
|
+
In a codebase this size, the raw counts matter less than the *shape* of the signal. The curated findings below are the ones a maintainer is most likely to find worth a look. (For real adoption, DebtLens's `--write-baseline` mode records existing signals so a team only sees newly introduced ones on each PR.)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Curated findings
|
|
48
|
+
|
|
49
|
+
### Near-duplicate structure (consider sharing)
|
|
50
|
+
|
|
51
|
+
These are high-confidence structural matches — pairs of functions/components with the same shape. Sometimes that is intentional parallelism; sometimes it is an opportunity to share one implementation.
|
|
52
|
+
|
|
53
|
+
**`Checkbox.tsx` ≈ `RadioButton.tsx`** — confidence **100%**
|
|
54
|
+
> `Checkbox` is structurally near-identical to `RadioButton` (29 vs 28 lines). Two selection controls that may share more than they currently do.
|
|
55
|
+
|
|
56
|
+
**`AnchorForAttachmentsOnly/index.tsx` ≈ `AnchorForCommentsOnly/index.tsx`** — confidence **100%**
|
|
57
|
+
> Two anchor variants with the same 9-line shape. A candidate for a single parameterized component.
|
|
58
|
+
|
|
59
|
+
**`Icon/ExpensifyIconLoader.ts` ≈ `Icon/IllustrationLoader.ts`** — confidence **100%** (two matched pairs)
|
|
60
|
+
> `loadExpensifyIconsChunk` ≈ `loadIllustrationsChunk` and `loadExpensifyIcon` ≈ `loadIllustration` — parallel lazy-loaders that could potentially share a generic loader.
|
|
61
|
+
|
|
62
|
+
**`SentrySendToggle` ≈ `SentryDebugToggle`** (`SentryDebugToolMenu.tsx`) — confidence **100%**
|
|
63
|
+
> Two 13-line toggles in the same file with identical structure.
|
|
64
|
+
|
|
65
|
+
### Components carrying many responsibilities
|
|
66
|
+
|
|
67
|
+
These are the largest component bodies in the subset by line count, hook usage, and branch points. Large components are common and often justified in feature-rich screens; DebtLens simply flags the extremes as candidates for extraction.
|
|
68
|
+
|
|
69
|
+
| Component | File | Signal |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| `Search` | `Search/index.tsx:274` | ~1,611-line body, 121 hooks, 135 branch points |
|
|
72
|
+
| `MoneyRequestView` | `ReportActionItem/MoneyRequestView.tsx:180` | ~1,191-line body, 46 hooks, 102 branches |
|
|
73
|
+
| `MoneyRequestReportTransactionList` | `MoneyRequestReportView/MoneyRequestReportTransactionList.tsx:170` | ~791-line body, 75 hooks |
|
|
74
|
+
| `TimePicker` | `TimePicker/TimePicker.tsx:118` | ~778-line body, 101 branches |
|
|
75
|
+
|
|
76
|
+
*(Line counts are DebtLens-measured component-body spans; `--threshold large-component.maxLines` is tunable per project.)*
|
|
77
|
+
|
|
78
|
+
### Local state concentrated in one component
|
|
79
|
+
|
|
80
|
+
High counts of stateful hooks can indicate a component coordinating several workflows — sometimes a good candidate for a reducer or an extracted hook.
|
|
81
|
+
|
|
82
|
+
- **`BaseVideoPlayer`** (`VideoPlayer/BaseVideoPlayer.tsx:35`) — 19 stateful hook calls (confidence 82%).
|
|
83
|
+
- **`MoneyRequestReportActionsList`** (`MoneyRequestReportView/MoneyRequestReportActionsList.tsx:87`) — 16 stateful hook calls.
|
|
84
|
+
|
|
85
|
+
### Overloaded effects
|
|
86
|
+
|
|
87
|
+
`useEffect` blocks that are long or carry many dependencies can be harder to reason about and re-run more often than intended.
|
|
88
|
+
|
|
89
|
+
- **`useSearchFocusSync.ts:64`** — a 46-line effect with 14 dependencies and 6 branches (confidence 80%).
|
|
90
|
+
- **`DistanceRequestController.tsx:183`** — a 25-line effect with 14 dependencies.
|
|
91
|
+
|
|
92
|
+
### Wide prop surfaces
|
|
93
|
+
|
|
94
|
+
These components forward many props onward. A wide forwarding surface can be a deliberate, well-typed API for a flexible primitive — or, at the extreme, a sign that data is threading through several layers. Worth a glance either way.
|
|
95
|
+
|
|
96
|
+
- **`MenuItem.tsx:609`** — forwards 63 props across 13 child components (confidence 73%).
|
|
97
|
+
- **`Button/index.tsx:302`** — forwards 43 props across 3 children.
|
|
98
|
+
|
|
99
|
+
> Note: for highly configurable primitives like `MenuItem` and `Button`, a broad prop surface is frequently intentional. This is exactly the kind of signal that benefits from human judgment rather than an automated verdict.
|
|
100
|
+
|
|
101
|
+
### Debt-marker comments
|
|
102
|
+
|
|
103
|
+
DebtLens surfaces `TODO`/`FIXME`/`HACK`/workaround markers that the authors themselves left in the code — useful for tracking and triage. A few honest examples (quoted verbatim):
|
|
104
|
+
|
|
105
|
+
- `ChronosTimerHeaderButton.tsx:61` — *"There is still a possible bug where if you are offline, the button could reflect the wrong state. However, there is really no way to fix this without breaking the offline experience."*
|
|
106
|
+
- `Attachments/AttachmentCarousel/extractAttachments.ts:76` — *"We apply this small hack to add an image extension and ensure AttachmentView renders the image."*
|
|
107
|
+
- `AvatarCropModal/Slider.tsx:70` — *"pointerEventsNone is a workaround to make sure the pan gesture works correctly on mobile safari."*
|
|
108
|
+
|
|
109
|
+
These are normal, responsible engineering breadcrumbs — DebtLens just makes them easy to find and convert into tracked issues.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Takeaways
|
|
114
|
+
|
|
115
|
+
- In a production React Native codebase of this scale, the highest-value signals were **near-duplicate components** (clear, actionable) and a small number of **very large components** concentrating responsibilities.
|
|
116
|
+
- The breadth of `prop-drilling` and `todo-comment` counts reflects the size of the codebase; in practice a team would adopt with `--write-baseline` and review only newly introduced signals on each PR.
|
|
117
|
+
- Every finding here is a **heuristic prompt for review**, not a defect report, and says nothing about how the code was authored.
|
|
118
|
+
|
|
119
|
+
*Generated with [DebtLens](https://github.com/ColumbusLabs/debtlens). Thresholds and rules are configurable; see the README.*
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "debtlens",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Find maintainability debt common in fast-moving AI-assisted TypeScript, React, React Native, Expo, and Next.js codebases.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://github.com/ColumbusLabs/DebtLens#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/ColumbusLabs/DebtLens.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/ColumbusLabs/DebtLens/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"debtlens": "dist/cli/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"schema",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"CHANGELOG.md",
|
|
23
|
+
"docs"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"dev": "tsx src/cli/index.ts scan examples/react --format terminal",
|
|
28
|
+
"scan:example": "tsx src/cli/index.ts scan examples/react --format markdown",
|
|
29
|
+
"test": "node scripts/test.mjs",
|
|
30
|
+
"test:all": "npm run typecheck && npm run typecheck:tests && npm run test",
|
|
31
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
32
|
+
"typecheck:tests": "tsc -p tsconfig.tests.json",
|
|
33
|
+
"schema:generate": "node --import tsx scripts/generate-schema.mjs",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"technical-debt",
|
|
38
|
+
"static-analysis",
|
|
39
|
+
"react",
|
|
40
|
+
"react-native",
|
|
41
|
+
"typescript",
|
|
42
|
+
"ai-code-review",
|
|
43
|
+
"cli",
|
|
44
|
+
"maintainability"
|
|
45
|
+
],
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=20"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"commander": "^15.0.0",
|
|
52
|
+
"fast-glob": "^3.3.3",
|
|
53
|
+
"ts-morph": "^28.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^22.15.0",
|
|
57
|
+
"tsx": "^4.19.0",
|
|
58
|
+
"typescript": "^5.8.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/ColumbusLabs/debtlens/main/schema/debtlens.config.schema.json",
|
|
4
|
+
"title": "DebtLens configuration",
|
|
5
|
+
"description": "Configuration for the DebtLens static-analysis CLI.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string"
|
|
11
|
+
},
|
|
12
|
+
"include": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"description": "Glob patterns to scan."
|
|
18
|
+
},
|
|
19
|
+
"exclude": {
|
|
20
|
+
"type": "array",
|
|
21
|
+
"items": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
24
|
+
"description": "Glob patterns to skip."
|
|
25
|
+
},
|
|
26
|
+
"minSeverity": {
|
|
27
|
+
"enum": [
|
|
28
|
+
"info",
|
|
29
|
+
"low",
|
|
30
|
+
"medium",
|
|
31
|
+
"high"
|
|
32
|
+
],
|
|
33
|
+
"description": "Lowest severity to report."
|
|
34
|
+
},
|
|
35
|
+
"rules": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"uniqueItems": true,
|
|
38
|
+
"items": {
|
|
39
|
+
"enum": [
|
|
40
|
+
"large-component",
|
|
41
|
+
"state-sprawl",
|
|
42
|
+
"effect-complexity",
|
|
43
|
+
"duplicate-logic",
|
|
44
|
+
"dead-abstraction",
|
|
45
|
+
"prop-drilling",
|
|
46
|
+
"todo-comment",
|
|
47
|
+
"naming-drift"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"description": "Rule ids to run. Omit to run all rules."
|
|
51
|
+
},
|
|
52
|
+
"maxFiles": {
|
|
53
|
+
"type": "integer",
|
|
54
|
+
"minimum": 1,
|
|
55
|
+
"description": "Maximum number of files to scan."
|
|
56
|
+
},
|
|
57
|
+
"thresholds": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "Per-rule numeric threshold overrides.",
|
|
60
|
+
"properties": {
|
|
61
|
+
"large-component.maxLines": {
|
|
62
|
+
"type": "number"
|
|
63
|
+
},
|
|
64
|
+
"large-component.maxBranches": {
|
|
65
|
+
"type": "number"
|
|
66
|
+
},
|
|
67
|
+
"large-component.maxHooks": {
|
|
68
|
+
"type": "number"
|
|
69
|
+
},
|
|
70
|
+
"state-sprawl.maxStatefulHooks": {
|
|
71
|
+
"type": "number"
|
|
72
|
+
},
|
|
73
|
+
"effect-complexity.maxLines": {
|
|
74
|
+
"type": "number"
|
|
75
|
+
},
|
|
76
|
+
"effect-complexity.maxDependencies": {
|
|
77
|
+
"type": "number"
|
|
78
|
+
},
|
|
79
|
+
"duplicate-logic.minSimilarity": {
|
|
80
|
+
"type": "number"
|
|
81
|
+
},
|
|
82
|
+
"duplicate-logic.minLines": {
|
|
83
|
+
"type": "number"
|
|
84
|
+
},
|
|
85
|
+
"duplicate-logic.maxSnippets": {
|
|
86
|
+
"type": "number"
|
|
87
|
+
},
|
|
88
|
+
"dead-abstraction.maxWrapperLines": {
|
|
89
|
+
"type": "number"
|
|
90
|
+
},
|
|
91
|
+
"prop-drilling.maxForwardedProps": {
|
|
92
|
+
"type": "number"
|
|
93
|
+
},
|
|
94
|
+
"naming-drift.minVariants": {
|
|
95
|
+
"type": "number"
|
|
96
|
+
},
|
|
97
|
+
"duplicate-logic.minStructuralSimilarity": {
|
|
98
|
+
"type": "number"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"additionalProperties": {
|
|
102
|
+
"type": "number"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"vocabulary": {
|
|
106
|
+
"type": "object",
|
|
107
|
+
"description": "Naming-drift concept groups (concept id -> competing terms).",
|
|
108
|
+
"additionalProperties": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"items": {
|
|
111
|
+
"type": "string"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|