@eduardbar/drift 0.2.3 → 0.4.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/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +39 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
- package/AGENTS.md +229 -0
- package/CHANGELOG.md +105 -0
- package/CODE_OF_CONDUCT.md +30 -0
- package/CONTRIBUTING.md +125 -0
- package/LICENSE +21 -0
- package/README.md +89 -7
- package/ROADMAP.md +213 -0
- package/assets/og-v030-linkedin.png +0 -0
- package/assets/og-v030-linkedin.svg +120 -0
- package/assets/og-v030-x.png +0 -0
- package/assets/og-v030-x.svg +94 -0
- package/content-v030.txt +165 -0
- package/dist/analyzer.d.ts +2 -2
- package/dist/analyzer.js +630 -2
- package/dist/cli.js +61 -5
- package/dist/config.d.ts +12 -0
- package/dist/config.js +40 -0
- package/dist/diff.d.ts +10 -0
- package/dist/diff.js +58 -0
- package/dist/git.d.ts +19 -0
- package/dist/git.js +84 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/printer.d.ts +5 -2
- package/dist/printer.js +157 -2
- package/dist/reporter.d.ts +2 -1
- package/dist/reporter.js +86 -0
- package/dist/types.d.ts +70 -0
- package/package.json +9 -1
- package/src/analyzer.ts +688 -3
- package/src/cli.ts +66 -5
- package/src/config.ts +45 -0
- package/src/diff.ts +74 -0
- package/src/git.ts +98 -0
- package/src/index.ts +2 -1
- package/src/printer.ts +175 -3
- package/src/reporter.ts +94 -1
- package/src/types.ts +85 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something is broken or behaving unexpectedly
|
|
4
|
+
title: "fix: "
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What happened
|
|
10
|
+
|
|
11
|
+
<!-- A clear description of the bug. -->
|
|
12
|
+
|
|
13
|
+
## Steps to reproduce
|
|
14
|
+
|
|
15
|
+
1. Run `npx @eduardbar/drift scan ...`
|
|
16
|
+
2. ...
|
|
17
|
+
|
|
18
|
+
## Expected behavior
|
|
19
|
+
|
|
20
|
+
<!-- What should have happened. -->
|
|
21
|
+
|
|
22
|
+
## Actual behavior
|
|
23
|
+
|
|
24
|
+
<!-- What actually happened. Include the full terminal output if relevant. -->
|
|
25
|
+
|
|
26
|
+
## Environment
|
|
27
|
+
|
|
28
|
+
- drift version: <!-- run `npx @eduardbar/drift --version` -->
|
|
29
|
+
- Node.js version: <!-- run `node --version` -->
|
|
30
|
+
- OS: <!-- e.g. Windows 11, macOS 14, Ubuntu 22.04 -->
|
|
31
|
+
- Shell: <!-- e.g. PowerShell, bash, zsh -->
|
|
32
|
+
|
|
33
|
+
## Minimal reproduction
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Paste the smallest possible file that triggers the bug
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Additional context
|
|
40
|
+
|
|
41
|
+
<!-- Screenshots, links, anything else that helps. -->
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Propose a new detection rule or CLI feature
|
|
4
|
+
title: "feat: "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
<!-- What specific AI-generated pattern or technical debt is NOT currently detected?
|
|
12
|
+
Or what workflow friction does this feature address? -->
|
|
13
|
+
|
|
14
|
+
## Proposed solution
|
|
15
|
+
|
|
16
|
+
<!-- Describe the rule or feature. If it's a new detection rule, include:
|
|
17
|
+
- Rule name (kebab-case)
|
|
18
|
+
- Severity: error | warning | info
|
|
19
|
+
- Suggested weight (1–20)
|
|
20
|
+
- What it detects and why it matters -->
|
|
21
|
+
|
|
22
|
+
## Example
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Code that SHOULD trigger the new rule
|
|
26
|
+
function example() {
|
|
27
|
+
// ...
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Why drift and not ESLint
|
|
32
|
+
|
|
33
|
+
<!-- drift is NOT an ESLint replacement. It targets patterns ESLint can't catch:
|
|
34
|
+
architectural violations, AI-specific habits, historical debt trends.
|
|
35
|
+
Explain why this belongs in drift. -->
|
|
36
|
+
|
|
37
|
+
## Additional context
|
|
38
|
+
|
|
39
|
+
<!-- Links, references, real-world examples that motivated this request. -->
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Pull Request
|
|
2
|
+
|
|
3
|
+
## Type
|
|
4
|
+
|
|
5
|
+
- [ ] Bug fix
|
|
6
|
+
- [ ] New detection rule
|
|
7
|
+
- [ ] New CLI feature
|
|
8
|
+
- [ ] Refactor / performance
|
|
9
|
+
- [ ] Docs
|
|
10
|
+
- [ ] Other
|
|
11
|
+
|
|
12
|
+
## Summary
|
|
13
|
+
|
|
14
|
+
<!-- What does this PR do and why? 1–3 sentences max. -->
|
|
15
|
+
|
|
16
|
+
## Changes
|
|
17
|
+
|
|
18
|
+
-
|
|
19
|
+
-
|
|
20
|
+
|
|
21
|
+
## New rule checklist (skip if not applicable)
|
|
22
|
+
|
|
23
|
+
- [ ] Entry added to `RULE_WEIGHTS` in `src/analyzer.ts`
|
|
24
|
+
- [ ] Detection logic implemented using ts-morph AST
|
|
25
|
+
- [ ] `fix_suggestion` added for the rule in `src/printer.ts`
|
|
26
|
+
- [ ] Rule documented in `README.md` (What it detects table)
|
|
27
|
+
- [ ] Rule documented in `AGENTS.md` (Rules table)
|
|
28
|
+
|
|
29
|
+
## Testing
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Command you ran to verify this works
|
|
33
|
+
npx @eduardbar/drift scan ./src
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
<!-- Paste the relevant part of the output. -->
|
|
37
|
+
|
|
38
|
+
## Breaking changes
|
|
39
|
+
|
|
40
|
+
<!-- Does this change the score of existing scans, remove a flag, or change output format?
|
|
41
|
+
If yes, describe the impact. -->
|
|
42
|
+
|
|
43
|
+
## Commit convention
|
|
44
|
+
|
|
45
|
+
This PR follows [Conventional Commits](https://www.conventionalcommits.org/).
|
|
46
|
+
All commits are in the format `type(scope): description`.
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# AGENTS.md — drift
|
|
2
|
+
|
|
3
|
+
## Qué es drift
|
|
4
|
+
|
|
5
|
+
`@eduardbar/drift` es un CLI TypeScript que escanea proyectos TypeScript con análisis AST (ts-morph) y asigna un score de 0 a 100 a cada archivo según la cantidad de deuda técnica AI-generada que contiene.
|
|
6
|
+
|
|
7
|
+
- **0** = código limpio
|
|
8
|
+
- **100** = reescribí esto antes de que alguien lo vea
|
|
9
|
+
|
|
10
|
+
Publicado en npm como `@eduardbar/drift`. MIT.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Stack técnico
|
|
15
|
+
|
|
16
|
+
| Dep | Rol |
|
|
17
|
+
|-----|-----|
|
|
18
|
+
| `ts-morph ^27` | Motor AST — traversal de nodos TypeScript |
|
|
19
|
+
| `commander ^14` | CLI flags y subcomandos |
|
|
20
|
+
| `kleur ^4` | Colores en consola (sin dependencias) |
|
|
21
|
+
| `typescript ^5.9` | Dev — compilación |
|
|
22
|
+
| `@types/node ^25` | Dev — tipos Node.js |
|
|
23
|
+
|
|
24
|
+
**Runtime:** Node.js 18+, ES Modules (`"type": "module"`).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Estructura del proyecto
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
drift/
|
|
32
|
+
├── bin/
|
|
33
|
+
│ └── drift.js ← wrapper cross-platform (Windows npx fix)
|
|
34
|
+
├── src/
|
|
35
|
+
│ ├── types.ts ← interfaces: DriftIssue, FileReport, DriftReport, AIOutput
|
|
36
|
+
│ ├── analyzer.ts ← motor AST + 10 reglas de detección + drift-ignore
|
|
37
|
+
│ ├── reporter.ts ← buildReport(), formatMarkdown(), formatAIOutput()
|
|
38
|
+
│ ├── printer.ts ← salida consola con colores y score bar ASCII
|
|
39
|
+
│ ├── utils.ts ← scoreToGrade, severityIcon, scoreBar
|
|
40
|
+
│ ├── index.ts ← re-exports públicos (librería)
|
|
41
|
+
│ └── cli.ts ← entry point Commander.js
|
|
42
|
+
├── assets/
|
|
43
|
+
│ ├── og.svg / og.png ← imagen OG original
|
|
44
|
+
│ ├── og-v030-linkedin.svg/png ← imagen post LinkedIn v0.3.0
|
|
45
|
+
│ └── og-v030-x.svg/png ← imagen hilo X v0.3.0
|
|
46
|
+
├── dist/ ← output tsc (no editar a mano)
|
|
47
|
+
├── .github/workflows/publish.yml
|
|
48
|
+
├── package.json
|
|
49
|
+
├── tsconfig.json
|
|
50
|
+
└── AGENTS.md ← este archivo
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Comandos de desarrollo
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm run build # tsc — compila src/ → dist/
|
|
59
|
+
npm run dev # tsc --watch
|
|
60
|
+
npm start # node dist/cli.js (desarrollo local)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Pre-publicación:** `prepublishOnly` corre `build` automáticamente.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## CLI — flags disponibles
|
|
68
|
+
|
|
69
|
+
| Flag | Tipo | Descripción |
|
|
70
|
+
|------|------|-------------|
|
|
71
|
+
| `scan <path>` | positional | Ruta a escanear (requerido) |
|
|
72
|
+
| `--output <file>` / `-o` | string | Escribe reporte Markdown a archivo |
|
|
73
|
+
| `--json` | boolean | Imprime `DriftReport` crudo como JSON |
|
|
74
|
+
| `--ai` | boolean | JSON optimizado para LLMs (`AIOutput`) |
|
|
75
|
+
| `--fix` | boolean | Muestra sugerencias de fix en consola |
|
|
76
|
+
| `--min-score <n>` | number | Exit code 1 si score supera umbral (CI) |
|
|
77
|
+
|
|
78
|
+
**Uso básico:**
|
|
79
|
+
```bash
|
|
80
|
+
npx @eduardbar/drift scan .
|
|
81
|
+
npx @eduardbar/drift scan ./src --min-score 60
|
|
82
|
+
npx @eduardbar/drift scan ./src --ai | pbcopy # pegar en Claude/GPT
|
|
83
|
+
npx @eduardbar/drift scan ./src --fix # ver sugerencias inline
|
|
84
|
+
npx @eduardbar/drift scan ./src -o report.md # exportar Markdown
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Reglas del analyzer
|
|
90
|
+
|
|
91
|
+
| Regla | Severidad | Peso | Qué detecta |
|
|
92
|
+
|-------|-----------|------|-------------|
|
|
93
|
+
| `large-file` | error | 20 | Archivos > 300 líneas |
|
|
94
|
+
| `large-function` | error | 15 | Funciones > 50 líneas |
|
|
95
|
+
| `duplicate-function-name` | error | 18 | Nombres de función duplicados (case-insensitive) |
|
|
96
|
+
| `debug-leftover` | warning | 10 | `console.log/warn/error` + `TODO/FIXME/HACK/XXX/TEMP` |
|
|
97
|
+
| `catch-swallow` | warning | 10 | Bloques `catch {}` vacíos |
|
|
98
|
+
| `dead-code` | warning | 8 | Imports nombrados sin usar |
|
|
99
|
+
| `any-abuse` | warning | 8 | Uso explícito de `any` como tipo |
|
|
100
|
+
| `comment-contradiction` | warning | 12 | (reservado — definido en RULE_WEIGHTS) |
|
|
101
|
+
| `no-return-type` | info | 5 | Funciones sin tipo de retorno explícito |
|
|
102
|
+
| `magic-number` | info | 3 | (reservado — definido en RULE_WEIGHTS) |
|
|
103
|
+
|
|
104
|
+
**Score = suma de pesos capped a 100. Score del proyecto = promedio de archivos.**
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## drift-ignore
|
|
109
|
+
|
|
110
|
+
**Por línea** (`// drift-ignore`):
|
|
111
|
+
- Suprime el issue en la línea actual o en la línea inmediatamente superior al problema.
|
|
112
|
+
- Funciona para cualquier regla.
|
|
113
|
+
|
|
114
|
+
**Por archivo** (`// drift-ignore-file`):
|
|
115
|
+
- Se coloca en las primeras 10 líneas del archivo.
|
|
116
|
+
- `analyzeFile()` devuelve reporte vacío (score 0, cero issues) para ese archivo.
|
|
117
|
+
- Usar en archivos con `console.log` intencional (ej: `printer.ts`).
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Formato `--ai` (`AIOutput`)
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface AIOutput {
|
|
125
|
+
summary: {
|
|
126
|
+
score: number
|
|
127
|
+
grade: string // "CLEAN" | "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"
|
|
128
|
+
total_issues: number
|
|
129
|
+
files_affected: number
|
|
130
|
+
files_clean: number
|
|
131
|
+
}
|
|
132
|
+
priority_order: Array<{
|
|
133
|
+
rank: number
|
|
134
|
+
file: string
|
|
135
|
+
line: number
|
|
136
|
+
rule: string
|
|
137
|
+
severity: "error" | "warning" | "info"
|
|
138
|
+
message: string
|
|
139
|
+
snippet: string
|
|
140
|
+
fix_suggestion: string
|
|
141
|
+
effort: "low" | "medium" | "high"
|
|
142
|
+
}>
|
|
143
|
+
context_for_ai: {
|
|
144
|
+
project_type: "typescript"
|
|
145
|
+
scan_path: string
|
|
146
|
+
rules_detected: string[]
|
|
147
|
+
recommended_action: string
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Los issues se ordenan: error > warning > info, luego low effort primero (quick wins).
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Formato `--fix` en consola
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
┌──────────────────────────────────────────────────────┐
|
|
160
|
+
│ - console.log(userData)
|
|
161
|
+
│ + Remove this console.log statement
|
|
162
|
+
│ + Or replace with a proper logging library
|
|
163
|
+
└──────────────────────────────────────────────────────┘
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Las sugerencias por regla están hardcodeadas en `src/printer.ts`.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## CI/CD — GitHub Actions
|
|
171
|
+
|
|
172
|
+
Workflow en `.github/workflows/publish.yml`:
|
|
173
|
+
- **Trigger único:** `release: published` (evita doble publish)
|
|
174
|
+
- **Fallback manual:** `workflow_dispatch` con input `tag`
|
|
175
|
+
- **Guard:** verifica `npm view @eduardbar/drift@$VERSION` antes de publicar
|
|
176
|
+
|
|
177
|
+
**Integración CI en proyectos externos:**
|
|
178
|
+
```yaml
|
|
179
|
+
- name: Check drift score
|
|
180
|
+
run: npx @eduardbar/drift scan ./src --min-score 60
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Compatibilidad Windows
|
|
186
|
+
|
|
187
|
+
`bin/drift.js` es el wrapper cross-platform:
|
|
188
|
+
```javascript
|
|
189
|
+
#!/usr/bin/env node
|
|
190
|
+
import('../dist/cli.js')
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`package.json` apunta `bin.drift` a `bin/drift.js`, **no** a `dist/cli.js`.
|
|
194
|
+
Sin esto, Windows no ejecuta el shebang correctamente con ES modules.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Versiones
|
|
199
|
+
|
|
200
|
+
| Versión | Cambios principales |
|
|
201
|
+
|---------|---------------------|
|
|
202
|
+
| **0.3.0** | `--ai` (LLM-optimized JSON output) + `--fix` (inline suggestions) |
|
|
203
|
+
| **0.2.3** | Fix: bin wrapper para compatibilidad Windows npx |
|
|
204
|
+
| **0.2.2** | Refactor: `formatMarkdown` dividido en helpers + fix CI doble publish |
|
|
205
|
+
| **0.2.1** | `drift-ignore` por línea y por archivo + fix console output propio |
|
|
206
|
+
| **0.2.0** | Score bar ASCII + header hierarchy + DRY utils + file count en CLI |
|
|
207
|
+
| **0.1.x** | Bootstrap: tipos, analyzer (10 reglas), reporter, printer, CLI, CI/CD |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Convenciones de código
|
|
212
|
+
|
|
213
|
+
- Todo en TypeScript — sin `any` explícito (drift se corre sobre sí mismo)
|
|
214
|
+
- ES Modules — `import/export`, sin CommonJS
|
|
215
|
+
- Conventional Commits obligatorios (ver AGENTS.md global)
|
|
216
|
+
- `// drift-ignore-file` en `printer.ts` — sus `console.log` son output intencional
|
|
217
|
+
- `scoreToGrade`, `severityIcon`, `scoreBar` viven en `utils.ts` — no duplicar
|
|
218
|
+
- Nuevas reglas: agregar entrada en `RULE_WEIGHTS` en `analyzer.ts` + lógica de detección AST
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Agregar una nueva regla — checklist
|
|
223
|
+
|
|
224
|
+
1. Agregar `"rule-name": <peso>` a `RULE_WEIGHTS` en `src/analyzer.ts`
|
|
225
|
+
2. Implementar la lógica de detección AST usando ts-morph en `analyzeFile()`
|
|
226
|
+
3. Agregar `fix_suggestion` para la regla en `src/printer.ts` (objeto de sugerencias por regla)
|
|
227
|
+
4. Actualizar `README.md` — tabla de reglas
|
|
228
|
+
5. Actualizar este `AGENTS.md` — tabla de reglas
|
|
229
|
+
6. Commit: `feat(analyzer): add <rule-name> rule`
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to drift are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## [0.4.0] — 2026-02-23
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **Phase 2: cross-file dead code detection** — three new rules that require project-level import graph analysis (ESLint cannot do this by design — issue wontfix #371):
|
|
18
|
+
- `unused-export` (warning, weight 8): named exports that are never imported anywhere in the project.
|
|
19
|
+
- `dead-file` (warning, weight 10): source files that are never imported by any other file.
|
|
20
|
+
- `unused-dependency` (warning, weight 6): packages listed in `dependencies` in `package.json` that are never imported in source code.
|
|
21
|
+
- `analyzeProject()` now builds a cross-file import graph before per-file analysis, enabling project-level rules without additional dependencies.
|
|
22
|
+
- Fix suggestions for all three new rules in `src/printer.ts`.
|
|
23
|
+
- **Phase 3: structural architecture analysis**:
|
|
24
|
+
- `circular-dependency` (error, weight 14): detects circular import chains using DFS cycle detection. Reports the full cycle path as `A → B → C → A`.
|
|
25
|
+
- `layer-violation` (error, weight 16): flags imports that violate declared architectural layers. Requires `drift.config.ts`.
|
|
26
|
+
- `cross-boundary-import` (warning, weight 10): flags imports across module boundaries outside allowed paths. Requires `drift.config.ts`.
|
|
27
|
+
- `loadConfig()` — new async config loader in `src/config.ts`. Discovers `drift.config.ts / .js / .json` at project root. All rules except `layer-violation` and `cross-boundary-import` work without any config.
|
|
28
|
+
- `DriftConfig`, `LayerDefinition`, `ModuleBoundary` types exported from the package.
|
|
29
|
+
- Fix suggestions for all Phase 3 rules in `src/printer.ts`.
|
|
30
|
+
- **Phase 4: `drift diff` — historical comparison**:
|
|
31
|
+
- `drift diff [ref]` command: compare current project state against any git ref (commit, branch, tag). Default ref: `HEAD~1`.
|
|
32
|
+
- Uses `git show <ref>:<file>` for non-destructive extraction — no checkout, no stash, no repo state changes.
|
|
33
|
+
- Detects new issues introduced and issues resolved per file.
|
|
34
|
+
- Shows score delta per file and overall (`+N` red = regression, `-N` green = improvement).
|
|
35
|
+
- `--json` flag outputs raw `DriftDiff` JSON for CI consumption.
|
|
36
|
+
- New types `DriftDiff` and `FileDiff` exported from the package.
|
|
37
|
+
- New `computeDiff()` function exported for programmatic use.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## [0.3.0]
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
- `--ai` flag: outputs LLM-optimized JSON (`AIOutput`) designed to be pasted directly into Claude, GPT, or any other model as context. Issues are ranked by severity and effort — quick wins first. Each issue includes `fix_suggestion` and `effort` level. The output includes `recommended_action` generated from the scan.
|
|
45
|
+
- `--fix` flag: shows inline fix suggestions in the console for each detected issue, rendered as a visual diff block.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- `formatAIOutput()` added to `reporter.ts` — produces the `AIOutput` structure with `summary`, `priority_order`, and `context_for_ai`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## [0.2.3]
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
- `npx @eduardbar/drift` now works correctly on Windows. The issue was that Node.js on Windows does not execute the shebang (`#!/usr/bin/env node`) in ES module `.js` files reliably. Added `bin/drift.js` as a thin wrapper with a dynamic `import()` that works cross-platform.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## [0.2.2]
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
- CI workflow was triggering a double publish on the same release. Removed the duplicate `push: tags` trigger — now uses only `release: published`. Added a guard step that checks `npm view @eduardbar/drift@$VERSION` before publishing to skip if already published.
|
|
63
|
+
|
|
64
|
+
### Refactored
|
|
65
|
+
- `formatMarkdown()` in `reporter.ts` split into smaller helper functions for readability.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## [0.2.1]
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
- `drift-ignore` comment support: add `// drift-ignore` on a line (or the line above it) to suppress that specific issue.
|
|
73
|
+
- `drift-ignore-file` comment support: add `// drift-ignore-file` in the first 10 lines of a file to exclude the entire file from analysis. Used in `printer.ts` itself — its `console.log` calls are intentional CLI output, not debug leftovers.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
- drift was reporting issues in its own `printer.ts` when run on itself. Fixed by adding `// drift-ignore-file` to that file.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## [0.2.0]
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
- ASCII score bar in console output (`█████████████░░░░░░░ 67/100`).
|
|
84
|
+
- Executive summary header with total file count, error/warning/info counts, and top issues.
|
|
85
|
+
- File count shown after scan completes.
|
|
86
|
+
- `scoreToGrade`, `severityIcon`, and `scoreBar` extracted to `src/utils.ts` — shared between printer and reporter.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- Console output restructured with cleaner visual hierarchy.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## [0.1.0]
|
|
94
|
+
|
|
95
|
+
### Added
|
|
96
|
+
- Initial release.
|
|
97
|
+
- AST analysis engine using ts-morph.
|
|
98
|
+
- 8 detection rules: `large-file`, `large-function`, `debug-leftover`, `dead-code`, `duplicate-function-name`, `any-abuse`, `catch-swallow`, `no-return-type`.
|
|
99
|
+
- Score 0–100 per file and per project (average).
|
|
100
|
+
- Console printer with color output using kleur.
|
|
101
|
+
- Markdown reporter (`--output`).
|
|
102
|
+
- Raw JSON output (`--json`).
|
|
103
|
+
- CI integration via `--min-score` (exit code 1 if score exceeds threshold).
|
|
104
|
+
- CLI entry point with Commander.js.
|
|
105
|
+
- GitHub Actions workflow for automated npm publish on release.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Commitment
|
|
4
|
+
|
|
5
|
+
drift is a technical project. We keep discussion focused on code, architecture, and technical debt patterns.
|
|
6
|
+
|
|
7
|
+
Everyone who participates — through issues, PRs, discussions, or comments — is expected to:
|
|
8
|
+
|
|
9
|
+
- Be direct and specific. Vague complaints don't help anyone.
|
|
10
|
+
- Criticize ideas, not people.
|
|
11
|
+
- Provide actionable feedback when rejecting a PR or issue.
|
|
12
|
+
- Assume good intent by default.
|
|
13
|
+
|
|
14
|
+
## What we don't tolerate
|
|
15
|
+
|
|
16
|
+
- Personal attacks, insults, or harassment of any kind.
|
|
17
|
+
- Dismissing contributions without explanation.
|
|
18
|
+
- Spam, self-promotion unrelated to drift, or off-topic debates.
|
|
19
|
+
|
|
20
|
+
## Scope
|
|
21
|
+
|
|
22
|
+
This applies in all project spaces: GitHub Issues, Pull Requests, Discussions, and any other channel where drift is represented.
|
|
23
|
+
|
|
24
|
+
## Enforcement
|
|
25
|
+
|
|
26
|
+
Violations can be reported to [ing.eduardbarrera@gmail.com](mailto:ing.eduardbarrera@gmail.com). All reports will be reviewed and responded to. Maintainers have final say on enforcement decisions.
|
|
27
|
+
|
|
28
|
+
## Note
|
|
29
|
+
|
|
30
|
+
This project does not adopt any third-party code of conduct document verbatim. These are our own rules, written to be simple and enforceable.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Contributing to drift
|
|
2
|
+
|
|
3
|
+
Thanks for taking the time. drift exists because ESLint solves correctness and SonarQube solves enterprise complexity — but nobody solved the middle: code that compiles, passes linting, and quietly accumulates into a codebase no one can maintain six months later.
|
|
4
|
+
|
|
5
|
+
Every rule in drift was added because real developers kept finding the same pattern in AI-generated code and had no automated way to catch it. That's the contribution model: you see something repeatedly, you open an issue, we add a rule.
|
|
6
|
+
|
|
7
|
+
**The gap drift fills:**
|
|
8
|
+
|
|
9
|
+
| Tool | What it catches | What it misses |
|
|
10
|
+
|------|-----------------|----------------|
|
|
11
|
+
| ESLint | Correctness, style, per-file patterns | Cross-file dead code, architecture violations, complexity trends |
|
|
12
|
+
| SonarQube | Enterprise security, deep complexity | Lightweight, fast, free for small teams |
|
|
13
|
+
| knip | Unused exports and files | Structural health, AI-specific patterns, score |
|
|
14
|
+
| **drift** | Structural debt, AI patterns, cross-file analysis, score | Style, correctness (intentionally) |
|
|
15
|
+
|
|
16
|
+
## How to contribute
|
|
17
|
+
|
|
18
|
+
### Report a bug
|
|
19
|
+
|
|
20
|
+
Open an issue using the **Bug Report** template. Include:
|
|
21
|
+
- The command you ran
|
|
22
|
+
- What you expected vs what happened
|
|
23
|
+
- Your Node.js version and OS
|
|
24
|
+
|
|
25
|
+
### Suggest a new rule
|
|
26
|
+
|
|
27
|
+
This is the most valuable contribution. If you keep seeing a specific AI-generated pattern that drift doesn't catch yet, open an issue using the **Rule Request** template with:
|
|
28
|
+
- A short description of the pattern
|
|
29
|
+
- A real code snippet that triggers it (anonymized is fine)
|
|
30
|
+
- Why it's harmful or a sign of AI-generated debt
|
|
31
|
+
|
|
32
|
+
### Submit a PR
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 1. Fork and clone
|
|
36
|
+
git clone https://github.com/eduardbar/drift
|
|
37
|
+
cd drift
|
|
38
|
+
|
|
39
|
+
# 2. Install dependencies
|
|
40
|
+
npm install
|
|
41
|
+
|
|
42
|
+
# 3. Build
|
|
43
|
+
npm run build
|
|
44
|
+
|
|
45
|
+
# 4. Create a branch
|
|
46
|
+
git checkout -b feat/rule-name
|
|
47
|
+
# or
|
|
48
|
+
git checkout -b fix/issue-description
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Adding a new rule
|
|
52
|
+
|
|
53
|
+
1. Add the rule weight in `RULE_WEIGHTS` in `src/analyzer.ts`:
|
|
54
|
+
```typescript
|
|
55
|
+
const RULE_WEIGHTS: Record<string, number> = {
|
|
56
|
+
'your-rule-name': 10, // weight between 1 and 20
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
2. Implement the detection logic in `analyzeFile()` using ts-morph AST traversal.
|
|
61
|
+
|
|
62
|
+
3. Add a fix suggestion in `src/printer.ts`:
|
|
63
|
+
```typescript
|
|
64
|
+
const FIX_SUGGESTIONS: Record<string, string[]> = {
|
|
65
|
+
'your-rule-name': [
|
|
66
|
+
'First suggestion',
|
|
67
|
+
'Alternative suggestion',
|
|
68
|
+
],
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
4. Update the rules table in `README.md`.
|
|
73
|
+
|
|
74
|
+
5. Run drift on itself to make sure nothing breaks:
|
|
75
|
+
```bash
|
|
76
|
+
node dist/cli.js scan ./src
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
6. Open a PR with a clear description of what the rule detects and why it matters.
|
|
80
|
+
|
|
81
|
+
#### Commit convention
|
|
82
|
+
|
|
83
|
+
This project follows [Conventional Commits](https://www.conventionalcommits.org/):
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
feat(analyzer): add high-complexity rule for cyclomatic detection
|
|
87
|
+
fix(printer): align snippet indentation for long file paths
|
|
88
|
+
docs(readme): add rule description for deep-nesting
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Types: `feat`, `fix`, `refactor`, `perf`, `docs`, `chore`, `ci`, `test`
|
|
92
|
+
|
|
93
|
+
### What makes a good rule
|
|
94
|
+
|
|
95
|
+
A good drift rule:
|
|
96
|
+
- Detects a **specific, reproducible** pattern — not a matter of style preference
|
|
97
|
+
- Has a **measurable signal** that AI tools leave this more than humans do
|
|
98
|
+
- Is **false-positive resistant** — it should almost never fire on intentional code
|
|
99
|
+
- Can be **ignored with `// drift-ignore`** when the pattern is intentional
|
|
100
|
+
|
|
101
|
+
### What drift is NOT
|
|
102
|
+
|
|
103
|
+
drift is not a linter for style or correctness. That's ESLint's job and it does it well. drift does not replace ESLint — it runs alongside it.
|
|
104
|
+
|
|
105
|
+
drift detects patterns that are:
|
|
106
|
+
- Syntactically correct and pass linting
|
|
107
|
+
- But accumulate into a codebase no one can maintain
|
|
108
|
+
- Specifically amplified by AI code generation tools
|
|
109
|
+
|
|
110
|
+
If your proposed rule overlaps with an existing ESLint rule (e.g. `no-unused-vars`, `complexity`, `no-empty`), it does not belong in drift — unless drift can do something ESLint fundamentally cannot (e.g. cross-file analysis, architectural context, project-wide scoring).
|
|
111
|
+
|
|
112
|
+
The test: *"Could ESLint catch this with a single-file rule?"* If yes, it's probably not a drift rule.
|
|
113
|
+
|
|
114
|
+
## Development setup
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npm install # install dependencies
|
|
118
|
+
npm run build # compile TypeScript → dist/
|
|
119
|
+
npm run dev # watch mode
|
|
120
|
+
node dist/cli.js scan ./src # run on the project itself
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Questions?
|
|
124
|
+
|
|
125
|
+
Open a [Discussion](https://github.com/eduardbar/drift/discussions) — not an issue. Issues are for bugs and rule requests.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Eduard Barrera
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|