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.
Files changed (112) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE +21 -0
  3. package/README.md +244 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.js +153 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/cli/init.d.ts +10 -0
  8. package/dist/cli/init.js +18 -0
  9. package/dist/cli/init.js.map +1 -0
  10. package/dist/cli/parseList.d.ts +2 -0
  11. package/dist/cli/parseList.js +29 -0
  12. package/dist/cli/parseList.js.map +1 -0
  13. package/dist/config/defaults.d.ts +2 -0
  14. package/dist/config/defaults.js +40 -0
  15. package/dist/config/defaults.js.map +1 -0
  16. package/dist/config/loadConfig.d.ts +2 -0
  17. package/dist/config/loadConfig.js +23 -0
  18. package/dist/config/loadConfig.js.map +1 -0
  19. package/dist/config/mergeConfig.d.ts +2 -0
  20. package/dist/config/mergeConfig.js +26 -0
  21. package/dist/config/mergeConfig.js.map +1 -0
  22. package/dist/config/schema.d.ts +7 -0
  23. package/dist/config/schema.js +63 -0
  24. package/dist/config/schema.js.map +1 -0
  25. package/dist/config/template.d.ts +10 -0
  26. package/dist/config/template.js +32 -0
  27. package/dist/config/template.js.map +1 -0
  28. package/dist/core/baseline.d.ts +23 -0
  29. package/dist/core/baseline.js +118 -0
  30. package/dist/core/baseline.js.map +1 -0
  31. package/dist/core/scan.d.ts +2 -0
  32. package/dist/core/scan.js +129 -0
  33. package/dist/core/scan.js.map +1 -0
  34. package/dist/core/severity.d.ts +7 -0
  35. package/dist/core/severity.js +26 -0
  36. package/dist/core/severity.js.map +1 -0
  37. package/dist/core/types.d.ts +96 -0
  38. package/dist/core/types.js +2 -0
  39. package/dist/core/types.js.map +1 -0
  40. package/dist/detectors/deadAbstraction.d.ts +2 -0
  41. package/dist/detectors/deadAbstraction.js +115 -0
  42. package/dist/detectors/deadAbstraction.js.map +1 -0
  43. package/dist/detectors/duplicateLogic.d.ts +2 -0
  44. package/dist/detectors/duplicateLogic.js +81 -0
  45. package/dist/detectors/duplicateLogic.js.map +1 -0
  46. package/dist/detectors/effectComplexity.d.ts +2 -0
  47. package/dist/detectors/effectComplexity.js +64 -0
  48. package/dist/detectors/effectComplexity.js.map +1 -0
  49. package/dist/detectors/index.d.ts +3 -0
  50. package/dist/detectors/index.js +20 -0
  51. package/dist/detectors/index.js.map +1 -0
  52. package/dist/detectors/largeComponent.d.ts +2 -0
  53. package/dist/detectors/largeComponent.js +46 -0
  54. package/dist/detectors/largeComponent.js.map +1 -0
  55. package/dist/detectors/namingDrift.d.ts +10 -0
  56. package/dist/detectors/namingDrift.js +82 -0
  57. package/dist/detectors/namingDrift.js.map +1 -0
  58. package/dist/detectors/propDrilling.d.ts +2 -0
  59. package/dist/detectors/propDrilling.js +97 -0
  60. package/dist/detectors/propDrilling.js.map +1 -0
  61. package/dist/detectors/stateSprawl.d.ts +2 -0
  62. package/dist/detectors/stateSprawl.js +47 -0
  63. package/dist/detectors/stateSprawl.js.map +1 -0
  64. package/dist/detectors/todoComment.d.ts +2 -0
  65. package/dist/detectors/todoComment.js +45 -0
  66. package/dist/detectors/todoComment.js.map +1 -0
  67. package/dist/reporters/index.d.ts +4 -0
  68. package/dist/reporters/index.js +14 -0
  69. package/dist/reporters/index.js.map +1 -0
  70. package/dist/reporters/jsonReporter.d.ts +2 -0
  71. package/dist/reporters/jsonReporter.js +4 -0
  72. package/dist/reporters/jsonReporter.js.map +1 -0
  73. package/dist/reporters/markdownReporter.d.ts +2 -0
  74. package/dist/reporters/markdownReporter.js +52 -0
  75. package/dist/reporters/markdownReporter.js.map +1 -0
  76. package/dist/reporters/sarifReporter.d.ts +7 -0
  77. package/dist/reporters/sarifReporter.js +77 -0
  78. package/dist/reporters/sarifReporter.js.map +1 -0
  79. package/dist/reporters/terminalReporter.d.ts +4 -0
  80. package/dist/reporters/terminalReporter.js +39 -0
  81. package/dist/reporters/terminalReporter.js.map +1 -0
  82. package/dist/utils/ast.d.ts +23 -0
  83. package/dist/utils/ast.js +132 -0
  84. package/dist/utils/ast.js.map +1 -0
  85. package/dist/utils/color.d.ts +8 -0
  86. package/dist/utils/color.js +27 -0
  87. package/dist/utils/color.js.map +1 -0
  88. package/dist/utils/createIssue.d.ts +13 -0
  89. package/dist/utils/createIssue.js +28 -0
  90. package/dist/utils/createIssue.js.map +1 -0
  91. package/dist/utils/git.d.ts +15 -0
  92. package/dist/utils/git.js +68 -0
  93. package/dist/utils/git.js.map +1 -0
  94. package/dist/utils/hostComponents.d.ts +12 -0
  95. package/dist/utils/hostComponents.js +57 -0
  96. package/dist/utils/hostComponents.js.map +1 -0
  97. package/dist/utils/identifiers.d.ts +3 -0
  98. package/dist/utils/identifiers.js +20 -0
  99. package/dist/utils/identifiers.js.map +1 -0
  100. package/dist/utils/lines.d.ts +8 -0
  101. package/dist/utils/lines.js +19 -0
  102. package/dist/utils/lines.js.map +1 -0
  103. package/dist/utils/similarity.d.ts +8 -0
  104. package/dist/utils/similarity.js +63 -0
  105. package/dist/utils/similarity.js.map +1 -0
  106. package/docs/architecture.md +68 -0
  107. package/docs/example-report.md +141 -0
  108. package/docs/good-first-issues.md +63 -0
  109. package/docs/rules.md +139 -0
  110. package/docs/showcase-expensify-app.md +119 -0
  111. package/package.json +60 -0
  112. 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
+ }