Skip to content

Commit 6d3f74a

Browse files
authored
Migrate 6 files from JavaScript to TypeScript (#57885)
1 parent 328c2f6 commit 6d3f74a

File tree

9 files changed

+251
-107
lines changed

9 files changed

+251
-107
lines changed

src/fixtures/tests/spotlight-processing.js renamed to src/fixtures/tests/spotlight-processing.ts

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,26 @@
11
import { describe, expect, test } from 'vitest'
22

3+
interface TocItem {
4+
title: string
5+
intro: string
6+
fullPath?: string
7+
}
8+
9+
interface SpotlightItem {
10+
article: string
11+
image: string
12+
}
13+
14+
interface ProcessedSpotlightItem {
15+
article: string
16+
title: string
17+
description: string
18+
url: string
19+
image: string
20+
}
21+
322
// Mock data to simulate tocItems and spotlight configurations
4-
const mockTocItems = [
23+
const mockTocItems: TocItem[] = [
524
{
625
title: 'Test Debug Article',
726
intro: 'A test article for debugging functionality.',
@@ -20,19 +39,22 @@ const mockTocItems = [
2039
]
2140

2241
// Helper function to simulate the spotlight processing logic from CategoryLanding
23-
function processSpotlight(spotlight, tocItems) {
24-
const findArticleData = (articlePath) => {
25-
const cleanPath = articlePath.startsWith('/') ? articlePath.slice(1) : articlePath
42+
function processSpotlight(
43+
spotlight: SpotlightItem[] | undefined,
44+
tocItems: TocItem[],
45+
): ProcessedSpotlightItem[] {
46+
const findArticleData = (articlePath: string): TocItem | undefined => {
47+
const cleanPath: string = articlePath.startsWith('/') ? articlePath.slice(1) : articlePath
2648
return tocItems.find(
27-
(item) =>
49+
(item: TocItem) =>
2850
item.fullPath?.endsWith(cleanPath) ||
2951
item.fullPath?.includes(cleanPath.split('/').pop() || ''),
3052
)
3153
}
3254

3355
return (
34-
spotlight?.map((spotlightItem) => {
35-
const articleData = findArticleData(spotlightItem.article)
56+
spotlight?.map((spotlightItem: SpotlightItem): ProcessedSpotlightItem => {
57+
const articleData: TocItem | undefined = findArticleData(spotlightItem.article)
3658
return {
3759
article: spotlightItem.article,
3860
title: articleData?.title || 'Unknown Article',
@@ -46,7 +68,7 @@ function processSpotlight(spotlight, tocItems) {
4668

4769
describe('spotlight processing logic', () => {
4870
test('processes spotlight object items correctly', () => {
49-
const spotlight = [
71+
const spotlight: SpotlightItem[] = [
5072
{
5173
article: '/debugging-errors/test-debug-article',
5274
image: '/assets/images/test-debugging.png',
@@ -57,7 +79,7 @@ describe('spotlight processing logic', () => {
5779
},
5880
]
5981

60-
const result = processSpotlight(spotlight, mockTocItems)
82+
const result: ProcessedSpotlightItem[] = processSpotlight(spotlight, mockTocItems)
6183

6284
expect(result).toHaveLength(2)
6385
expect(result[0]).toEqual({
@@ -77,7 +99,7 @@ describe('spotlight processing logic', () => {
7799
})
78100

79101
test('processes multiple spotlight items with different images', () => {
80-
const spotlight = [
102+
const spotlight: SpotlightItem[] = [
81103
{
82104
article: '/debugging-errors/test-debug-article',
83105
image: '/assets/images/debugging.png',
@@ -92,7 +114,7 @@ describe('spotlight processing logic', () => {
92114
},
93115
]
94116

95-
const result = processSpotlight(spotlight, mockTocItems)
117+
const result: ProcessedSpotlightItem[] = processSpotlight(spotlight, mockTocItems)
96118

97119
expect(result).toHaveLength(3)
98120
expect(result[0].image).toBe('/assets/images/debugging.png')
@@ -102,21 +124,21 @@ describe('spotlight processing logic', () => {
102124
})
103125

104126
test('finds articles by filename when full path does not match', () => {
105-
const spotlight = [
127+
const spotlight: SpotlightItem[] = [
106128
{
107129
article: 'test-debug-article',
108130
image: '/assets/images/debug.png',
109131
},
110132
]
111-
const result = processSpotlight(spotlight, mockTocItems)
133+
const result: ProcessedSpotlightItem[] = processSpotlight(spotlight, mockTocItems)
112134

113135
expect(result[0].title).toBe('Test Debug Article')
114136
expect(result[0].url).toBe('/en/category/debugging-errors/test-debug-article')
115137
expect(result[0].image).toBe('/assets/images/debug.png')
116138
})
117139

118140
test('handles articles not found in tocItems', () => {
119-
const spotlight = [
141+
const spotlight: SpotlightItem[] = [
120142
{
121143
article: '/completely/nonexistent/path',
122144
image: '/assets/images/missing1.png',
@@ -127,7 +149,7 @@ describe('spotlight processing logic', () => {
127149
},
128150
]
129151

130-
const result = processSpotlight(spotlight, mockTocItems)
152+
const result: ProcessedSpotlightItem[] = processSpotlight(spotlight, mockTocItems)
131153

132154
expect(result).toHaveLength(2)
133155
expect(result[0]).toEqual({
@@ -147,13 +169,13 @@ describe('spotlight processing logic', () => {
147169
})
148170

149171
test('handles empty spotlight array', () => {
150-
const spotlight = []
151-
const result = processSpotlight(spotlight, mockTocItems)
172+
const spotlight: SpotlightItem[] = []
173+
const result: ProcessedSpotlightItem[] = processSpotlight(spotlight, mockTocItems)
152174
expect(result).toEqual([])
153175
})
154176

155177
test('handles undefined spotlight', () => {
156-
const result = processSpotlight(undefined, mockTocItems)
178+
const result: ProcessedSpotlightItem[] = processSpotlight(undefined, mockTocItems)
157179
expect(result).toEqual([])
158180
})
159181
})

src/frame/middleware/context/whats-new-changelog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default async function whatsNewChangelog(
1919
const changelogVersions = getApplicableVersions(req.context.page.changelog.versions)
2020

2121
// If the current version is not included, do not display a changelog.
22-
if (!changelogVersions.includes(req.context.currentVersion)) {
22+
if (!req.context.currentVersion || !changelogVersions.includes(req.context.currentVersion)) {
2323
return next()
2424
}
2525
}

src/learning-track/lib/process-learning-tracks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export default async function processLearningTracks(
8282
const trackVersions = getApplicableVersions(track.versions)
8383

8484
// If the current version is not included, do not display the track.
85-
if (!trackVersions.includes(context.currentVersion)) {
85+
if (!context.currentVersion || !trackVersions.includes(context.currentVersion)) {
8686
continue
8787
}
8888
}

src/products/tests/get-product-groups.js renamed to src/products/tests/get-product-groups.ts

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,33 @@ import {
66
getLocalizedGroupNames,
77
} from '@/products/lib/get-product-groups'
88

9+
// Mock data interface for tests - uses required name to match library expectations
10+
interface MockProductGroupData {
11+
name: string
12+
octicon?: string
13+
children: string[]
14+
}
15+
16+
// Mock data for testing edge cases with optional fields
17+
interface PartialProductGroupData {
18+
name?: string
19+
octicon?: string
20+
children: string[]
21+
}
22+
923
describe('get-product-groups helper functions', () => {
1024
describe('createOcticonToNameMap', () => {
1125
test('creates correct mapping from childGroups', () => {
12-
const mockChildGroups = [
26+
const mockChildGroups: MockProductGroupData[] = [
1327
{ name: 'Get started', octicon: 'RocketIcon', children: ['get-started'] },
1428
{ name: 'GitHub Copilot', octicon: 'CopilotIcon', children: ['copilot'] },
1529
{ name: 'Security', octicon: 'ShieldLockIcon', children: ['code-security'] },
1630
]
1731

18-
const octiconToName = createOcticonToNameMap(mockChildGroups)
32+
// Using any to cast mock data structure to match library's expected ProductGroupData type
33+
const octiconToName: { [key: string]: string } = createOcticonToNameMap(
34+
mockChildGroups as any,
35+
)
1936

2037
expect(octiconToName['RocketIcon']).toBe('Get started')
2138
expect(octiconToName['CopilotIcon']).toBe('GitHub Copilot')
@@ -24,14 +41,17 @@ describe('get-product-groups helper functions', () => {
2441
})
2542

2643
test('handles missing octicon or name gracefully', () => {
27-
const mockChildGroups = [
44+
const mockChildGroups: PartialProductGroupData[] = [
2845
{ name: 'Valid Group', octicon: 'RocketIcon', children: [] },
2946
{ octicon: 'MissingNameIcon', children: [] }, // missing name
3047
{ name: 'Missing Octicon', children: [] }, // missing octicon
3148
{ name: '', octicon: 'EmptyNameIcon', children: [] }, // empty name
3249
]
3350

34-
const octiconToName = createOcticonToNameMap(mockChildGroups)
51+
// Using any to test edge cases with partial/missing fields that wouldn't normally pass strict typing
52+
const octiconToName: { [key: string]: string } = createOcticonToNameMap(
53+
mockChildGroups as any,
54+
)
3555

3656
expect(octiconToName['RocketIcon']).toBe('Valid Group')
3757
expect(octiconToName['MissingNameIcon']).toBeUndefined()
@@ -42,19 +62,23 @@ describe('get-product-groups helper functions', () => {
4262

4363
describe('mapEnglishToLocalizedNames', () => {
4464
test('maps English names to localized names using octicon as key', () => {
45-
const englishGroups = [
65+
const englishGroups: MockProductGroupData[] = [
4666
{ name: 'Get started', octicon: 'RocketIcon', children: [] },
4767
{ name: 'Security', octicon: 'ShieldLockIcon', children: [] },
4868
{ name: 'GitHub Copilot', octicon: 'CopilotIcon', children: [] },
4969
]
5070

51-
const localizedByOcticon = {
71+
const localizedByOcticon: { [key: string]: string } = {
5272
RocketIcon: 'Empezar',
5373
ShieldLockIcon: 'Seguridad',
5474
CopilotIcon: 'GitHub Copilot', // Some names stay the same
5575
}
5676

57-
const nameMap = mapEnglishToLocalizedNames(englishGroups, localizedByOcticon)
77+
// Using any to cast mock data structure to match library's expected ProductGroupData type
78+
const nameMap: { [key: string]: string } = mapEnglishToLocalizedNames(
79+
englishGroups as any,
80+
localizedByOcticon,
81+
)
5882

5983
expect(nameMap['Get started']).toBe('Empezar')
6084
expect(nameMap['Security']).toBe('Seguridad')
@@ -63,18 +87,22 @@ describe('get-product-groups helper functions', () => {
6387
})
6488

6589
test('handles missing translations gracefully', () => {
66-
const englishGroups = [
90+
const englishGroups: MockProductGroupData[] = [
6791
{ name: 'Get started', octicon: 'RocketIcon', children: [] },
6892
{ name: 'Missing Translation', octicon: 'MissingIcon', children: [] },
6993
{ name: 'No Octicon', children: [] },
7094
]
7195

72-
const localizedByOcticon = {
96+
const localizedByOcticon: { [key: string]: string } = {
7397
RocketIcon: 'Empezar',
7498
// MissingIcon is not in the localized map
7599
}
76100

77-
const nameMap = mapEnglishToLocalizedNames(englishGroups, localizedByOcticon)
101+
// Using any to cast mock data structure to match library's expected ProductGroupData type
102+
const nameMap: { [key: string]: string } = mapEnglishToLocalizedNames(
103+
englishGroups as any,
104+
localizedByOcticon,
105+
)
78106

79107
expect(nameMap['Get started']).toBe('Empezar')
80108
expect(nameMap['Missing Translation']).toBeUndefined()
@@ -84,18 +112,22 @@ describe('get-product-groups helper functions', () => {
84112

85113
test('handles different ordering between English and localized groups', () => {
86114
// English groups in one order
87-
const englishGroups = [
115+
const englishGroups: MockProductGroupData[] = [
88116
{ name: 'Get started', octicon: 'RocketIcon', children: [] },
89117
{ name: 'Security', octicon: 'ShieldLockIcon', children: [] },
90118
]
91119

92120
// Localized groups in different order (but mapped by octicon)
93-
const localizedByOcticon = {
121+
const localizedByOcticon: { [key: string]: string } = {
94122
ShieldLockIcon: 'Seguridad', // Security comes first in localized
95123
RocketIcon: 'Empezar', // Get started comes second
96124
}
97125

98-
const nameMap = mapEnglishToLocalizedNames(englishGroups, localizedByOcticon)
126+
// Using any to cast mock data structure to match library's expected ProductGroupData type
127+
const nameMap: { [key: string]: string } = mapEnglishToLocalizedNames(
128+
englishGroups as any,
129+
localizedByOcticon,
130+
)
99131

100132
// Should correctly map regardless of order
101133
expect(nameMap['Get started']).toBe('Empezar')
@@ -105,17 +137,20 @@ describe('get-product-groups helper functions', () => {
105137

106138
describe('getLocalizedGroupNames integration', () => {
107139
test('returns empty object for English language', async () => {
108-
const result = await getLocalizedGroupNames('en')
140+
const result: { [key: string]: string } = await getLocalizedGroupNames('en')
109141
expect(result).toEqual({})
110142
})
111143

112144
test('returns empty object when no translation root available', () => {
113145
// Test the fallback when translation root is not found
114146
const lang = 'unknown-lang'
115-
const languages = { en: { dir: '/en' }, es: { dir: '/es' } }
147+
const languages: { [key: string]: { dir: string } } = {
148+
en: { dir: '/en' },
149+
es: { dir: '/es' },
150+
}
116151

117-
const translationRoot = languages[lang]?.dir
118-
const result = translationRoot
152+
const translationRoot: string | undefined = languages[lang]?.dir
153+
const result: { [key: string]: string } = translationRoot
119154
? {
120155
/* would proceed */
121156
}
@@ -126,7 +161,7 @@ describe('get-product-groups helper functions', () => {
126161

127162
test('handles file read errors gracefully', () => {
128163
// Test the try/catch behavior when file read fails
129-
let result
164+
let result: { [key: string]: string }
130165
try {
131166
// Simulate file read error
132167
throw new Error('File not found')
@@ -141,28 +176,35 @@ describe('get-product-groups helper functions', () => {
141176
describe('full translation pipeline', () => {
142177
test('complete flow from English groups to localized names', () => {
143178
// Simulate the complete flow
144-
const englishChildGroups = [
179+
const englishChildGroups: MockProductGroupData[] = [
145180
{ name: 'Get started', octicon: 'RocketIcon', children: ['get-started'] },
146181
{ name: 'Security', octicon: 'ShieldLockIcon', children: ['code-security'] },
147182
{ name: 'GitHub Copilot', octicon: 'CopilotIcon', children: ['copilot'] },
148183
]
149184

150185
// Simulate what would come from a Spanish localized file
151-
const mockLocalizedChildGroups = [
186+
const mockLocalizedChildGroups: MockProductGroupData[] = [
152187
{ name: 'Empezar', octicon: 'RocketIcon', children: ['get-started'] },
153188
{ name: 'Seguridad', octicon: 'ShieldLockIcon', children: ['code-security'] },
154189
{ name: 'GitHub Copilot', octicon: 'CopilotIcon', children: ['copilot'] },
155190
]
156191

157192
// Step 1: Create octicon -> localized name mapping
158-
const localizedByOcticon = createOcticonToNameMap(mockLocalizedChildGroups)
193+
// Using any to cast mock data structure to match library's expected ProductGroupData type
194+
const localizedByOcticon: { [key: string]: string } = createOcticonToNameMap(
195+
mockLocalizedChildGroups as any,
196+
)
159197

160198
// Step 2: Map English names to localized names
161-
const localizedNames = mapEnglishToLocalizedNames(englishChildGroups, localizedByOcticon)
199+
// Using any to cast mock data structure to match library's expected ProductGroupData type
200+
const localizedNames: { [key: string]: string } = mapEnglishToLocalizedNames(
201+
englishChildGroups as any,
202+
localizedByOcticon,
203+
)
162204

163205
// Step 3: Use in final mapping
164-
const finalResult = englishChildGroups.map((group) => {
165-
const localizedName = localizedNames[group.name] || group.name
206+
const finalResult = englishChildGroups.map((group: MockProductGroupData) => {
207+
const localizedName: string = localizedNames[group.name] || group.name
166208
return {
167209
name: localizedName,
168210
octicon: group.octicon,

src/secret-scanning/middleware/secret-scanning.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default async function secretScanning(
3131
const { currentVersion } = req.context
3232

3333
req.context.secretScanningData = secretScanningData.filter((entry) =>
34-
getApplicableVersions(entry.versions).includes(currentVersion),
34+
currentVersion ? getApplicableVersions(entry.versions).includes(currentVersion) : false,
3535
)
3636

3737
// Some entries might use Liquid syntax, so we need

0 commit comments

Comments
 (0)