Skip to content

Commit 8adc699

Browse files
heiskrrsese
andauthored
Enable github/array-foreach ESLint rule by converting all forEach to for loops (#58302)
Co-authored-by: Robert Sese <734194+rsese@users.noreply.github.com>
1 parent 86216fb commit 8adc699

File tree

124 files changed

+798
-739
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+798
-739
lines changed

eslint.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ export default [
9696
camelcase: 'off', // Many gh apis use underscores, 600+ uses
9797

9898
// Disabled rules to review
99-
'github/array-foreach': 'off', // 250+
10099
'no-console': 'off', // 800+
101100
'@typescript-eslint/no-explicit-any': 'off', // 1000+
102101
},

src/ai-tools/scripts/ai-tools.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ const editorTypes: EditorTypes = {
4848

4949
const refinementDescriptions = (): string => {
5050
let str = '\n\n'
51-
Object.entries(editorTypes).forEach(([ed, edObj]) => {
51+
for (const [ed, edObj] of Object.entries(editorTypes)) {
5252
str += ` ${ed.padEnd(12)} ${edObj.description}\n`
53-
})
53+
}
5454
return str
5555
}
5656

@@ -155,10 +155,10 @@ async function callEditor(
155155

156156
const prompt = yaml.load(fs.readFileSync(promptTemplatePath, 'utf8')) as PromptData
157157

158-
prompt.messages.forEach((msg) => {
158+
for (const msg of prompt.messages) {
159159
msg.content = msg.content.replace('{{markdownPrompt}}', markdownPrompt)
160160
msg.content = msg.content.replace('{{input}}', content)
161-
})
161+
}
162162

163163
return callModelsApi(prompt)
164164
}

src/article-api/scripts/generate-api-docs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ function extractExample(commentBlock: string): string {
117117
function generateMarkdown(apiDocs: any[]): string {
118118
let markdown = '## Reference: API endpoints\n\n'
119119

120-
apiDocs.forEach((doc) => {
120+
for (const doc of apiDocs) {
121121
markdown += `### ${doc.method.toUpperCase()} ${doc.path}\n\n`
122122
markdown += `${doc.description}\n\n`
123123

@@ -142,7 +142,7 @@ function generateMarkdown(apiDocs: any[]): string {
142142
}
143143

144144
markdown += '---\n\n'
145-
})
145+
}
146146

147147
return markdown
148148
}

src/article-api/tests/pagelist.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,16 @@ describe.each(allVersionKeys)('pagelist api for %s', async (versionKey) => {
4141
expression = new RegExp(`/\\w{2}(/${versionKey})?/?.*`)
4242
else expression = new RegExp(`/\\w{2}/${versionKey}/?.*`)
4343

44-
res.body
45-
.trim()
46-
.split('\n')
47-
.forEach((permalink: string) => {
48-
expect(permalink).toMatch(expression)
49-
})
44+
for (const permalink of res.body.trim().split('\n')) {
45+
expect(permalink).toMatch(expression)
46+
}
5047
})
5148

5249
test('English requests only returns urls that contain /en', async () => {
5350
const expression = new RegExp(`^/en(/${nonEnterpriseDefaultVersion})?/?.*`)
54-
res.body
55-
.trim()
56-
.split('\n')
57-
.forEach((permalink: string) => {
58-
expect(permalink).toMatch(expression)
59-
})
51+
for (const permalink of res.body.trim().split('\n')) {
52+
expect(permalink).toMatch(expression)
53+
}
6054
})
6155
})
6256

src/assets/scripts/list-image-sizes.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ const images = await Promise.all(
2525
return { relativePath, width, height, size }
2626
}),
2727
)
28-
images
29-
.sort((a, b) => b.size - a.size)
30-
.forEach((image) => {
31-
const { relativePath, width, height } = image
32-
console.log(`${width} x ${height} - ${relativePath}`)
33-
})
28+
for (const image of images.sort((a, b) => b.size - a.size)) {
29+
const { relativePath, width, height } = image
30+
console.log(`${width} x ${height} - ${relativePath}`)
31+
}

src/audit-logs/lib/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,14 @@ export async function filterAndUpdateGhesDataByAllowlistValues({
317317
// Categorizes the given array of audit log events by event category
318318
function categorizeEvents(events: AuditLogEventT[]) {
319319
const categorizedEvents: CategorizedEvents = {}
320-
events.forEach((event) => {
320+
for (const event of events) {
321321
const [category] = event.action.split('.')
322322
if (!Object.hasOwn(categorizedEvents, category)) {
323323
categorizedEvents[category] = []
324324
}
325325

326326
categorizedEvents[category].push(event)
327-
})
327+
}
328328

329329
return categorizedEvents
330330
}

src/audit-logs/scripts/sync.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,16 @@ async function main() {
180180
await mkdirp(auditLogVersionDirPath)
181181
}
182182

183-
Object.values(AUDIT_LOG_PAGES).forEach(async (page) => {
183+
for (const page of Object.values(AUDIT_LOG_PAGES)) {
184184
const auditLogSchemaFilePath = path.join(auditLogVersionDirPath, `${page}.json`)
185185

186186
if (auditLogData[version][page]) {
187187
await writeFile(
188188
auditLogSchemaFilePath,
189189
JSON.stringify(auditLogData[version][page], null, 2),
190190
)
191-
console.log(`✅ Wrote ${auditLogSchemaFilePath}`)
192191
}
193-
})
192+
}
194193
}
195194
}
196195

src/audit-logs/tests/fields.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,25 @@ describe('Audit log fields functionality', () => {
3131

3232
if (eventWithFields) {
3333
expect(Array.isArray(eventWithFields.fields)).toBe(true)
34-
eventWithFields.fields!.forEach((field) => {
34+
for (const field of eventWithFields.fields!) {
3535
expect(typeof field).toBe('string')
3636
expect(field.length).toBeGreaterThan(0)
37-
})
37+
}
3838
}
3939
})
4040

4141
test('should handle events without fields gracefully', () => {
4242
// Some events might not have fields, this should not break anything
4343
const events = getAuditLogEvents('organization', 'enterprise-cloud@latest')
4444

45-
events.forEach((event) => {
45+
for (const event of events) {
4646
expect(event).toHaveProperty('action')
4747
expect(event).toHaveProperty('description')
4848
// fields property is optional
4949
if (event.fields) {
5050
expect(Array.isArray(event.fields)).toBe(true)
5151
}
52-
})
52+
}
5353
})
5454

5555
test('should include common audit log fields', () => {
@@ -82,19 +82,19 @@ describe('Audit log fields functionality', () => {
8282
expect(categories.length).toBeGreaterThan(0)
8383

8484
// Check that events in categories have proper structure including fields
85-
categories.forEach((category) => {
85+
for (const category of categories) {
8686
const events = categorizedEvents[category]
8787
expect(Array.isArray(events)).toBe(true)
8888

89-
events.forEach((event: AuditLogEventT) => {
89+
for (const event of events as AuditLogEventT[]) {
9090
expect(event).toHaveProperty('action')
9191
expect(event).toHaveProperty('description')
9292
// fields is optional but if present should be array
9393
if (event.fields) {
9494
expect(Array.isArray(event.fields)).toBe(true)
9595
}
96-
})
97-
})
96+
}
97+
}
9898
})
9999

100100
test('should preserve fields data through categorization', () => {
@@ -127,20 +127,20 @@ describe('Audit log fields functionality', () => {
127127
test('should not have duplicate fields in same event', () => {
128128
const events = getAuditLogEvents('organization', 'enterprise-cloud@latest')
129129

130-
events.forEach((event) => {
130+
for (const event of events) {
131131
if (event.fields) {
132132
const uniqueFields = new Set(event.fields)
133133
expect(uniqueFields.size).toBe(event.fields.length)
134134
}
135-
})
135+
}
136136
})
137137

138138
test('should have reasonable field names', () => {
139139
const events = getAuditLogEvents('organization', 'enterprise-cloud@latest')
140140
const eventWithFields = events.find((event) => event.fields && event.fields.length > 0)
141141

142142
if (eventWithFields) {
143-
eventWithFields.fields!.forEach((field) => {
143+
for (const field of eventWithFields.fields!) {
144144
// Field names should be reasonable strings
145145
expect(field).toBeTruthy()
146146
expect(typeof field).toBe('string')
@@ -149,33 +149,33 @@ describe('Audit log fields functionality', () => {
149149

150150
// Should not contain special characters that would break display
151151
expect(field).not.toMatch(/[<>'"&]/)
152-
})
152+
}
153153
}
154154
})
155155

156156
test('should handle different page types consistently', () => {
157157
const pageTypes = ['organization', 'enterprise', 'user']
158158

159-
pageTypes.forEach((pageType) => {
159+
for (const pageType of pageTypes) {
160160
try {
161161
const events = getAuditLogEvents(pageType, 'enterprise-cloud@latest')
162162

163-
events.forEach((event) => {
163+
for (const event of events) {
164164
expect(event).toHaveProperty('action')
165165
expect(event).toHaveProperty('description')
166166

167167
if (event.fields) {
168168
expect(Array.isArray(event.fields)).toBe(true)
169-
event.fields.forEach((field) => {
169+
for (const field of event.fields) {
170170
expect(typeof field).toBe('string')
171-
})
171+
}
172172
}
173-
})
173+
}
174174
} catch (error) {
175175
// Some page types might not exist for certain versions, that's ok
176176
console.log(`Skipping ${pageType} page type due to: ${error}`)
177177
}
178-
})
178+
}
179179
})
180180
})
181181

@@ -194,9 +194,9 @@ describe('Audit log fields functionality', () => {
194194

195195
if (fields) {
196196
expect(Array.isArray(fields)).toBe(true)
197-
fields.forEach((field) => {
197+
for (const field of fields) {
198198
expect(typeof field).toBe('string')
199-
})
199+
}
200200
}
201201
})
202202
})

src/audit-logs/tests/unit/category-notes.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ describe('audit log category notes', () => {
1616

1717
test('category notes are strings', () => {
1818
if (config.categoryNotes) {
19-
Object.values(config.categoryNotes).forEach((note) => {
19+
for (const note of Object.values(config.categoryNotes)) {
2020
expect(typeof note).toBe('string')
2121
expect(note.length).toBeGreaterThan(0)
22-
})
22+
}
2323
}
2424
})
2525

@@ -51,13 +51,13 @@ describe('audit log category notes', () => {
5151
expect(Object.keys(enterpriseEvents).length).toBeGreaterThan(0)
5252

5353
// Each category should still contain arrays of events
54-
Object.values(organizationEvents).forEach((events) => {
54+
for (const events of Object.values(organizationEvents)) {
5555
expect(Array.isArray(events)).toBe(true)
5656
if (events.length > 0) {
5757
expect(events[0]).toHaveProperty('action')
5858
expect(events[0]).toHaveProperty('description')
5959
}
60-
})
60+
}
6161
})
6262

6363
test('category notes are properly typed', () => {

src/automated-pipelines/lib/update-markdown.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,9 @@ async function getIndexFileVersions(
399399
throw new Error(`Frontmatter in ${filepath} does not contain versions.`)
400400
}
401401
const fmVersions = getApplicableVersions(data.versions)
402-
fmVersions.forEach((version: string) => versions.add(version))
402+
for (const version of fmVersions) {
403+
versions.add(version)
404+
}
403405
}),
404406
)
405407
const versionArray = [...versions]
@@ -431,7 +433,7 @@ export async function convertVersionsToFrontmatter(
431433

432434
// Currently, only GHES is numbered. Number releases have to be
433435
// handled differently because they use semantic versioning.
434-
versions.forEach((version) => {
436+
for (const version of versions) {
435437
const docsVersion = allVersions[version]
436438
if (!docsVersion.hasNumberedReleases) {
437439
frontmatterVersions[docsVersion.shortName] = '*'
@@ -455,10 +457,10 @@ export async function convertVersionsToFrontmatter(
455457
numberedReleases[docsVersion.shortName].availableReleases[i] = docsVersion.currentRelease
456458
}
457459
}
458-
})
460+
}
459461

460462
// Create semantic versions for numbered releases
461-
Object.keys(numberedReleases).forEach((key) => {
463+
for (const key of Object.keys(numberedReleases)) {
462464
const availableReleases = numberedReleases[key].availableReleases
463465
const versionContinuity = checkVersionContinuity(availableReleases)
464466
if (availableReleases.every(Boolean)) {
@@ -483,7 +485,7 @@ export async function convertVersionsToFrontmatter(
483485
}
484486
frontmatterVersions[key] = semVer.join(' ')
485487
}
486-
})
488+
}
487489
const sortedFrontmatterVersions = Object.keys(frontmatterVersions)
488490
.sort()
489491
.reduce((acc: { [key: string]: string }, key) => {

0 commit comments

Comments
 (0)