Skip to content

Commit e6bbb47

Browse files
committed
chore(eslint): enable iteration fallback style
## Summary Enable Unicorn's iteration-fallback-style rule and migrate existing loops. ## Why Explicit guards avoid allocating empty fallback collections in iterated paths.
1 parent da8d0ef commit e6bbb47

37 files changed

Lines changed: 474 additions & 327 deletions

ci/diagnose.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,10 @@ function checkSupportedFrameworks (results, frameworks) {
506506
)
507507
}
508508

509-
for (const note of framework.notes || []) {
510-
addResult(results, 'info', `${framework.name} capability note`, note)
509+
if (framework.notes) {
510+
for (const note of framework.notes) {
511+
addResult(results, 'info', `${framework.name} capability note`, note)
512+
}
511513
}
512514
}
513515
}

ci/test-optimization-validation/approval-artifacts.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,16 @@ function getCoveredFilesManifest (material) {
154154
}
155155
for (const executable of material.executables) {
156156
if (executable.path && executable.sha256) files.set(executable.path, executable.sha256)
157-
for (const delegated of executable.delegated || []) files.set(delegated.path, delegated.sha256)
158-
for (const entrypoint of executable.entrypoints || []) files.set(entrypoint.path, entrypoint.sha256)
157+
if (executable.delegated) {
158+
for (const delegated of executable.delegated) files.set(delegated.path, delegated.sha256)
159+
}
160+
if (executable.entrypoints) {
161+
for (const entrypoint of executable.entrypoints) files.set(entrypoint.path, entrypoint.sha256)
162+
}
163+
}
164+
if (material.projectFiles) {
165+
for (const projectFile of material.projectFiles) files.set(projectFile.path, projectFile.sha256)
159166
}
160-
for (const projectFile of material.projectFiles || []) files.set(projectFile.path, projectFile.sha256)
161167

162168
return [...files]
163169
.sort(([left], [right]) => left.localeCompare(right))

ci/test-optimization-validation/approval.js

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,25 @@ function getApprovalCommand (id, command) {
240240
*/
241241
function getGeneratedFileMaterial (manifest, requestedScenario) {
242242
const files = []
243-
for (const framework of manifest.frameworks || []) {
244-
const strategy = framework.generatedTestStrategy
245-
const selectedPaths = getSelectedGeneratedPaths(strategy, requestedScenario)
246-
for (const file of strategy?.files || []) {
247-
if (!selectedPaths.has(path.resolve(file.path))) continue
248-
const content = `${file.contentLines.join('\n')}\n`
249-
files.push(sanitizeForReport({
250-
frameworkId: framework.id,
251-
path: path.resolve(file.path),
252-
sha256: crypto.createHash('sha256').update(content).digest('hex'),
253-
content,
254-
removeAfterValidation: (strategy.cleanupPaths || []).some(cleanupPath => {
255-
return path.resolve(cleanupPath) === path.resolve(file.path)
256-
}),
257-
}))
243+
if (manifest.frameworks) {
244+
for (const framework of manifest.frameworks) {
245+
const strategy = framework.generatedTestStrategy
246+
const selectedPaths = getSelectedGeneratedPaths(strategy, requestedScenario)
247+
if (strategy?.files) {
248+
for (const file of strategy.files) {
249+
if (!selectedPaths.has(path.resolve(file.path))) continue
250+
const content = `${file.contentLines.join('\n')}\n`
251+
files.push(sanitizeForReport({
252+
frameworkId: framework.id,
253+
path: path.resolve(file.path),
254+
sha256: crypto.createHash('sha256').update(content).digest('hex'),
255+
content,
256+
removeAfterValidation: (strategy.cleanupPaths || []).some(cleanupPath => {
257+
return path.resolve(cleanupPath) === path.resolve(file.path)
258+
}),
259+
}))
260+
}
261+
}
258262
}
259263
}
260264
return files
@@ -278,9 +282,11 @@ function getSelectedGeneratedPaths (strategy, requestedScenario) {
278282
return path.resolve(scenario.testIdentities[0].file)
279283
}))
280284
const selectedPaths = new Set()
281-
for (const file of strategy.files || []) {
282-
const filename = path.resolve(file.path)
283-
if (!requestedScenario || !scenarioPaths.has(filename)) selectedPaths.add(filename)
285+
if (strategy.files) {
286+
for (const file of strategy.files) {
287+
const filename = path.resolve(file.path)
288+
if (!requestedScenario || !scenarioPaths.has(filename)) selectedPaths.add(filename)
289+
}
284290
}
285291
if (generatedId) {
286292
const scenario = strategy.scenarios?.find(candidate => candidate.id === generatedId)

ci/test-optimization-validation/ci-discovery.js

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,22 @@ function buildCiDiscovery ({ manifest, diagnosis }) {
6161
function getManifestWorkflowLocations (manifest) {
6262
const root = manifest.repository?.root
6363
const locations = []
64-
for (const framework of manifest.frameworks || []) {
65-
const configFile = framework.ciWiring?.configFile
66-
if (typeof configFile !== 'string') continue
67-
if (!root || !path.isAbsolute(configFile)) {
68-
locations.push(configFile)
69-
continue
64+
if (manifest.frameworks) {
65+
for (const framework of manifest.frameworks) {
66+
const configFile = framework.ciWiring?.configFile
67+
if (typeof configFile !== 'string') continue
68+
if (!root || !path.isAbsolute(configFile)) {
69+
locations.push(configFile)
70+
continue
71+
}
72+
73+
const relative = path.relative(root, configFile)
74+
const isRelativePath = relative && relative !== '..' && !relative.startsWith(`..${path.sep}`) &&
75+
!path.isAbsolute(relative)
76+
locations.push(isRelativePath
77+
? relative.split(path.sep).join('/')
78+
: configFile)
7079
}
71-
72-
const relative = path.relative(root, configFile)
73-
locations.push(relative && relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)
74-
? relative.split(path.sep).join('/')
75-
: configFile)
7680
}
7781
return uniqueStrings(locations)
7882
}
@@ -106,12 +110,14 @@ function getCiDiscoveryContradictions ({ manifest, declaredFound, staticFound })
106110
)
107111
}
108112

109-
for (const framework of manifest.frameworks || []) {
110-
if (!frameworkClaimsNoCi(framework)) continue
111-
contradictions.push(
112-
`framework ${framework.id || '<unknown>'} records no CI workflow, but static diagnosis found ` +
113-
formatList(staticFound)
114-
)
113+
if (manifest.frameworks) {
114+
for (const framework of manifest.frameworks) {
115+
if (!frameworkClaimsNoCi(framework)) continue
116+
contradictions.push(
117+
`framework ${framework.id || '<unknown>'} records no CI workflow, but static diagnosis found ` +
118+
formatList(staticFound)
119+
)
120+
}
115121
}
116122

117123
return contradictions

ci/test-optimization-validation/command-runner.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -555,11 +555,13 @@ function buildOfflineValidationEnv ({ fixture, outputRoot }) {
555555
*/
556556
function assertNoInlineValidationEnvOverrides (command, env) {
557557
if (!env[VALIDATION_MODE_ENV]) return
558-
for (const name of Object.keys(command.env || {})) {
559-
const normalized = process.platform === 'win32' ? name.toUpperCase() : name
560-
if (VALIDATION_RESERVED_ENV_NAMES.some(reserved => environmentNamesEqual(reserved, name)) ||
561-
isDatadogEnvironmentName(name) || normalized.startsWith('OTEL_')) {
562-
throw new Error(`Direct-runner adapter must not override validator-controlled environment variable ${name}.`)
558+
if (command.env) {
559+
for (const name of Object.keys(command.env)) {
560+
const normalized = process.platform === 'win32' ? name.toUpperCase() : name
561+
if (VALIDATION_RESERVED_ENV_NAMES.some(reserved => environmentNamesEqual(reserved, name)) ||
562+
isDatadogEnvironmentName(name) || normalized.startsWith('OTEL_')) {
563+
throw new Error(`Direct-runner adapter must not override validator-controlled environment variable ${name}.`)
564+
}
563565
}
564566
}
565567
}

ci/test-optimization-validation/environment.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ function setEnvironmentValue (environment, name, value, platform = process.platf
6363
* @returns {void}
6464
*/
6565
function mergeEnvironment (target, source, platform = process.platform) {
66-
for (const [name, value] of Object.entries(source || {})) {
67-
setEnvironmentValue(target, name, value, platform)
66+
if (source) {
67+
for (const [name, value] of Object.entries(source)) {
68+
setEnvironmentValue(target, name, value, platform)
69+
}
6870
}
6971
}
7072

ci/test-optimization-validation/executable.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,21 @@ function getResolvedExecutable (command) {
4040
*/
4141
function bindManifestExecutables (manifest) {
4242
const identities = []
43-
for (const framework of manifest.frameworks || []) {
44-
if (framework.status !== 'runnable') continue
45-
const command = getManifestCommands({ frameworks: [framework] })[0]?.[1]
46-
try {
47-
const identity = getCommandExecutableIdentity(command, manifest.repository.root)
48-
bindApprovedExecutable(framework.validation, identity)
49-
identities.push({ id: `framework:${framework.id}`, ...identity })
50-
} catch (error) {
51-
identities.push({
52-
id: `framework:${framework.id}`,
53-
unavailable: true,
54-
reason: error?.message || String(error),
55-
})
43+
if (manifest.frameworks) {
44+
for (const framework of manifest.frameworks) {
45+
if (framework.status !== 'runnable') continue
46+
const command = getManifestCommands({ frameworks: [framework] })[0]?.[1]
47+
try {
48+
const identity = getCommandExecutableIdentity(command, manifest.repository.root)
49+
bindApprovedExecutable(framework.validation, identity)
50+
identities.push({ id: `framework:${framework.id}`, ...identity })
51+
} catch (error) {
52+
identities.push({
53+
id: `framework:${framework.id}`,
54+
unavailable: true,
55+
reason: error?.message || String(error),
56+
})
57+
}
5658
}
5759
}
5860
return identities

ci/test-optimization-validation/generated-files.js

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,16 @@ function cleanupGeneratedFiles (manifest, { keep = false } = {}) {
9191
filesRemoved: 0,
9292
filesRetained: 0,
9393
}
94-
for (const framework of manifest.frameworks || []) {
95-
const strategy = framework.generatedTestStrategy
96-
addCleanupOutcome(
97-
outcome,
98-
cleanupPaths(getSafeCleanupPaths(framework, strategy, { includeGeneratedFiles: true })),
99-
'files'
100-
)
101-
addCleanupOutcome(outcome, cleanupCreatedDirectories(framework.project.root), 'directories')
94+
if (manifest.frameworks) {
95+
for (const framework of manifest.frameworks) {
96+
const strategy = framework.generatedTestStrategy
97+
addCleanupOutcome(
98+
outcome,
99+
cleanupPaths(getSafeCleanupPaths(framework, strategy, { includeGeneratedFiles: true })),
100+
'files'
101+
)
102+
addCleanupOutcome(outcome, cleanupCreatedDirectories(framework.project.root), 'directories')
103+
}
102104
}
103105
outcome.status = outcome.filesRetained > 0 || outcome.directoriesRetained > 0
104106
? 'incomplete'
@@ -168,13 +170,15 @@ function initializeRuntimeCleanupFiles (framework, strategy) {
168170
if (initializedCleanupStrategies.has(strategy)) return
169171

170172
const generatedFiles = new Set((strategy.files || []).map(file => validateGeneratedFilePath(framework, file.path)))
171-
for (const cleanupPath of strategy.cleanupPaths || []) {
172-
const filename = validateCleanupPath(framework, cleanupPath)
173-
if (generatedFiles.has(filename) || isDirectory(filename) || !isNamespacedRuntimeFile(filename)) continue
174-
if (fs.existsSync(filename)) {
175-
throw new Error(`Refusing to delete pre-existing generated validation runtime file: ${filename}`)
173+
if (strategy.cleanupPaths) {
174+
for (const cleanupPath of strategy.cleanupPaths) {
175+
const filename = validateCleanupPath(framework, cleanupPath)
176+
if (generatedFiles.has(filename) || isDirectory(filename) || !isNamespacedRuntimeFile(filename)) continue
177+
if (fs.existsSync(filename)) {
178+
throw new Error(`Refusing to delete pre-existing generated validation runtime file: ${filename}`)
179+
}
180+
authorizedRuntimeCleanupFiles.set(filename, authorizePathForCleanup(framework.project.root, filename))
176181
}
177-
authorizedRuntimeCleanupFiles.set(filename, authorizePathForCleanup(framework.project.root, filename))
178182
}
179183
initializedCleanupStrategies.add(strategy)
180184
}
@@ -183,20 +187,24 @@ function getSafeCleanupPaths (framework, strategy, { includeGeneratedFiles }) {
183187
if (!strategy) return []
184188

185189
const generatedFiles = new Set()
186-
for (const file of strategy.files || []) {
187-
generatedFiles.add(validateGeneratedFilePath(framework, file.path))
190+
if (strategy.files) {
191+
for (const file of strategy.files) {
192+
generatedFiles.add(validateGeneratedFilePath(framework, file.path))
193+
}
188194
}
189195

190196
const cleanupPaths = []
191-
for (const cleanupPath of strategy.cleanupPaths || []) {
192-
const filename = validateCleanupPath(framework, cleanupPath)
193-
if (generatedFiles.has(filename)) {
194-
if (includeGeneratedFiles && writtenGeneratedFiles.has(filename)) cleanupPaths.push(filename)
195-
continue
196-
}
197+
if (strategy.cleanupPaths) {
198+
for (const cleanupPath of strategy.cleanupPaths) {
199+
const filename = validateCleanupPath(framework, cleanupPath)
200+
if (generatedFiles.has(filename)) {
201+
if (includeGeneratedFiles && writtenGeneratedFiles.has(filename)) cleanupPaths.push(filename)
202+
continue
203+
}
197204

198-
if (authorizedRuntimeCleanupFiles.has(filename)) {
199-
cleanupPaths.push(filename)
205+
if (authorizedRuntimeCleanupFiles.has(filename)) {
206+
cleanupPaths.push(filename)
207+
}
200208
}
201209
}
202210

@@ -264,10 +272,12 @@ function authorizePathForCleanup (root, filename) {
264272
}
265273

266274
function pinRuntimeCleanupParents (strategy) {
267-
for (const cleanupPath of strategy.cleanupPaths || []) {
268-
const authorization = authorizedRuntimeCleanupFiles.get(path.resolve(cleanupPath))
269-
if (authorization && authorization.physicalParent === undefined) {
270-
pinCleanupParent(authorization, cleanupPath)
275+
if (strategy.cleanupPaths) {
276+
for (const cleanupPath of strategy.cleanupPaths) {
277+
const authorization = authorizedRuntimeCleanupFiles.get(path.resolve(cleanupPath))
278+
if (authorization && authorization.physicalParent === undefined) {
279+
pinCleanupParent(authorization, cleanupPath)
280+
}
271281
}
272282
}
273283
}

ci/test-optimization-validation/generated-verifier.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,16 @@ function getVerificationFailure (framework, evidence, artifacts, scenario, resul
209209
function getGeneratedRuntimeFileStatus (strategy) {
210210
const generatedFiles = new Set((strategy.files || []).map(file => path.resolve(file.path)))
211211
let expectsRuntimeFile = false
212-
for (const cleanupPath of strategy.cleanupPaths || []) {
213-
const filename = path.resolve(cleanupPath)
214-
if (generatedFiles.has(filename)) continue
215-
expectsRuntimeFile = true
216-
try {
217-
const stat = fs.lstatSync(filename)
218-
if (!stat.isSymbolicLink() && stat.isFile()) return true
219-
} catch {}
212+
if (strategy.cleanupPaths) {
213+
for (const cleanupPath of strategy.cleanupPaths) {
214+
const filename = path.resolve(cleanupPath)
215+
if (generatedFiles.has(filename)) continue
216+
expectsRuntimeFile = true
217+
try {
218+
const stat = fs.lstatSync(filename)
219+
if (!stat.isSymbolicLink() && stat.isFile()) return true
220+
} catch {}
221+
}
220222
}
221223
return expectsRuntimeFile ? false : undefined
222224
}

ci/test-optimization-validation/manifest-scaffold.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -457,15 +457,17 @@ function buildFramework (repositoryRoot, detection, ciDiscovery) {
457457

458458
function getImplicitConfigFiles (framework, projectRoot, repositoryRoot) {
459459
const files = []
460-
for (const basename of IMPLICIT_CONFIG_FILENAMES[framework] || []) {
461-
const filename = path.join(projectRoot, basename)
462-
try {
463-
const stat = fs.lstatSync(filename)
464-
const physical = fs.realpathSync(filename)
465-
if (stat.isFile() && !stat.isSymbolicLink() &&
466-
fs.statSync(physical).isFile() &&
467-
isPathInside(fs.realpathSync(repositoryRoot), physical)) files.push(physical)
468-
} catch {}
460+
if (IMPLICIT_CONFIG_FILENAMES[framework]) {
461+
for (const basename of IMPLICIT_CONFIG_FILENAMES[framework]) {
462+
const filename = path.join(projectRoot, basename)
463+
try {
464+
const stat = fs.lstatSync(filename)
465+
const physical = fs.realpathSync(filename)
466+
if (stat.isFile() && !stat.isSymbolicLink() &&
467+
fs.statSync(physical).isFile() &&
468+
isPathInside(fs.realpathSync(repositoryRoot), physical)) files.push(physical)
469+
} catch {}
470+
}
469471
}
470472
return files
471473
}
@@ -1135,9 +1137,11 @@ function getFrameworkPackageJson (repositoryRoot, detection) {
11351137
if (preciseLocation) return findOwningPackageJson(repositoryRoot, preciseLocation)
11361138

11371139
const owners = new Map()
1138-
for (const location of detection.locations || []) {
1139-
const owner = findOwningPackageJson(repositoryRoot, location)
1140-
if (owner) owners.set(owner.path, owner)
1140+
if (detection.locations) {
1141+
for (const location of detection.locations) {
1142+
const owner = findOwningPackageJson(repositoryRoot, location)
1143+
if (owner) owners.set(owner.path, owner)
1144+
}
11411145
}
11421146
if (owners.size === 1) return [...owners.values()][0]
11431147
}

0 commit comments

Comments
 (0)