@dewtech/dare-cli 2.16.0 → 2.17.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/README.md +98 -0
- package/dist/__tests__/refine.test.d.ts +2 -0
- package/dist/__tests__/refine.test.d.ts.map +1 -0
- package/dist/__tests__/refine.test.js +186 -0
- package/dist/__tests__/refine.test.js.map +1 -0
- package/dist/__tests__/review.test.d.ts +2 -0
- package/dist/__tests__/review.test.d.ts.map +1 -0
- package/dist/__tests__/review.test.js +242 -0
- package/dist/__tests__/review.test.js.map +1 -0
- package/dist/__tests__/update.test.d.ts +2 -0
- package/dist/__tests__/update.test.d.ts.map +1 -0
- package/dist/__tests__/update.test.js +150 -0
- package/dist/__tests__/update.test.js.map +1 -0
- package/dist/bin/dare.js +6 -0
- package/dist/bin/dare.js.map +1 -1
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +76 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/refine.d.ts +16 -0
- package/dist/commands/refine.d.ts.map +1 -0
- package/dist/commands/refine.js +167 -0
- package/dist/commands/refine.js.map +1 -0
- package/dist/commands/review.d.ts +16 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +106 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +149 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/types/Refine.types.d.ts +96 -0
- package/dist/types/Refine.types.d.ts.map +1 -0
- package/dist/types/Refine.types.js +19 -0
- package/dist/types/Refine.types.js.map +1 -0
- package/dist/types/Review.types.d.ts +86 -0
- package/dist/types/Review.types.d.ts.map +1 -0
- package/dist/types/Review.types.js +15 -0
- package/dist/types/Review.types.js.map +1 -0
- package/dist/types/UpdateManifest.types.d.ts +91 -0
- package/dist/types/UpdateManifest.types.d.ts.map +1 -0
- package/dist/types/UpdateManifest.types.js +13 -0
- package/dist/types/UpdateManifest.types.js.map +1 -0
- package/dist/utils/ReviewRunner.d.ts +42 -0
- package/dist/utils/ReviewRunner.d.ts.map +1 -0
- package/dist/utils/ReviewRunner.js +175 -0
- package/dist/utils/ReviewRunner.js.map +1 -0
- package/dist/utils/UpdateApplier.d.ts +42 -0
- package/dist/utils/UpdateApplier.d.ts.map +1 -0
- package/dist/utils/UpdateApplier.js +207 -0
- package/dist/utils/UpdateApplier.js.map +1 -0
- package/dist/utils/UpdateDetector.d.ts +56 -0
- package/dist/utils/UpdateDetector.d.ts.map +1 -0
- package/dist/utils/UpdateDetector.js +164 -0
- package/dist/utils/UpdateDetector.js.map +1 -0
- package/dist/utils/complexity-analyzer.d.ts +60 -0
- package/dist/utils/complexity-analyzer.d.ts.map +1 -0
- package/dist/utils/complexity-analyzer.js +292 -0
- package/dist/utils/complexity-analyzer.js.map +1 -0
- package/dist/utils/project-generator.d.ts.map +1 -1
- package/dist/utils/project-generator.js +21 -2
- package/dist/utils/project-generator.js.map +1 -1
- package/dist/utils/static-analyzer.d.ts +29 -0
- package/dist/utils/static-analyzer.d.ts.map +1 -0
- package/dist/utils/static-analyzer.js +390 -0
- package/dist/utils/static-analyzer.js.map +1 -0
- package/dist/utils/version-compare.d.ts +27 -0
- package/dist/utils/version-compare.d.ts.map +1 -0
- package/dist/utils/version-compare.js +47 -0
- package/dist/utils/version-compare.js.map +1 -0
- package/package.json +1 -1
- package/templates/UPDATE-MANIFEST.json +48 -0
- package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +180 -36
- package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +114 -0
- package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -0
- package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +41 -0
- package/templates/ide/antigravity/templates/TASK-SPEC-template.md +45 -4
- package/templates/ide/claude/.claude/commands/dare-blueprint.md +56 -0
- package/templates/ide/claude/.claude/commands/dare-dag-build.md +41 -0
- package/templates/ide/claude/.claude/commands/dare-refine.md +145 -0
- package/templates/ide/claude/.claude/commands/dare-review.md +113 -0
- package/templates/ide/claude/templates/TASK-SPEC-template.md +45 -4
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +45 -0
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +42 -0
- package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -0
- package/templates/ide/cursor/.cursor/commands/review-task.md +91 -0
- package/templates/ide/cursor/templates/TASK-SPEC-template.md +45 -4
package/README.md
CHANGED
|
@@ -375,6 +375,104 @@ of each canonical DARE artifact, active GraphRAG backend, and task progress.
|
|
|
375
375
|
dare info
|
|
376
376
|
```
|
|
377
377
|
|
|
378
|
+
### `dare review` ← new in v2.17.0
|
|
379
|
+
|
|
380
|
+
**Anti-stub gate.** Audita os arquivos que uma task tocou e detecta padrões de "fake completeness": `TODO`/`FIXME`, stubs (`throw new Error('not implemented')`, `todo!()`, `NotImplementedError`), funções vazias, retorno-fantasma (`return null` como única statement), mocks fora de testes (`jest.fn`, `vi.mock`, `sinon.stub`, `MagicMock`), comentários-placeholder (`// implement later`).
|
|
381
|
+
|
|
382
|
+
A camada estática (regex, determinística) é só metade. A IDE agent pode rodar a skill `dare-review` / `review-task` para validar critério-a-critério se a implementação atende a spec, emitir um `SemanticVerdict` JSON, e o CLI funde os dois numa única decisão.
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
# Audita os arquivos listados em DARE/EXECUTION/task-034.md
|
|
386
|
+
dare review task-034
|
|
387
|
+
|
|
388
|
+
# Em CI:
|
|
389
|
+
dare review task-034 --strict --format json
|
|
390
|
+
|
|
391
|
+
# Lista explícita de arquivos:
|
|
392
|
+
dare review task-034 --files src/auth/login.ts src/auth/register.ts
|
|
393
|
+
|
|
394
|
+
# Funde com verdito semântico do agente:
|
|
395
|
+
dare review task-034 --from-agent .dare/verdict-task-034.json
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Gate opt-in no Ralph Loop:** com `review.onComplete: true` em `dare.config.json`, `dare execute --complete <id>` bloqueia DONE se a review falhar. Para projetos novos (`dare init` v2.17+) já vem ligado; projetos legados permanecem off até o dev flipar.
|
|
399
|
+
|
|
400
|
+
### `dare refine` ← new in v2.17.0
|
|
401
|
+
|
|
402
|
+
**Anti-monstro.** Mede complexidade de uma task e, opcionalmente, propõe quebra em sub-tasks menores. Heurística determinística pesa # arquivos, # funções/endpoints, # testes, # dependências, keywords "pesadas" (refactor/migrate/integrate/multiple) — produz um score em LOW (0–5) / MED (6–12) / HIGH (13–20) / CRITICAL (21+).
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
# Apenas mede e reporta:
|
|
406
|
+
dare refine task-034
|
|
407
|
+
|
|
408
|
+
# Mede + propõe quebra em sub-tasks (task-034a, task-034b, ...):
|
|
409
|
+
dare refine task-034 --split
|
|
410
|
+
|
|
411
|
+
# Anota TASKS.md marcando a task para split (o agente regenera as specs):
|
|
412
|
+
dare refine task-034 --split --apply
|
|
413
|
+
|
|
414
|
+
# Em CI: exit code 2 se HIGH/CRITICAL:
|
|
415
|
+
dare refine task-034 --strict
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
A camada determinística agrupa arquivos por diretório raiz. A IDE agent (skills `dare-refine` / `refine-task`) refina o split semanticamente — por camada (Model/Controller/Service), por endpoint, por feature, refactor-then-feature, migration-then-code.
|
|
419
|
+
|
|
420
|
+
Thresholds configuráveis em `dare.config.json`:
|
|
421
|
+
|
|
422
|
+
```jsonc
|
|
423
|
+
{
|
|
424
|
+
"refine": {
|
|
425
|
+
"thresholds": { "low": 5, "med": 12, "high": 20 }
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### `dare update` ← new in v2.17.0
|
|
431
|
+
|
|
432
|
+
Sync the **project's DARE setup** (templates, slash commands, skills, schema)
|
|
433
|
+
with the version of the CLI currently installed. Useful when you upgrade the
|
|
434
|
+
CLI globally (`npm install -g @dewtech/dare-cli@latest`) and want a previous
|
|
435
|
+
project to pick up the new improvements — **without touching your DESIGN /
|
|
436
|
+
BLUEPRINT / TASKS / dare-dag.yaml artifacts**.
|
|
437
|
+
|
|
438
|
+
Different from upgrading the CLI itself: `npm update -g @dewtech/dare-cli`
|
|
439
|
+
changes the binary on your machine; `dare update` changes the *project files
|
|
440
|
+
on disk* to match what that binary now ships.
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
dare update # interactive (recommended)
|
|
444
|
+
dare update --dry-run # preview: shows changelog + affected files, writes nothing
|
|
445
|
+
dare update --yes # CI: apply, preserve customizations, no prompts
|
|
446
|
+
dare update --force # also overwrite files the dev customized (dangerous)
|
|
447
|
+
dare update --target 2.17.0 # update to a specific release instead of the installed CLI
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**What it does:**
|
|
451
|
+
|
|
452
|
+
1. Reads `version` from `dare.config.json` (the project's last-known DARE version).
|
|
453
|
+
2. Loads `templates/UPDATE-MANIFEST.json` (ships with the CLI) and lists every
|
|
454
|
+
release between the project's version and the CLI's version.
|
|
455
|
+
3. Prints the changelog for each pending release and the list of files
|
|
456
|
+
affected for your IDE (cursor / claude-code / antigravity / hybrid).
|
|
457
|
+
4. For each file, classifies the situation:
|
|
458
|
+
- **identical** → skip
|
|
459
|
+
- **missing** → create
|
|
460
|
+
- **apply** → file matches the previous template hash, safe to overwrite
|
|
461
|
+
- **customized** → file diverges from the previous template; prompt
|
|
462
|
+
(`keep` / `replace`) unless `--yes` (keep) or `--force` (replace).
|
|
463
|
+
5. Backs up every affected file to `.dare/backup-<from-version>/` before
|
|
464
|
+
writing.
|
|
465
|
+
6. Runs any schema migrations declared by the release (e.g. renaming a
|
|
466
|
+
config field).
|
|
467
|
+
7. Stamps `version` and `updatedAt` in `dare.config.json`.
|
|
468
|
+
|
|
469
|
+
**Adding entries when you cut a release:** each new CLI version that ships
|
|
470
|
+
template changes needs a corresponding entry in `templates/UPDATE-MANIFEST.json`
|
|
471
|
+
listing `changes` (added / modified / removed / renamed) and optional
|
|
472
|
+
`migrations`. The applier filters changes by `appliesTo: [ide]`, so a
|
|
473
|
+
template that's cursor-only won't be installed in a Claude Code project and
|
|
474
|
+
vice versa.
|
|
475
|
+
|
|
378
476
|
### `dare validate`
|
|
379
477
|
|
|
380
478
|
Static checks on `dare-dag.yaml` — ideal for pre-commit hooks and CI.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/refine.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { analyzeTaskComplexity, proposeSplit, levelFromScore, } from '../utils/complexity-analyzer.js';
|
|
6
|
+
async function makeTempDir() {
|
|
7
|
+
return fs.mkdtemp(path.join(os.tmpdir(), 'dare-refine-test-'));
|
|
8
|
+
}
|
|
9
|
+
async function writeFile(dir, rel, content) {
|
|
10
|
+
const abs = path.join(dir, rel);
|
|
11
|
+
await fs.ensureDir(path.dirname(abs));
|
|
12
|
+
await fs.writeFile(abs, content);
|
|
13
|
+
}
|
|
14
|
+
// ── levelFromScore ────────────────────────────────────────────────────────────
|
|
15
|
+
describe('levelFromScore', () => {
|
|
16
|
+
it('maps scores to default buckets', () => {
|
|
17
|
+
expect(levelFromScore(0)).toBe('LOW');
|
|
18
|
+
expect(levelFromScore(5)).toBe('LOW');
|
|
19
|
+
expect(levelFromScore(6)).toBe('MED');
|
|
20
|
+
expect(levelFromScore(12)).toBe('MED');
|
|
21
|
+
expect(levelFromScore(13)).toBe('HIGH');
|
|
22
|
+
expect(levelFromScore(20)).toBe('HIGH');
|
|
23
|
+
expect(levelFromScore(21)).toBe('CRITICAL');
|
|
24
|
+
expect(levelFromScore(50)).toBe('CRITICAL');
|
|
25
|
+
});
|
|
26
|
+
it('respects custom thresholds', () => {
|
|
27
|
+
const t = { low: 2, med: 4, high: 6 };
|
|
28
|
+
expect(levelFromScore(2, t)).toBe('LOW');
|
|
29
|
+
expect(levelFromScore(3, t)).toBe('MED');
|
|
30
|
+
expect(levelFromScore(4, t)).toBe('MED');
|
|
31
|
+
expect(levelFromScore(5, t)).toBe('HIGH');
|
|
32
|
+
expect(levelFromScore(6, t)).toBe('HIGH');
|
|
33
|
+
expect(levelFromScore(7, t)).toBe('CRITICAL');
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
// ── analyzeTaskComplexity ─────────────────────────────────────────────────────
|
|
37
|
+
describe('analyzeTaskComplexity', () => {
|
|
38
|
+
let tmp;
|
|
39
|
+
beforeEach(async () => {
|
|
40
|
+
tmp = await makeTempDir();
|
|
41
|
+
});
|
|
42
|
+
afterEach(async () => {
|
|
43
|
+
await fs.remove(tmp);
|
|
44
|
+
});
|
|
45
|
+
it('returns no-spec signal when spec is missing', async () => {
|
|
46
|
+
const r = await analyzeTaskComplexity('task-ghost', tmp);
|
|
47
|
+
expect(r).not.toBeNull();
|
|
48
|
+
expect(r?.specPath).toBeNull();
|
|
49
|
+
expect(r?.signals[0].kind).toBe('no-spec');
|
|
50
|
+
});
|
|
51
|
+
it('scores a tiny task as LOW', async () => {
|
|
52
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-001.md', `
|
|
53
|
+
# Task 001
|
|
54
|
+
|
|
55
|
+
## 3. Arquivos
|
|
56
|
+
|
|
57
|
+
| Ação | Caminho |
|
|
58
|
+
|------|---------|
|
|
59
|
+
| CRIAR | \`src/foo.ts\` |
|
|
60
|
+
|
|
61
|
+
## 4. Implementação
|
|
62
|
+
|
|
63
|
+
- [ ] Teste do caminho feliz
|
|
64
|
+
`);
|
|
65
|
+
const r = await analyzeTaskComplexity('task-001', tmp);
|
|
66
|
+
expect(r?.level).toBe('LOW');
|
|
67
|
+
expect(r?.recommendsSplit).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
it('scores a big task as HIGH/CRITICAL', async () => {
|
|
70
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-002.md', `
|
|
71
|
+
# Task 002
|
|
72
|
+
|
|
73
|
+
> **Complexidade:** HIGH
|
|
74
|
+
|
|
75
|
+
## 3. Arquivos
|
|
76
|
+
|
|
77
|
+
| Ação | Caminho |
|
|
78
|
+
|------|---------|
|
|
79
|
+
| CRIAR | \`src/a.ts\` |
|
|
80
|
+
| CRIAR | \`src/b.ts\` |
|
|
81
|
+
| CRIAR | \`src/c.ts\` |
|
|
82
|
+
| CRIAR | \`src/d.ts\` |
|
|
83
|
+
| CRIAR | \`src/e.ts\` |
|
|
84
|
+
| CRIAR | \`src/f.ts\` |
|
|
85
|
+
| CRIAR | \`src/g.ts\` |
|
|
86
|
+
| MODIFICAR | \`tests/a.test.ts\` |
|
|
87
|
+
|
|
88
|
+
## 4. Implementação
|
|
89
|
+
|
|
90
|
+
Implementar:
|
|
91
|
+
- \`POST /auth/register\`
|
|
92
|
+
- \`POST /auth/login\`
|
|
93
|
+
- \`POST /auth/refresh\`
|
|
94
|
+
- \`POST /auth/logout\`
|
|
95
|
+
- \`GET /auth/me\`
|
|
96
|
+
|
|
97
|
+
Vamos refactor o UserService e migrate o schema para suportar profile_settings.
|
|
98
|
+
Precisamos integrate com o serviço externo de email também.
|
|
99
|
+
|
|
100
|
+
- [ ] Teste do happy path
|
|
101
|
+
- [ ] Teste de email inválido
|
|
102
|
+
- [ ] Teste de senha fraca
|
|
103
|
+
- [ ] Teste de email duplicado
|
|
104
|
+
- [ ] Teste de rate limit
|
|
105
|
+
- [ ] Teste de refresh expirado
|
|
106
|
+
- [ ] Teste de logout idempotente
|
|
107
|
+
`);
|
|
108
|
+
const r = await analyzeTaskComplexity('task-002', tmp);
|
|
109
|
+
expect(['HIGH', 'CRITICAL']).toContain(r?.level);
|
|
110
|
+
expect(r?.recommendsSplit).toBe(true);
|
|
111
|
+
// Should attribute weight to multiple signal kinds
|
|
112
|
+
const kinds = r?.signals.map((s) => s.kind) ?? [];
|
|
113
|
+
expect(kinds).toContain('files');
|
|
114
|
+
expect(kinds).toContain('functions');
|
|
115
|
+
expect(kinds).toContain('tests');
|
|
116
|
+
expect(kinds).toContain('keywords');
|
|
117
|
+
expect(kinds).toContain('author-high');
|
|
118
|
+
});
|
|
119
|
+
it('counts depends_on when caller provides it', async () => {
|
|
120
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-003.md', `## 3. Arquivos\n| CRIAR | \`a.ts\` |`);
|
|
121
|
+
const r0 = await analyzeTaskComplexity('task-003', tmp, { dependsOnCount: 0 });
|
|
122
|
+
const r4 = await analyzeTaskComplexity('task-003', tmp, { dependsOnCount: 4 });
|
|
123
|
+
expect((r4?.score ?? 0)).toBeGreaterThan(r0?.score ?? 0);
|
|
124
|
+
expect(r4?.signals.some((s) => s.kind === 'dependencies')).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
it('honors custom thresholds from options', async () => {
|
|
127
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-004.md', `| CRIAR | \`a.ts\` |\n| CRIAR | \`b.ts\` |`);
|
|
128
|
+
const r = await analyzeTaskComplexity('task-004', tmp, {
|
|
129
|
+
thresholds: { low: 0.5, med: 1, high: 1.5 },
|
|
130
|
+
});
|
|
131
|
+
expect(r?.level).toBe('CRITICAL'); // tiny score still tripped by aggressive thresholds
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// ── proposeSplit ──────────────────────────────────────────────────────────────
|
|
135
|
+
describe('proposeSplit', () => {
|
|
136
|
+
it('returns empty proposal when no files listed', () => {
|
|
137
|
+
const p = proposeSplit('task-001', []);
|
|
138
|
+
expect(p.subtasks).toHaveLength(0);
|
|
139
|
+
expect(p.notes).toContain('Nenhum arquivo listado');
|
|
140
|
+
});
|
|
141
|
+
it('groups by top-level directory', () => {
|
|
142
|
+
const p = proposeSplit('task-002', [
|
|
143
|
+
'src/auth/login.ts',
|
|
144
|
+
'src/auth/register.ts',
|
|
145
|
+
'src/users/profile.ts',
|
|
146
|
+
'tests/auth/login.test.ts',
|
|
147
|
+
]);
|
|
148
|
+
// 3 groups: src/auth, src/users, tests/auth
|
|
149
|
+
expect(p.subtasks).toHaveLength(3);
|
|
150
|
+
expect(p.subtasks.map((s) => s.id)).toEqual([
|
|
151
|
+
'task-002a',
|
|
152
|
+
'task-002b',
|
|
153
|
+
'task-002c',
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
it('splits overlarge groups by maxFilesPerSubtask', () => {
|
|
157
|
+
const files = Array.from({ length: 9 }, (_, i) => `src/auth/file${i}.ts`);
|
|
158
|
+
const p = proposeSplit('task-003', files, { maxFilesPerSubtask: 3 });
|
|
159
|
+
// 9 files / 3 per chunk = 3 chunks (all from same group)
|
|
160
|
+
expect(p.subtasks).toHaveLength(3);
|
|
161
|
+
expect(p.subtasks.every((s) => s.files.length <= 3)).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
it('assigns sequential letter suffixes', () => {
|
|
164
|
+
const p = proposeSplit('task-004', [
|
|
165
|
+
'a/one.ts',
|
|
166
|
+
'b/one.ts',
|
|
167
|
+
'c/one.ts',
|
|
168
|
+
'd/one.ts',
|
|
169
|
+
]);
|
|
170
|
+
const ids = p.subtasks.map((s) => s.id);
|
|
171
|
+
expect(ids[0]).toBe('task-004a');
|
|
172
|
+
expect(ids[1]).toBe('task-004b');
|
|
173
|
+
expect(ids[2]).toBe('task-004c');
|
|
174
|
+
expect(ids[3]).toBe('task-004d');
|
|
175
|
+
});
|
|
176
|
+
it('preserves files within each sub-task', () => {
|
|
177
|
+
const p = proposeSplit('task-005', [
|
|
178
|
+
'src/auth/a.ts',
|
|
179
|
+
'src/auth/b.ts',
|
|
180
|
+
'src/users/c.ts',
|
|
181
|
+
]);
|
|
182
|
+
const authSub = p.subtasks.find((s) => s.title.includes('src/auth'));
|
|
183
|
+
expect(authSub?.files).toEqual(['src/auth/a.ts', 'src/auth/b.ts']);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=refine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.test.js","sourceRoot":"","sources":["../../src/__tests__/refine.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,cAAc,GAEf,MAAM,iCAAiC,CAAC;AAEzC,KAAK,UAAU,WAAW;IACxB,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,GAAW,EAAE,OAAe;IAChE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChC,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,iFAAiF;AAEjF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,GAAW,CAAC;IAChB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IACH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,CAAC,GAAG,MAAM,qBAAqB,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;QACzD,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,SAAS,CACb,GAAG,EACH,4BAA4B,EAC5B;;;;;;;;;;;;CAYL,CACI,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvD,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,SAAS,CACb,GAAG,EACH,4BAA4B,EAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCL,CACI,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACvD,MAAM,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,mDAAmD;QACnD,MAAM,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,SAAS,CAAC,GAAG,EAAE,4BAA4B,EAAE,sCAAsC,CAAC,CAAC;QAC3F,MAAM,EAAE,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/E,MAAM,EAAE,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/E,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,SAAS,CAAC,GAAG,EAAE,4BAA4B,EAAE,4CAA4C,CAAC,CAAC;QACjG,MAAM,CAAC,GAAG,MAAM,qBAAqB,CAAC,UAAU,EAAE,GAAG,EAAE;YACrD,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE;SAC5C,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,oDAAoD;IACzF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE;YACjC,mBAAmB;YACnB,sBAAsB;YACtB,sBAAsB;YACtB,0BAA0B;SAC3B,CAAC,CAAC;QACH,4CAA4C;QAC5C,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1C,WAAW;YACX,WAAW;YACX,WAAW;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC;QACrE,yDAAyD;QACzD,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE;YACjC,UAAU;YACV,UAAU;YACV,UAAU;YACV,UAAU;SACX,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,GAAG,YAAY,CAAC,UAAU,EAAE;YACjC,eAAe;YACf,eAAe;YACf,gBAAgB;SACjB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/review.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { analyzeFile, isTestFile, runStaticAnalysis, } from '../utils/static-analyzer.js';
|
|
6
|
+
import { parseFilesFromSpec, runReview, } from '../utils/ReviewRunner.js';
|
|
7
|
+
// Temp dir helper — each test gets its own sandbox.
|
|
8
|
+
async function makeTempDir() {
|
|
9
|
+
return fs.mkdtemp(path.join(os.tmpdir(), 'dare-review-test-'));
|
|
10
|
+
}
|
|
11
|
+
async function writeFile(dir, rel, content) {
|
|
12
|
+
const abs = path.join(dir, rel);
|
|
13
|
+
await fs.ensureDir(path.dirname(abs));
|
|
14
|
+
await fs.writeFile(abs, content);
|
|
15
|
+
}
|
|
16
|
+
// ── isTestFile ────────────────────────────────────────────────────────────────
|
|
17
|
+
describe('isTestFile', () => {
|
|
18
|
+
it('matches *.test.ts', () => {
|
|
19
|
+
expect(isTestFile('src/foo.test.ts')).toBe(true);
|
|
20
|
+
expect(isTestFile('src/foo.spec.ts')).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
it('matches __tests__ directories', () => {
|
|
23
|
+
expect(isTestFile('src/__tests__/foo.ts')).toBe(true);
|
|
24
|
+
expect(isTestFile('src\\__tests__\\foo.ts')).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('matches Go/Python test conventions', () => {
|
|
27
|
+
expect(isTestFile('pkg/auth/auth_test.go')).toBe(true);
|
|
28
|
+
expect(isTestFile('tests/test_auth.py')).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it('rejects production files', () => {
|
|
31
|
+
expect(isTestFile('src/auth/login.ts')).toBe(false);
|
|
32
|
+
expect(isTestFile('src/controllers/users.go')).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
// ── parseFilesFromSpec ────────────────────────────────────────────────────────
|
|
36
|
+
describe('parseFilesFromSpec', () => {
|
|
37
|
+
it('extracts files from a CRIAR/MODIFICAR table', () => {
|
|
38
|
+
const md = `
|
|
39
|
+
## 3. ARQUIVOS
|
|
40
|
+
|
|
41
|
+
| Ação | Caminho | Descrição |
|
|
42
|
+
|------|---------|-----------|
|
|
43
|
+
| CRIAR | \`src/auth/login.ts\` | Login handler |
|
|
44
|
+
| MODIFICAR | \`src/routes.ts\` | Wire route |
|
|
45
|
+
| CRIAR | \`tests/auth.test.ts\` | Tests |
|
|
46
|
+
`;
|
|
47
|
+
expect(parseFilesFromSpec(md)).toEqual([
|
|
48
|
+
'src/auth/login.ts',
|
|
49
|
+
'src/routes.ts',
|
|
50
|
+
'tests/auth.test.ts',
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
it('accepts English actions too', () => {
|
|
54
|
+
const md = `
|
|
55
|
+
| Action | Path |
|
|
56
|
+
| CREATE | \`a.ts\` |
|
|
57
|
+
| MODIFY | \`b.ts\` |
|
|
58
|
+
| UPDATE | \`c.ts\` |
|
|
59
|
+
`;
|
|
60
|
+
expect(parseFilesFromSpec(md)).toEqual(['a.ts', 'b.ts', 'c.ts']);
|
|
61
|
+
});
|
|
62
|
+
it('de-duplicates paths', () => {
|
|
63
|
+
const md = `
|
|
64
|
+
| MODIFICAR | \`src/a.ts\` |
|
|
65
|
+
| MODIFICAR | \`src/a.ts\` |
|
|
66
|
+
`;
|
|
67
|
+
expect(parseFilesFromSpec(md)).toEqual(['src/a.ts']);
|
|
68
|
+
});
|
|
69
|
+
it('ignores rows without a backtick path', () => {
|
|
70
|
+
const md = `
|
|
71
|
+
| CRIAR | descrição sem path | x |
|
|
72
|
+
| MODIFICAR | \`src/real.ts\` | x |
|
|
73
|
+
`;
|
|
74
|
+
expect(parseFilesFromSpec(md)).toEqual(['src/real.ts']);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ── Static analyzer detectors ─────────────────────────────────────────────────
|
|
78
|
+
describe('static-analyzer: detectors', () => {
|
|
79
|
+
let tmp;
|
|
80
|
+
beforeEach(async () => {
|
|
81
|
+
tmp = await makeTempDir();
|
|
82
|
+
});
|
|
83
|
+
afterEach(async () => {
|
|
84
|
+
await fs.remove(tmp);
|
|
85
|
+
});
|
|
86
|
+
async function analyze(rel, content) {
|
|
87
|
+
await writeFile(tmp, rel, content);
|
|
88
|
+
return analyzeFile(path.join(tmp, rel), rel);
|
|
89
|
+
}
|
|
90
|
+
function kinds(report) {
|
|
91
|
+
return report.violations.map((v) => v.kind);
|
|
92
|
+
}
|
|
93
|
+
it('detects TODO/FIXME/XXX/HACK in comments', async () => {
|
|
94
|
+
const r = await analyze('src/a.ts', `// TODO: implement\nconst x = 1; // FIXME later\n// XXX broken\n/* HACK */`);
|
|
95
|
+
const found = kinds(r);
|
|
96
|
+
expect(found.filter((k) => k === 'todo-marker').length).toBeGreaterThanOrEqual(4);
|
|
97
|
+
});
|
|
98
|
+
it('ignores TODO inside string literals', async () => {
|
|
99
|
+
const r = await analyze('src/a.ts', `const msg = "TODO: not a real comment";\nconst real = 1;`);
|
|
100
|
+
expect(kinds(r)).not.toContain('todo-marker');
|
|
101
|
+
});
|
|
102
|
+
it('detects throw new Error("not implemented") and friends', async () => {
|
|
103
|
+
const r = await analyze('src/b.ts', `function x() { throw new Error('not implemented'); }\nfunction y() { throw new Error('todo'); }`);
|
|
104
|
+
const stubs = r.violations.filter((v) => v.kind === 'not-implemented-stub');
|
|
105
|
+
expect(stubs.length).toBeGreaterThanOrEqual(2);
|
|
106
|
+
});
|
|
107
|
+
it('detects Rust unimplemented!() and todo!()', async () => {
|
|
108
|
+
const r = await analyze('src/lib.rs', `fn a() { unimplemented!() }\nfn b() { todo!() }`);
|
|
109
|
+
expect(kinds(r)).toContain('not-implemented-stub');
|
|
110
|
+
});
|
|
111
|
+
it('detects Python raise NotImplementedError', async () => {
|
|
112
|
+
const r = await analyze('src/x.py', `def foo():\n raise NotImplementedError\n`);
|
|
113
|
+
expect(kinds(r)).toContain('not-implemented-stub');
|
|
114
|
+
});
|
|
115
|
+
it('detects empty function single-line (TS)', async () => {
|
|
116
|
+
const r = await analyze('src/c.ts', `function foo() {}\nconst bar = () => {};\nfunction baz() { /* real */ return 1; }`);
|
|
117
|
+
const empties = r.violations.filter((v) => v.kind === 'empty-function');
|
|
118
|
+
expect(empties.length).toBeGreaterThanOrEqual(1);
|
|
119
|
+
});
|
|
120
|
+
it('detects empty multi-line function (TS)', async () => {
|
|
121
|
+
const r = await analyze('src/d.ts', `function alpha() {\n}\nfunction beta() {\n const x = 1;\n return x;\n}`);
|
|
122
|
+
const empties = r.violations.filter((v) => v.kind === 'empty-function');
|
|
123
|
+
expect(empties.length).toBe(1);
|
|
124
|
+
});
|
|
125
|
+
it('detects Python def x(): pass', async () => {
|
|
126
|
+
const r = await analyze('src/e.py', `def foo():\n pass\n`);
|
|
127
|
+
expect(kinds(r)).toContain('empty-function');
|
|
128
|
+
});
|
|
129
|
+
it('detects phantom returns (only stmt is return null)', async () => {
|
|
130
|
+
const r = await analyze('src/f.ts', `function getUser(id: string) {\n return null;\n}\nfunction getOther() {\n const x = compute();\n return x;\n}`);
|
|
131
|
+
const phantoms = r.violations.filter((v) => v.kind === 'phantom-return');
|
|
132
|
+
expect(phantoms.length).toBe(1);
|
|
133
|
+
});
|
|
134
|
+
it('detects placeholder comments', async () => {
|
|
135
|
+
const r = await analyze('src/g.ts', `// implement later\n// stub\n# placeholder\n// fixme implement\nconst real = 1;`);
|
|
136
|
+
const placeholders = r.violations.filter((v) => v.kind === 'placeholder-comment');
|
|
137
|
+
expect(placeholders.length).toBeGreaterThanOrEqual(3);
|
|
138
|
+
});
|
|
139
|
+
it('detects production mocks (jest.fn, sinon.stub, vi.mock)', async () => {
|
|
140
|
+
const r = await analyze('src/h.ts', `const x = jest.fn();\nconst y = sinon.stub();\nvi.mock('foo');`);
|
|
141
|
+
const mocks = r.violations.filter((v) => v.kind === 'production-mock');
|
|
142
|
+
expect(mocks.length).toBeGreaterThanOrEqual(3);
|
|
143
|
+
});
|
|
144
|
+
it('does NOT flag mocks in test files', async () => {
|
|
145
|
+
const r = await analyze('src/h.test.ts', `const x = jest.fn();\nvi.mock('foo');`);
|
|
146
|
+
expect(r.isTestFile).toBe(true);
|
|
147
|
+
expect(kinds(r)).not.toContain('production-mock');
|
|
148
|
+
});
|
|
149
|
+
it('runs clean on a real-looking implementation', async () => {
|
|
150
|
+
const r = await analyze('src/auth/login.ts', `
|
|
151
|
+
import { hash } from 'crypto';
|
|
152
|
+
|
|
153
|
+
export async function login(email: string, password: string) {
|
|
154
|
+
if (!email || !password) {
|
|
155
|
+
throw new Error('email and password are required');
|
|
156
|
+
}
|
|
157
|
+
const user = await db.users.findOne({ email });
|
|
158
|
+
if (!user) return { ok: false, code: 401 };
|
|
159
|
+
const ok = await verify(user.passwordHash, password);
|
|
160
|
+
if (!ok) return { ok: false, code: 401 };
|
|
161
|
+
return { ok: true, token: signToken(user.id) };
|
|
162
|
+
}
|
|
163
|
+
`.trim());
|
|
164
|
+
expect(r.violations).toEqual([]);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
// ── runStaticAnalysis + runReview end-to-end ──────────────────────────────────
|
|
168
|
+
describe('runStaticAnalysis', () => {
|
|
169
|
+
let tmp;
|
|
170
|
+
beforeEach(async () => {
|
|
171
|
+
tmp = await makeTempDir();
|
|
172
|
+
});
|
|
173
|
+
afterEach(async () => {
|
|
174
|
+
await fs.remove(tmp);
|
|
175
|
+
});
|
|
176
|
+
it('scans multiple files in parallel', async () => {
|
|
177
|
+
await writeFile(tmp, 'src/a.ts', `function x() {} // empty`);
|
|
178
|
+
await writeFile(tmp, 'src/b.ts', `// TODO\nconst y = 1;`);
|
|
179
|
+
await writeFile(tmp, 'src/c.ts', `export const PI = 3.14;`);
|
|
180
|
+
const reports = await runStaticAnalysis(tmp, ['src/a.ts', 'src/b.ts', 'src/c.ts']);
|
|
181
|
+
expect(reports).toHaveLength(3);
|
|
182
|
+
expect(reports[0].violations.length).toBeGreaterThan(0);
|
|
183
|
+
expect(reports[1].violations.length).toBeGreaterThan(0);
|
|
184
|
+
expect(reports[2].violations).toEqual([]);
|
|
185
|
+
});
|
|
186
|
+
it('returns clean report for missing files', async () => {
|
|
187
|
+
const reports = await runStaticAnalysis(tmp, ['does/not/exist.ts']);
|
|
188
|
+
expect(reports[0].violations).toEqual([]);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe('runReview end-to-end', () => {
|
|
192
|
+
let tmp;
|
|
193
|
+
beforeEach(async () => {
|
|
194
|
+
tmp = await makeTempDir();
|
|
195
|
+
});
|
|
196
|
+
afterEach(async () => {
|
|
197
|
+
await fs.remove(tmp);
|
|
198
|
+
});
|
|
199
|
+
it('parses spec, scans listed files, fails on errors', async () => {
|
|
200
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-001.md', `
|
|
201
|
+
## 3. ARQUIVOS
|
|
202
|
+
|
|
203
|
+
| Ação | Caminho | Descrição |
|
|
204
|
+
|------|---------|-----------|
|
|
205
|
+
| CRIAR | \`src/foo.ts\` | Foo handler |
|
|
206
|
+
`);
|
|
207
|
+
await writeFile(tmp, 'src/foo.ts', `function foo() { throw new Error('not implemented'); }`);
|
|
208
|
+
const report = await runReview('task-001', { projectRoot: tmp });
|
|
209
|
+
expect(report.taskId).toBe('task-001');
|
|
210
|
+
expect(report.filesScanned).toEqual(['src/foo.ts']);
|
|
211
|
+
expect(report.failed).toBe(true);
|
|
212
|
+
expect(report.totals.errors).toBeGreaterThan(0);
|
|
213
|
+
});
|
|
214
|
+
it('passes when nothing is found', async () => {
|
|
215
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-002.md', `| MODIFICAR | \`src/clean.ts\` | x |`);
|
|
216
|
+
await writeFile(tmp, 'src/clean.ts', `export const X = 1;`);
|
|
217
|
+
const report = await runReview('task-002', { projectRoot: tmp });
|
|
218
|
+
expect(report.failed).toBe(false);
|
|
219
|
+
expect(report.totals.errors).toBe(0);
|
|
220
|
+
});
|
|
221
|
+
it('merges --from-agent semantic verdict', async () => {
|
|
222
|
+
await writeFile(tmp, 'DARE/EXECUTION/task-003.md', `| MODIFICAR | \`src/clean.ts\` | x |`);
|
|
223
|
+
await writeFile(tmp, 'src/clean.ts', `export const X = 1;`);
|
|
224
|
+
await writeFile(tmp, 'verdict.json', JSON.stringify({
|
|
225
|
+
passed: false,
|
|
226
|
+
unmetCriteria: ['Missing password regex'],
|
|
227
|
+
notes: 'Stub-free but spec not satisfied',
|
|
228
|
+
}));
|
|
229
|
+
const report = await runReview('task-003', {
|
|
230
|
+
projectRoot: tmp,
|
|
231
|
+
fromAgent: path.join(tmp, 'verdict.json'),
|
|
232
|
+
});
|
|
233
|
+
expect(report.semantic?.passed).toBe(false);
|
|
234
|
+
expect(report.failed).toBe(true); // semantic failure flips it
|
|
235
|
+
});
|
|
236
|
+
it('returns empty report when no files can be resolved', async () => {
|
|
237
|
+
const report = await runReview('task-ghost', { projectRoot: tmp });
|
|
238
|
+
expect(report.filesScanned).toHaveLength(0);
|
|
239
|
+
expect(report.failed).toBe(false);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
//# sourceMappingURL=review.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.test.js","sourceRoot":"","sources":["../../src/__tests__/review.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/update.test.ts"],"names":[],"mappings":""}
|