Skip to content

Commit 886b8bb

Browse files
committed
improvement(audits): fail closed on missing baselines, write nothing on refused updates, flag utils/utils.ts
1 parent f1a92ad commit 886b8bb

3 files changed

Lines changed: 71 additions & 24 deletions

File tree

‎scripts/check-explicit-any.ts‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,21 @@ function total(counts: Counts): number {
8787
}
8888

8989
const current = collect()
90-
const baseline: Baseline = existsSync(BASELINE)
91-
? (JSON.parse(readFileSync(BASELINE, 'utf8')) as Baseline)
92-
: current
90+
/**
91+
* The committed baseline. A missing file fails closed: restore it from git. `--update --init`
92+
* is the only way to create one, and it accepts every current hit.
93+
*/
94+
function readBaseline(): Baseline {
95+
if (existsSync(BASELINE)) return JSON.parse(readFileSync(BASELINE, 'utf8')) as Baseline
96+
if (process.argv.includes('--update') && process.argv.includes('--init')) return current
97+
console.error(
98+
`✗ ${path.relative(ROOT, BASELINE)} is missing. Restore it from git; ` +
99+
'create a new one only with --update --init.'
100+
)
101+
process.exit(1)
102+
}
103+
104+
const baseline = readBaseline()
93105

94106
/** Per-file counts clamped to the baseline, so an update can only lower them. */
95107
function shrunkTo(after: Counts, before: Counts): Counts {
@@ -105,11 +117,6 @@ if (process.argv.includes('--update')) {
105117
explicitAny: sorted(shrunkTo(current.explicitAny, baseline.explicitAny ?? {})),
106118
nonNullAssertion: sorted(shrunkTo(current.nonNullAssertion, baseline.nonNullAssertion ?? {})),
107119
}
108-
writeFileSync(BASELINE, `${JSON.stringify(next, null, 2)}\n`)
109-
console.log(
110-
`Wrote ${path.relative(ROOT, BASELINE)}: ${total(next.explicitAny)} explicit any, ` +
111-
`${total(next.nonNullAssertion)} non-null assertions`
112-
)
113120
const raised = (Object.keys(METRICS) as Metric[]).flatMap((metric) =>
114121
Object.entries(current[metric])
115122
.filter(([file, count]) => count > (baseline[metric]?.[file] ?? 0))
@@ -121,8 +128,14 @@ if (process.argv.includes('--update')) {
121128
if (raised.length) {
122129
console.error(`✗ refused to raise the baseline for ${raised.length} file(s); fix them instead:`)
123130
console.error(raised.sort().join('\n'))
131+
process.exit(1)
124132
}
125-
process.exit(raised.length ? 1 : 0)
133+
writeFileSync(BASELINE, `${JSON.stringify(next, null, 2)}\n`)
134+
console.log(
135+
`Wrote ${path.relative(ROOT, BASELINE)}: ${total(next.explicitAny)} explicit any, ` +
136+
`${total(next.nonNullAssertion)} non-null assertions`
137+
)
138+
process.exit(0)
126139
}
127140

128141
let regressed = 0

‎scripts/check-file-names.ts‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,15 @@ function check(file: string): Violation[] {
151151

152152
const parent = segments[segments.length - 2]
153153
const [stem, ...suffixes] = name.split('.')
154-
for (const suffix of ROLE_FOLDERS[parent] ?? []) {
154+
const roleSuffixes = ROLE_FOLDERS[parent] ?? []
155+
if (roleSuffixes.some((suffix) => stem === suffix.slice(1))) {
156+
violations.push({
157+
rule: 'redundant-suffix',
158+
file,
159+
expected: `<what-it-does>.${suffixes.join('.')}`,
160+
})
161+
}
162+
for (const suffix of roleSuffixes) {
155163
if (stem.endsWith(suffix) && stem.length > suffix.length) {
156164
const expected = [stem.slice(0, -suffix.length), ...suffixes].join('.')
157165
violations.push({ rule: 'redundant-suffix', file, expected })
@@ -187,21 +195,34 @@ const violations = sourceFiles().flatMap(check)
187195
const byKey = new Map(violations.map((violation) => [key(violation), violation]))
188196
const current = [...byKey.keys()].sort()
189197

190-
const baseline = new Set<string>(
191-
existsSync(BASELINE) ? JSON.parse(readFileSync(BASELINE, 'utf8')) : current
192-
)
198+
/**
199+
* The committed baseline. A missing file fails closed: restore it from git. `--update --init`
200+
* is the only way to create one, and it accepts every current violation.
201+
*/
202+
function readBaseline(current: string[]): string[] {
203+
if (existsSync(BASELINE)) return JSON.parse(readFileSync(BASELINE, 'utf8'))
204+
if (process.argv.includes('--update') && process.argv.includes('--init')) return current
205+
console.error(
206+
`✗ ${path.relative(ROOT, BASELINE)} is missing. Restore it from git; ` +
207+
'create a new one only with --update --init.'
208+
)
209+
process.exit(1)
210+
}
211+
212+
const baseline = new Set<string>(readBaseline(current))
193213
const added = current.filter((entry) => !baseline.has(entry))
194214

195215
if (process.argv.includes('--update')) {
196-
// Shrink-only: drop fixed entries, never admit a new one.
216+
// Shrink-only: drop fixed entries, never admit a new one, and write nothing if refusing.
197217
const kept = current.filter((entry) => baseline.has(entry))
198-
writeFileSync(BASELINE, `${JSON.stringify(kept, null, 2)}\n`)
199-
console.log(`Wrote ${kept.length} baseline entries to ${path.relative(ROOT, BASELINE)}`)
200218
for (const entry of added) {
201219
const violation = byKey.get(entry) as Violation
202220
console.error(`✗ not baselined — rename: ${violation.file} → ${violation.expected}`)
203221
}
204-
process.exit(added.length ? 1 : 0)
222+
if (added.length) process.exit(1)
223+
writeFileSync(BASELINE, `${JSON.stringify(kept, null, 2)}\n`)
224+
console.log(`Wrote ${kept.length} baseline entries to ${path.relative(ROOT, BASELINE)}`)
225+
process.exit(0)
205226
}
206227

207228
const currentSet = new Set(current)

‎scripts/check-unused-exports.ts‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,34 @@ if (strict.length) {
112112

113113
const current = [...kindByEntry.keys()].sort()
114114

115-
const baseline = new Set<string>(
116-
existsSync(BASELINE) ? JSON.parse(readFileSync(BASELINE, 'utf8')) : current
117-
)
115+
/**
116+
* The committed baseline. A missing file fails closed: restore it from git. `--update --init`
117+
* is the only way to create one, and it accepts every current violation.
118+
*/
119+
function readBaseline(current: string[]): string[] {
120+
if (existsSync(BASELINE)) return JSON.parse(readFileSync(BASELINE, 'utf8'))
121+
if (process.argv.includes('--update') && process.argv.includes('--init')) return current
122+
console.error(
123+
`✗ ${path.relative(ROOT, BASELINE)} is missing. Restore it from git; ` +
124+
'create a new one only with --update --init.'
125+
)
126+
process.exit(1)
127+
}
128+
129+
const baseline = new Set<string>(readBaseline(current))
118130
const added = current.filter((entry) => !baseline.has(entry))
119131

120132
if (process.argv.includes('--update')) {
121-
// Shrink-only: drop fixed entries, never admit a new one.
133+
// Shrink-only: drop fixed entries, never admit a new one, and write nothing if refusing.
122134
const kept = current.filter((entry) => baseline.has(entry))
123-
writeFileSync(BASELINE, `${JSON.stringify(kept, null, 2)}\n`)
124-
console.log(`Wrote ${kept.length} baseline entries to ${path.relative(ROOT, BASELINE)}`)
125135
if (added.length) {
126136
console.error(`✗ refused to baseline ${added.length} new unused export(s); fix them instead:`)
127137
for (const entry of added) console.error(` ${entry}`)
138+
process.exit(1)
128139
}
129-
process.exit(strict.length || added.length ? 1 : 0)
140+
writeFileSync(BASELINE, `${JSON.stringify(kept, null, 2)}\n`)
141+
console.log(`Wrote ${kept.length} baseline entries to ${path.relative(ROOT, BASELINE)}`)
142+
process.exit(strict.length ? 1 : 0)
130143
}
131144

132145
const currentSet = new Set(current)

0 commit comments

Comments
 (0)