Skip to content

Commit 08469b0

Browse files
committed
fix(types): narrow indexed-access + side-effect imports
Resolve 189 TS errors surfaced by the canonical fleet tsconfig.base adoption (concrete config now sets allowImportingTsExtensions, declaration, module, noEmit; base contributes noUncheckedIndexedAccess + noUncheckedSideEffectImports). Techniques: - Bounded array indexing in `for (let i = 0; i < length; i += 1)` loops: add `!` non-null assertion on `arr[i]` reads — the loop bound makes the access provably in-range, the assertion just teaches the checker. - Two real bugs caught by the type widening: - check-consistency.mts: `Set` indexed as if it were an array (`categories[i]` on `Set<string>`) — switched to `for...of`. - check-patch-format.mts / validate-cache-versions.mts: same Set indexing shape — switched to `for...of`. No `as` casts, no `@ts-ignore`, no API surface changes.
1 parent 4605f16 commit 08469b0

16 files changed

Lines changed: 65 additions & 65 deletions

scripts/bump-cache-version.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export async function bumpAll(): Promise<BumpResult[]> {
4747

4848
const results: BumpResult[] = []
4949
for (let i = 0, { length } = packages; i < length; i += 1) {
50-
const pkg = packages[i]
50+
const pkg = packages[i]!
5151
const result = await bumpCacheVersion(pkg)
5252
results.push(result)
5353
}

scripts/check-cascade-completeness.mts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export function collectDockerfileCopies(): Finding[] {
129129
withFileTypes: true,
130130
})
131131
for (let i = 0, { length } = packages; i < length; i += 1) {
132-
const pkgEntry = packages[i]
132+
const pkgEntry = packages[i]!
133133
if (!pkgEntry.isDirectory()) {
134134
continue
135135
}
@@ -160,7 +160,7 @@ export function collectDockerfileCopies(): Finding[] {
160160
continue
161161
}
162162
for (let i = 0, { length } = dockerFiles; i < length; i += 1) {
163-
const df = dockerFiles[i]
163+
const df = dockerFiles[i]!
164164
const dfPath = path.join(dockerDir, df)
165165
let contents: string
166166
try {
@@ -183,7 +183,7 @@ export function collectDockerfileCopies(): Finding[] {
183183
// Last token is the destination; everything else is a source.
184184
const sources = tokens.slice(0, -1)
185185
for (let i2 = 0, { length } = sources; i2 < length; i2 += 1) {
186-
const src = sources[i2]
186+
const src = sources[i2]!
187187
// Skip variable interpolations / quoted anomalies — out of scope.
188188
if (src.includes('${') || src.includes('"') || src === '.') {
189189
continue
@@ -249,7 +249,7 @@ export function collectMakefileIncludes(): Finding[] {
249249
withFileTypes: true,
250250
})
251251
for (let i = 0, { length } = packages; i < length; i += 1) {
252-
const pkgEntry = packages[i]
252+
const pkgEntry = packages[i]!
253253
if (!pkgEntry.isDirectory()) {
254254
continue
255255
}
@@ -261,7 +261,7 @@ export function collectMakefileIncludes(): Finding[] {
261261
continue
262262
}
263263
for (let i = 0, { length } = files; i < length; i += 1) {
264-
const file = files[i]
264+
const file = files[i]!
265265
const mkPath = path.join(pkgDir, file)
266266
let contents: string
267267
try {
@@ -324,7 +324,7 @@ export function collectTypeScriptImports(): Finding[] {
324324
return out
325325
}
326326
for (let i = 0, { length } = entries; i < length; i += 1) {
327-
const entry = entries[i]
327+
const entry = entries[i]!
328328
if (COLLECT_TS_IMPORTS_SKIP_DIRS.has(entry.name)) {
329329
continue
330330
}
@@ -342,7 +342,7 @@ export function collectTypeScriptImports(): Finding[] {
342342
}
343343
const files = walk(path.join(MONOREPO_ROOT, 'packages'))
344344
for (let i = 0, { length } = files; i < length; i += 1) {
345-
const file = files[i]
345+
const file = files[i]!
346346
let contents: string
347347
try {
348348
contents = readFileSync(file, 'utf8')
@@ -526,7 +526,7 @@ async function main(): Promise<void> {
526526
const seen = new Set<string>()
527527
const deduped: Finding[] = []
528528
for (let i = 0, { length } = surviving; i < length; i += 1) {
529-
const f = surviving[i]
529+
const f = surviving[i]!
530530
const key = `${f.consumer}|${f.gap}|${f.missingPath}`
531531
if (seen.has(key)) {
532532
continue
@@ -555,7 +555,7 @@ async function main(): Promise<void> {
555555
)
556556
}
557557
for (let i = 0, { length } = deduped; i < length; i += 1) {
558-
const f = deduped[i]
558+
const f = deduped[i]!
559559
printFinding(f, opts)
560560
}
561561
if (!opts.json) {

scripts/check-consistency.mts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export async function discoverPackages(): Promise<PackageInfo[]> {
258258
const packages: PackageInfo[] = []
259259

260260
for (let i = 0, { length } = entries; i < length; i += 1) {
261-
const entry = entries[i]
261+
const entry = entries[i]!
262262
if (!entry.isDirectory()) {
263263
continue
264264
}
@@ -293,11 +293,11 @@ export async function checkRequiredFiles(
293293
log('\n[1/8] Checking required files...', colors.blue)
294294

295295
for (let i = 0, { length } = packages; i < length; i += 1) {
296-
const pkg = packages[i]
296+
const pkg = packages[i]!
297297
const requiredFiles: string[] = ['package.json', 'README.md']
298298

299299
for (let i = 0, { length } = requiredFiles; i < length; i += 1) {
300-
const file = requiredFiles[i]
300+
const file = requiredFiles[i]!
301301
const filePath = path.join(pkg.path, file)
302302
if (!existsSync(filePath)) {
303303
reportIssue(
@@ -338,7 +338,7 @@ export async function checkVitestConfig(
338338
)
339339

340340
for (let i = 0, { length } = vitestPackages; i < length; i += 1) {
341-
const pkg = vitestPackages[i]
341+
const pkg = vitestPackages[i]!
342342
const configPath = path.join(pkg.path, 'vitest.config.mts')
343343
const config = await fs.readFile(configPath, 'utf8')
344344

@@ -396,7 +396,7 @@ export async function checkTestScripts(packages: PackageInfo[]): Promise<void> {
396396
}
397397

398398
for (let i = 0, { length } = packages; i < length; i += 1) {
399-
const pkg = packages[i]
399+
const pkg = packages[i]!
400400
const { scripts } = pkg.pkgJson
401401

402402
if (!scripts || !scripts['test']) {
@@ -438,7 +438,7 @@ export async function checkCoverageScripts(
438438
const jsPackages = packages.filter(pkg => !C_PACKAGES.has(pkg.name))
439439

440440
for (let i = 0, { length } = jsPackages; i < length; i += 1) {
441-
const pkg = jsPackages[i]
441+
const pkg = jsPackages[i]!
442442
const { devDependencies, scripts } = pkg.pkgJson
443443

444444
// Check for cover script (standardized name across the workspace).
@@ -563,7 +563,7 @@ export async function checkBuildOutputStructure(
563563
log('[6/8] Checking build output structure...', colors.blue)
564564

565565
for (let i = 0, { length } = packages; i < length; i += 1) {
566-
const pkg = packages[i]
566+
const pkg = packages[i]!
567567
const buildDir = path.join(pkg.path, 'build')
568568

569569
if (!existsSync(buildDir)) {
@@ -599,7 +599,7 @@ export async function checkBuildOutputStructure(
599599
// Fall back to per-platform subdirs (binsuite, wasm, and native-addon styles).
600600
const entries = await fs.readdir(modeDir, { withFileTypes: true })
601601
for (let i = 0, { length } = entries; i < length; i += 1) {
602-
const entry = entries[i]
602+
const entry = entries[i]!
603603
if (!entry.isDirectory()) {
604604
continue
605605
}
@@ -651,7 +651,7 @@ export async function checkPackageJsonStructure(
651651
log('[7/8] Checking package.json structure...', colors.blue)
652652

653653
for (let i = 0, { length } = packages; i < length; i += 1) {
654-
const pkg = packages[i]
654+
const pkg = packages[i]!
655655
const { description, license, name, scripts, type, version } = pkg.pkgJson
656656
const pkgJsonPath = path.join(pkg.path, 'package.json')
657657

@@ -777,7 +777,7 @@ export async function checkWorkspaceDependencies(
777777
log('[8/8] Checking workspace dependencies...', colors.blue)
778778

779779
for (let i = 0, { length } = packages; i < length; i += 1) {
780-
const pkg = packages[i]
780+
const pkg = packages[i]!
781781
const { dependencies = {}, devDependencies = {} } = pkg.pkgJson
782782
const allDeps = { ...dependencies, ...devDependencies }
783783
const pkgJsonPath = path.join(pkg.path, 'package.json')
@@ -847,7 +847,7 @@ export function collectPatterns(packages: PackageInfo[]): void {
847847
patternStats.total = packages.length
848848

849849
for (let i = 0, { length } = packages; i < length; i += 1) {
850-
const pkg = packages[i]
850+
const pkg = packages[i]!
851851
// Collect script patterns
852852
if (pkg.pkgJson.scripts) {
853853
// oxlint-disable-next-line socket/prefer-cached-for-loop -- loop variable is destructured
@@ -1100,7 +1100,7 @@ export function displaySuggestions(suggestions: Suggestion[]): void {
11001100
log('='.repeat(60), colors.bright)
11011101

11021102
for (let i = 0, { length } = suggestions; i < length; i += 1) {
1103-
const suggestion = suggestions[i]
1103+
const suggestion = suggestions[i]!
11041104
const confidenceColor =
11051105
suggestion.level === 'HIGH' || suggestion.level === 'VERY HIGH'
11061106
? colors.green
@@ -1139,7 +1139,7 @@ export async function executeFixes(): Promise<void> {
11391139
log('='.repeat(60), colors.bright)
11401140

11411141
for (let i = 0, { length } = fixableIssues; i < length; i += 1) {
1142-
const issue = fixableIssues[i]
1142+
const issue = fixableIssues[i]!
11431143
if (CLI_FLAGS.dryRun) {
11441144
log('\n[DRY RUN] Would fix:', colors.yellow)
11451145
log(` ${issue.file}`, colors.blue)
@@ -1191,7 +1191,7 @@ export async function executeFixes(): Promise<void> {
11911191
log(`Successfully fixed ${fixedIssues.length} issue(s)`, colors.green)
11921192

11931193
for (let i = 0, { length } = fixedIssues; i < length; i += 1) {
1194-
const fixed = fixedIssues[i]
1194+
const fixed = fixedIssues[i]!
11951195
log(` ✓ ${fixed.file}`, colors.green)
11961196
}
11971197
}
@@ -1257,8 +1257,8 @@ async function main(): Promise<void> {
12571257
...issues.info.map(i => i.category),
12581258
])
12591259

1260-
for (let i = 0, { length } = categories; i < length; i += 1) {
1261-
const category = categories[i]
1260+
// oxlint-disable-next-line socket/prefer-cached-for-loop -- iterable is a Set (not array-indexed)
1261+
for (const category of categories) {
12621262
const categoryIssues = {
12631263
error: issues.error.filter(i => i.category === category),
12641264
info: issues.info.filter(i => i.category === category),

scripts/check-mirror-docs.mts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export function walk(
127127
continue
128128
}
129129
for (let i = 0, { length } = entries; i < length; i += 1) {
130-
const entry = entries[i]
130+
const entry = entries[i]!
131131
const full = path.join(dir, entry.name)
132132
if (entry.isDirectory()) {
133133
queue.push(full)
@@ -153,7 +153,7 @@ export function collectOrphanDocs(): Finding[] {
153153
const docs = walk(DOCS_ROOT, r => r.endsWith('.md'))
154154
const findings: Finding[] = []
155155
for (let i = 0, { length } = docs; i < length; i += 1) {
156-
const docRel = docs[i]
156+
const docRel = docs[i]!
157157
// Doc naming convention: trim the trailing ".md" — the remaining
158158
// path (e.g. "lib/smol-http.js" or "lib/internal/.../version_subset.js")
159159
// is the expected source file name. Per CLAUDE.md, the JS extension
@@ -285,7 +285,7 @@ async function main(): Promise<void> {
285285
)
286286
}
287287
for (let i = 0, { length } = surviving; i < length; i += 1) {
288-
const f = surviving[i]
288+
const f = surviving[i]!
289289
printFinding(f, opts)
290290
}
291291
if (!opts.json) {

scripts/check-patch-format.mts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export function collectMultiplePatchesPerFileViolations(
116116
// and accumulate.
117117
const fileToPatches = new Map<string, string[]>()
118118
for (let i = 0, { length } = files; i < length; i += 1) {
119-
const patchName = files[i]
119+
const patchName = files[i]!
120120
const abs = path.join(dir, patchName)
121121
let content
122122
try {
@@ -134,8 +134,8 @@ export function collectMultiplePatchesPerFileViolations(
134134
minusFiles.add(match[1]!)
135135
}
136136
}
137-
for (let i = 0, { length } = minusFiles; i < length; i += 1) {
138-
const f = minusFiles[i]
137+
// oxlint-disable-next-line socket/prefer-cached-for-loop -- iterable is a Set (not array-indexed)
138+
for (const f of minusFiles) {
139139
const list = fileToPatches.get(f) ?? []
140140
list.push(patchName)
141141
fileToPatches.set(f, list)
@@ -179,7 +179,7 @@ export function collectNumberGapViolations(dir: string): Violation[] {
179179
const files = readdirSync(dir).filter(f => f.endsWith('.patch'))
180180
const numbered: Array<{ name: string; num: number }> = []
181181
for (let i = 0, { length } = files; i < length; i += 1) {
182-
const name = files[i]
182+
const name = files[i]!
183183
const num = numericPrefix(name)
184184
if (num !== undefined) {
185185
numbered.push({ name, num })
@@ -628,7 +628,7 @@ async function main(): Promise<void> {
628628
const allViolations: Violation[] = []
629629
let patchesScanned = 0
630630
for (let i = 0, { length } = PATCH_ROOTS; i < length; i += 1) {
631-
const root = PATCH_ROOTS[i]
631+
const root = PATCH_ROOTS[i]!
632632
const absRoot = path.join(MONOREPO_ROOT, root.dir)
633633
if (!existsSync(absRoot)) {
634634
continue
@@ -642,7 +642,7 @@ async function main(): Promise<void> {
642642
continue
643643
}
644644
for (let i = 0, { length } = files; i < length; i += 1) {
645-
const f = files[i]
645+
const f = files[i]!
646646
const abs = path.join(absRoot, f)
647647
try {
648648
const stat = statSync(abs)
@@ -679,7 +679,7 @@ async function main(): Promise<void> {
679679
)
680680
}
681681
for (let i = 0, { length } = surviving; i < length; i += 1) {
682-
const v = surviving[i]
682+
const v = surviving[i]!
683683
printViolation(v, opts)
684684
}
685685
if (!opts.json) {

scripts/check-regression-patterns.mts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ export async function findNonExistentPnpmScripts(
419419
if (existsSync(pkgsDir)) {
420420
const entries = await fsPromises.readdir(pkgsDir, { withFileTypes: true })
421421
for (let i = 0, { length } = entries; i < length; i += 1) {
422-
const entry = entries[i]
422+
const entry = entries[i]!
423423
if (entry.isDirectory()) {
424424
await collectPackageScripts(
425425
path.join(pkgsDir, entry.name, 'package.json'),
@@ -435,7 +435,7 @@ export async function findNonExistentPnpmScripts(
435435
// convention.
436436
const placeholders = new Set(['bar', 'baz', 'foo', 'script'])
437437
for (let i = 0, { length } = rawMatches; i < length; i += 1) {
438-
const m = rawMatches[i]
438+
const m = rawMatches[i]!
439439
// Skip Claude Code permission-glob patterns like
440440
// Bash(pnpm run check:*)
441441
// Those describe a class of allowed Bash invocations, not a
@@ -628,7 +628,7 @@ export function wrapText(
628628
const words = text.split(/\s+/)
629629
let line = ''
630630
for (let i = 0, { length } = words; i < length; i += 1) {
631-
const w = words[i]
631+
const w = words[i]!
632632
if (line.length + w.length + 1 > width) {
633633
out.push(pad + line)
634634
line = w
@@ -664,7 +664,7 @@ async function main(): Promise<void> {
664664

665665
const allMatches: Match[] = []
666666
for (let i = 0, { length } = REGRESSIONS; i < length; i += 1) {
667-
const regression = REGRESSIONS[i]
667+
const regression = REGRESSIONS[i]!
668668
const matches =
669669
regression.id === 'docs-pnpm-run-nonexistent'
670670
? await findNonExistentPnpmScripts(regression)
@@ -685,7 +685,7 @@ async function main(): Promise<void> {
685685
// Group by pattern for a readable summary first.
686686
const byPattern = new Map<string, Match[]>()
687687
for (let i = 0, { length } = allMatches; i < length; i += 1) {
688-
const m = allMatches[i]
688+
const m = allMatches[i]!
689689
const key = m.regression.id
690690
const arr = byPattern.get(key) || []
691691
arr.push(m)
@@ -694,15 +694,15 @@ async function main(): Promise<void> {
694694

695695
if (opts.json) {
696696
for (let i = 0, { length } = allMatches; i < length; i += 1) {
697-
const m = allMatches[i]
697+
const m = allMatches[i]!
698698
printMatch(m, opts)
699699
}
700700
} else {
701701
logger.error(
702702
`Found ${allMatches.length} regression-pattern match${allMatches.length === 1 ? '' : 'es'} across ${byPattern.size} pattern${byPattern.size === 1 ? '' : 's'}:`,
703703
)
704704
for (let i = 0, { length } = allMatches; i < length; i += 1) {
705-
const m = allMatches[i]
705+
const m = allMatches[i]!
706706
printMatch(m, opts)
707707
}
708708
logger.log('')

scripts/check-version-consistency.mts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,14 @@ export async function collectMismatches(): Promise<Mismatch[]> {
255255
// Group package.json source entries by upstream name.
256256
const pkgByUpstream = new Map<string, PackageJsonSource>()
257257
for (let i = 0, { length } = pkgSources; i < length; i += 1) {
258-
const s = pkgSources[i]
258+
const s = pkgSources[i]!
259259
pkgByUpstream.set(s.upstream, s)
260260
}
261261

262262
// For each submodule with a version comment, find a matching package.json
263263
// source entry (same upstream name) and compare.
264264
for (let i = 0, { length } = submodules; i < length; i += 1) {
265-
const sub = submodules[i]
265+
const sub = submodules[i]!
266266
if (!sub.versionComment) {
267267
continue
268268
}
@@ -397,7 +397,7 @@ async function main(): Promise<void> {
397397
)
398398
}
399399
for (let i = 0, { length } = surviving; i < length; i += 1) {
400-
const m = surviving[i]
400+
const m = surviving[i]!
401401
printMismatch(m, opts)
402402
}
403403
if (!opts.json) {

0 commit comments

Comments
 (0)