Skip to content

Commit 7f18758

Browse files
frankieyanclaude
andauthored
feat: report error decreases in --check-files flag (#36)
* feat: report error decreases in --check-files flag Replace getErrorIncreases with getErrorChanges to track both increases and decreases. When errors decrease, display an informational message to help developers verify fixes have succeeded. Closes #35 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: report decreases before increases so users see progress Move the decrease reporting block before the increase check in checkErrorChanges(). Previously, if there were any error increases, exitWithError() would terminate the process immediately, preventing users from seeing their successful fixes (decreases). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: use consistent newline characters in error message Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add blank line between decrease and increase messages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: simplify getErrorChanges with for...of loop Replace reduce pattern with a cleaner for...of loop since we're just building up a mutable object. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: document error decrease reporting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 34b00f8 commit 7f18758

4 files changed

Lines changed: 91 additions & 46 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ npx @doist/react-compiler-tracker --overwrite
7474

7575
### `--stage-record-file <file1> <file2> ...`
7676

77-
Checks the provided files and updates the records. Exits with code 1 if errors increase (preventing the commit), otherwise updates the records file for the checked files. Deleted files are automatically removed from the records.
77+
Checks the provided files and updates the records. Exits with code 1 if errors increase (preventing the commit), otherwise updates the records file for the checked files. Reports when errors decrease, celebrating your progress. Deleted files are automatically removed from the records.
7878

7979
```bash
8080
npx @doist/react-compiler-tracker --stage-record-file src/components/Button.tsx src/hooks/useData.ts
@@ -84,7 +84,7 @@ If no files are provided, exits cleanly with a success message.
8484

8585
### `--check-files <file1> <file2> ...`
8686

87-
Checks specific files without updating records. Exits with code 1 if checked files show increased error counts (or new errors), or if any provided file does not exist. Primarily for CI to ensure PRs don't introduce new compiler errors.
87+
Checks specific files without updating records. Exits with code 1 if checked files show increased error counts (or new errors), or if any provided file does not exist. Reports when errors decrease, celebrating your progress. Primarily for CI to ensure PRs don't introduce new compiler errors.
8888

8989
```bash
9090
npx @doist/react-compiler-tracker --check-files src/components/Button.tsx src/hooks/useData.ts

src/index.mts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ async function runStageRecords({
191191
customReactCompilerLogger: customReactCompilerLogger,
192192
})
193193

194-
const records = exitIfErrorsIncreased({ filePaths: existingFilePaths, recordsFilePath })
194+
const records = checkErrorChanges({ filePaths: existingFilePaths, recordsFilePath })
195195

196196
//
197197
// Update and stage records file (includes deleted files so they get removed from records)
@@ -244,7 +244,7 @@ async function runCheckFiles({
244244
customReactCompilerLogger: customReactCompilerLogger,
245245
})
246246

247-
exitIfErrorsIncreased({ filePaths, recordsFilePath })
247+
checkErrorChanges({ filePaths, recordsFilePath })
248248

249249
console.log('✅ No new React Compiler errors in checked files')
250250
}
@@ -299,28 +299,42 @@ function getErrorCount() {
299299
/**
300300
* Compare error changes between the existing records and errors captured during this session in `compilerErrors`.
301301
* If errors have increased, exit with an error message.
302+
* If errors have decreased, report the good news.
302303
*/
303-
function exitIfErrorsIncreased({
304+
function checkErrorChanges({
304305
filePaths,
305306
recordsFilePath,
306307
}: {
307308
filePaths: string[]
308309
recordsFilePath: string
309310
}) {
310311
const records = recordsFile.load(recordsFilePath)
311-
const errorIncreases = recordsFile.getErrorIncreases({
312+
const { increases, decreases } = recordsFile.getErrorChanges({
312313
filePaths,
313314
existingRecords: records?.files ?? {},
314315
newRecords: Object.fromEntries(compilerErrors.entries()),
315316
})
316317

317-
const errorEntries = Object.entries(errorIncreases)
318+
const increaseEntries = Object.entries(increases)
318319

319-
if (errorEntries.length) {
320-
const errorList = errorEntries.map(([filePath, count]) => ` • ${filePath}: +${count}`)
320+
// Report decreases first so users see their progress even if there are also increases
321+
const decreaseEntries = Object.entries(decreases)
322+
if (decreaseEntries.length) {
323+
const decreaseList = decreaseEntries.map(
324+
([filePath, count]) => ` ${filePath}: -${count}`,
325+
)
326+
console.log(`🎉 React Compiler errors have decreased in:\n${decreaseList.join('\n')}`)
327+
if (increaseEntries.length) {
328+
console.log() // blank line separator
329+
}
330+
}
331+
332+
// Report increases (exit with error)
333+
if (increaseEntries.length) {
334+
const errorList = increaseEntries.map(([filePath, count]) => ` ${filePath}: +${count}`)
321335
322336
exitWithError(
323-
`React Compiler errors have increased in:\r\n${errorList.join('\r\n')}\r\n\r\nPlease fix the errors and run the command again.`,
337+
`React Compiler errors have increased in:\n${errorList.join('\n')}\n\nPlease fix the errors and run the command again.`,
324338
)
325339
}
326340

src/records-file.mts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,28 @@ function load(recordsPath: string) {
3232
return null
3333
}
3434

35-
function getErrorIncreases({
35+
type ErrorChanges = {
36+
increases: Record<string, number>
37+
decreases: Record<string, number>
38+
}
39+
40+
function getErrorChanges({
3641
filePaths,
3742
existingRecords,
3843
newRecords,
3944
}: {
4045
filePaths: string[]
4146
existingRecords: Records['files']
4247
newRecords: Records['files']
43-
}) {
44-
return filePaths.reduce<Record<string, number>>((errorIncreases, filePath) => {
45-
const existingErrors: FileErrors | undefined = existingRecords[filePath]
46-
const newErrors: FileErrors | undefined = newRecords[filePath]
48+
}): ErrorChanges {
49+
const changes: ErrorChanges = { increases: {}, decreases: {} }
50+
51+
for (const filePath of filePaths) {
52+
const existingErrors = existingRecords[filePath]
53+
const newErrors = newRecords[filePath]
4754

4855
if (!existingErrors && !newErrors) {
49-
return errorIncreases
56+
continue
5057
}
5158

5259
const existingErrorCount = Object.values(existingErrors ?? {}).reduce(
@@ -58,16 +65,14 @@ function getErrorIncreases({
5865
0,
5966
)
6067

61-
if (newErrorCount <= existingErrorCount) {
62-
return errorIncreases
68+
if (newErrorCount > existingErrorCount) {
69+
changes.increases[filePath] = newErrorCount - existingErrorCount
70+
} else if (newErrorCount < existingErrorCount) {
71+
changes.decreases[filePath] = existingErrorCount - newErrorCount
6372
}
73+
}
6474

65-
const newErrorIncreases = errorIncreases
66-
newErrorIncreases[filePath] =
67-
newErrorCount > existingErrorCount ? newErrorCount - existingErrorCount : 0
68-
69-
return newErrorIncreases
70-
}, {})
75+
return changes
7176
}
7277

7378
function save({
@@ -117,4 +122,4 @@ function stage(recordsPath: string) {
117122
execSync(`git add ${recordsPath}`, { stdio: 'inherit' })
118123
}
119124

120-
export { type FileErrors, getErrorIncreases, load, type Records, save, stage }
125+
export { type ErrorChanges, type FileErrors, getErrorChanges, load, type Records, save, stage }

src/records-file.test.mts

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { afterEach, describe, expect, it, vi } from 'vitest'
2-
import { getErrorIncreases, load, save } from './records-file.mjs'
2+
import { getErrorChanges, load, save } from './records-file.mjs'
33

44
vi.mock('node:fs', () => ({
55
existsSync: vi.fn(),
@@ -17,59 +17,71 @@ afterEach(() => {
1717
vi.clearAllMocks()
1818
})
1919

20-
describe('getErrorIncreases', () => {
21-
it('returns empty object when no errors in either records', () => {
22-
const result = getErrorIncreases({
20+
describe('getErrorChanges', () => {
21+
it('returns empty increases/decreases when no errors in either records', () => {
22+
const result = getErrorChanges({
2323
filePaths: ['src/index.ts'],
2424
existingRecords: {},
2525
newRecords: {},
2626
})
2727

28-
expect(result).toEqual({})
28+
expect(result).toEqual({ increases: {}, decreases: {} })
2929
})
3030

31-
it('returns empty object when new errors are less than or equal to existing', () => {
32-
const result = getErrorIncreases({
31+
it('detects increased errors for a file', () => {
32+
const result = getErrorChanges({
3333
filePaths: ['src/index.ts'],
3434
existingRecords: {
35-
'src/index.ts': { CompileError: 2 },
35+
'src/index.ts': { CompileError: 1 },
3636
},
3737
newRecords: {
38-
'src/index.ts': { CompileError: 1 },
38+
'src/index.ts': { CompileError: 3 },
3939
},
4040
})
4141

42-
expect(result).toEqual({})
42+
expect(result).toEqual({ increases: { 'src/index.ts': 2 }, decreases: {} })
4343
})
4444

45-
it('detects increased errors for a file', () => {
46-
const result = getErrorIncreases({
45+
it('detects decreased errors for a file', () => {
46+
const result = getErrorChanges({
4747
filePaths: ['src/index.ts'],
4848
existingRecords: {
49-
'src/index.ts': { CompileError: 1 },
49+
'src/index.ts': { CompileError: 5 },
5050
},
5151
newRecords: {
52-
'src/index.ts': { CompileError: 3 },
52+
'src/index.ts': { CompileError: 2 },
5353
},
5454
})
5555

56-
expect(result).toEqual({ 'src/index.ts': 2 })
56+
expect(result).toEqual({ increases: {}, decreases: { 'src/index.ts': 3 } })
5757
})
5858

5959
it('detects new errors for a file with no previous records', () => {
60-
const result = getErrorIncreases({
60+
const result = getErrorChanges({
6161
filePaths: ['src/index.ts'],
6262
existingRecords: {},
6363
newRecords: {
6464
'src/index.ts': { CompileError: 2 },
6565
},
6666
})
6767

68-
expect(result).toEqual({ 'src/index.ts': 2 })
68+
expect(result).toEqual({ increases: { 'src/index.ts': 2 }, decreases: {} })
69+
})
70+
71+
it('detects all errors fixed - file had errors, now has none', () => {
72+
const result = getErrorChanges({
73+
filePaths: ['src/index.ts'],
74+
existingRecords: {
75+
'src/index.ts': { CompileError: 3, CompileSkip: 2 },
76+
},
77+
newRecords: {},
78+
})
79+
80+
expect(result).toEqual({ increases: {}, decreases: { 'src/index.ts': 5 } })
6981
})
7082

7183
it('sums all error types when comparing', () => {
72-
const result = getErrorIncreases({
84+
const result = getErrorChanges({
7385
filePaths: ['src/index.ts'],
7486
existingRecords: {
7587
'src/index.ts': { CompileError: 1, CompileSkip: 1 },
@@ -79,11 +91,11 @@ describe('getErrorIncreases', () => {
7991
},
8092
})
8193

82-
expect(result).toEqual({ 'src/index.ts': 3 })
94+
expect(result).toEqual({ increases: { 'src/index.ts': 3 }, decreases: {} })
8395
})
8496

8597
it('only checks files in the provided filePaths', () => {
86-
const result = getErrorIncreases({
98+
const result = getErrorChanges({
8799
filePaths: ['src/index.ts'],
88100
existingRecords: {
89101
'src/other.ts': { CompileError: 0 },
@@ -93,7 +105,21 @@ describe('getErrorIncreases', () => {
93105
},
94106
})
95107

96-
expect(result).toEqual({})
108+
expect(result).toEqual({ increases: {}, decreases: {} })
109+
})
110+
111+
it('returns empty for unchanged error counts', () => {
112+
const result = getErrorChanges({
113+
filePaths: ['src/index.ts'],
114+
existingRecords: {
115+
'src/index.ts': { CompileError: 2 },
116+
},
117+
newRecords: {
118+
'src/index.ts': { CompileError: 2 },
119+
},
120+
})
121+
122+
expect(result).toEqual({ increases: {}, decreases: {} })
97123
})
98124
})
99125

0 commit comments

Comments
 (0)