Skip to content

Commit 5ae4ec0

Browse files
authored
Migrate 6 files from JavaScript to TypeScript (#58002)
1 parent 7cd719d commit 5ae4ec0

File tree

17 files changed

+354
-225
lines changed

17 files changed

+354
-225
lines changed

src/automated-pipelines/tests/rendering.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { get } from '@/tests/helpers/e2etest'
88

99
// Type definitions for page objects
1010
type Page = {
11-
autogenerated?: boolean
11+
autogenerated?: string
1212
fullPath: string
1313
permalinks: Array<{ href: string }>
1414
versions: {

src/content-linter/tests/lint-frontmatter-links.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,23 @@ describe('front matter', () => {
4949
async (page) => {
5050
const redirectsContext = { redirects, pages }
5151

52-
const trouble = page.includeGuides
53-
// Using any type for uri because includeGuides can contain various URI formats
52+
const trouble = page
53+
.includeGuides! // Using any type for uri because includeGuides can contain various URI formats
5454
.map((uri: any, i: number) => checkURL(uri, i, redirectsContext))
5555
.filter(Boolean)
5656

5757
const customErrorMessage = makeCustomErrorMessage(page, trouble, 'includeGuides')
5858
expect(trouble.length, customErrorMessage).toEqual(0)
5959

6060
const counts = new Map()
61-
for (const guide of page.includeGuides) {
61+
for (const guide of page.includeGuides!) {
6262
counts.set(guide, (counts.get(guide) || 0) + 1)
6363
}
6464
const countUnique = counts.size
6565
let notDistinctMessage = `In ${page.relativePath} there are duplicate links in .includeGuides`
6666
const dupes = [...counts.entries()].filter(([, count]) => count > 1).map(([entry]) => entry)
6767
notDistinctMessage += `\nTo fix this, remove: ${dupes.join(' and ')}`
68-
expect(page.includeGuides.length, notDistinctMessage).toEqual(countUnique)
68+
expect(page.includeGuides!.length, notDistinctMessage).toEqual(countUnique)
6969
},
7070
)
7171

@@ -78,12 +78,17 @@ describe('front matter', () => {
7878
const redirectsContext = { redirects, pages }
7979

8080
const trouble = []
81-
for (const links of Object.values(page.featuredLinks)) {
81+
for (const links of Object.values(page.featuredLinks!)) {
8282
// Some thing in `.featuredLinks` are not arrays.
8383
// For example `popularHeading`. So just skip them.
8484
if (!Array.isArray(links)) continue
8585

86-
trouble.push(...links.map((uri, i) => checkURL(uri, i, redirectsContext)).filter(Boolean))
86+
trouble.push(
87+
...links
88+
.filter((link) => link.href)
89+
.map((link, i) => checkURL(link.href, i, redirectsContext))
90+
.filter(Boolean),
91+
)
8792
}
8893

8994
const customErrorMessage = makeCustomErrorMessage(page, trouble, 'featuredLinks')
@@ -98,7 +103,7 @@ describe('front matter', () => {
98103
const redirectsContext = { redirects, pages }
99104

100105
const trouble = []
101-
for (const linksRaw of Object.values(page.introLinks)) {
106+
for (const linksRaw of Object.values(page.introLinks!)) {
102107
const links = Array.isArray(linksRaw) ? linksRaw : [linksRaw]
103108
trouble.push(
104109
...links
Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ import { merge, get } from 'lodash-es'
88
import languages from '@/languages/lib/languages'
99
import { correctTranslatedContentStrings } from '@/languages/lib/correct-translation-content'
1010

11+
interface YAMLException extends Error {
12+
mark?: any
13+
}
14+
15+
interface FileSystemError extends Error {
16+
code?: string
17+
}
18+
1119
// If you run `export DEBUG_JIT_DATA_READS=true` in your terminal,
1220
// next time it will mention every file it reads from disk.
1321
const DEBUG_JIT_DATA_READS = Boolean(JSON.parse(process.env.DEBUG_JIT_DATA_READS || 'false'))
@@ -23,29 +31,33 @@ const ALWAYS_ENGLISH_MD_FILES = new Set([
2331
])
2432

2533
// Returns all the things inside a directory
26-
export const getDeepDataByLanguage = memoize((dottedPath, langCode, dir = null) => {
27-
if (!(langCode in languages))
28-
throw new Error(`langCode '${langCode}' not a recognized language code`)
34+
export const getDeepDataByLanguage = memoize(
35+
(dottedPath: string, langCode: string, dir: string | null = null): any => {
36+
if (!(langCode in languages)) {
37+
throw new Error(`langCode '${langCode}' not a recognized language code`)
38+
}
2939

30-
// The `dir` argument is only used for testing purposes.
31-
// For example, our unit tests that depend on using a fixtures
32-
// root.
33-
// If we don't allow those tests to override the `dir` argument,
34-
// it'll be stuck from the first time `languages.js` was imported.
35-
if (dir === null) {
36-
dir = languages[langCode].dir
37-
}
38-
return getDeepDataByDir(dottedPath, dir)
39-
})
40+
// The `dir` argument is only used for testing purposes.
41+
// For example, our unit tests that depend on using a fixtures
42+
// root.
43+
// If we don't allow those tests to override the `dir` argument,
44+
// it'll be stuck from the first time `languages.js` was imported.
45+
let actualDir = dir
46+
if (actualDir === null) {
47+
actualDir = languages[langCode].dir
48+
}
49+
return getDeepDataByDir(dottedPath, actualDir)
50+
},
51+
)
4052

4153
// Doesn't need to be memoized because it's used by getDataKeysByLanguage
4254
// which is already memoized.
43-
function getDeepDataByDir(dottedPath, dir) {
55+
function getDeepDataByDir(dottedPath: string, dir: string): any {
4456
const fullPath = ['data']
4557
const split = dottedPath.split(/\./g)
4658
fullPath.push(...split)
4759

48-
const things = {}
60+
const things: any = {}
4961
const relPath = fullPath.join(path.sep)
5062
for (const dirent of getDirents(dir, relPath)) {
5163
if (dirent.name === 'README.md') continue
@@ -63,12 +75,12 @@ function getDeepDataByDir(dottedPath, dir) {
6375
return things
6476
}
6577

66-
function getDirents(root, relPath) {
78+
function getDirents(root: string, relPath: string): fs.Dirent[] {
6779
const filePath = root ? path.join(root, relPath) : relPath
6880
return fs.readdirSync(filePath, { withFileTypes: true })
6981
}
7082

71-
export const getUIDataMerged = memoize((langCode) => {
83+
export const getUIDataMerged = memoize((langCode: string): any => {
7284
const uiEnglish = getUIData('en')
7385
if (langCode === 'en') return uiEnglish
7486
// Got to combine. Start with the English and put the translation on top.
@@ -77,21 +89,21 @@ export const getUIDataMerged = memoize((langCode) => {
7789
// swedish = {food: "Mat"}
7890
// =>
7991
// combind = {food: "Mat", drink: "Drink"}
80-
const combined = {}
92+
const combined: any = {}
8193
merge(combined, uiEnglish)
8294
merge(combined, getUIData(langCode))
8395
return combined
8496
})
8597

8698
// Doesn't need to be memoized because it's used by another function
8799
// that is memoized.
88-
const getUIData = (langCode) => {
100+
const getUIData = (langCode: string): any => {
89101
const fullPath = ['data', 'ui.yml']
90102
const { dir } = languages[langCode]
91103
return getYamlContent(dir, fullPath.join(path.sep))
92104
}
93105

94-
export const getDataByLanguage = memoize((dottedPath, langCode) => {
106+
export const getDataByLanguage = memoize((dottedPath: string, langCode: string): any => {
95107
if (!(langCode in languages))
96108
throw new Error(`langCode '${langCode}' not a recognized language code`)
97109
const { dir } = languages[langCode]
@@ -111,7 +123,7 @@ export const getDataByLanguage = memoize((dottedPath, langCode) => {
111123
}
112124
return value
113125
} catch (error) {
114-
if (error instanceof Error && error.mark && error.message) {
126+
if (error instanceof Error && (error as YAMLException).mark && error.message) {
115127
// It's a yaml.load() generated error!
116128
// Remember, the file that we read might have been a .yml or a .md
117129
// file. If it was a .md file, with corrupt front-matter that too
@@ -128,12 +140,17 @@ export const getDataByLanguage = memoize((dottedPath, langCode) => {
128140
throw error
129141
}
130142

131-
if (error.code === 'ENOENT') return undefined
143+
if ((error as FileSystemError).code === 'ENOENT') return undefined
132144
throw error
133145
}
134146
})
135147

136-
function getDataByDir(dottedPath, dir, englishRoot, langCode) {
148+
function getDataByDir(
149+
dottedPath: string,
150+
dir: string,
151+
englishRoot?: string,
152+
langCode?: string,
153+
): any {
137154
const fullPath = ['data']
138155

139156
// Using English here because it doesn't matter. We just want to
@@ -159,29 +176,29 @@ function getDataByDir(dottedPath, dir, englishRoot, langCode) {
159176
// data/early-access/reusables/foo/bar.md
160177
//
161178
if (split[0] === 'early-access') {
162-
fullPath.push(split.shift())
179+
fullPath.push(split.shift()!)
163180
}
164181
const first = split[0]
165182

166183
if (first === 'variables') {
167-
const key = split.pop()
168-
const basename = split.pop()
184+
const key = split.pop()!
185+
const basename = split.pop()!
169186
fullPath.push(...split)
170187
fullPath.push(`${basename}.yml`)
171188
const allData = getYamlContent(dir, fullPath.join(path.sep), englishRoot)
172-
if (allData) {
189+
if (allData && key) {
173190
const value = allData[key]
174191
if (value) {
175192
return matter(value).content
176193
}
177194
} else {
178195
console.warn(`Unable to find variables Yaml file ${fullPath.join(path.sep)}`)
179196
}
180-
return
197+
return undefined
181198
}
182199

183200
if (first === 'reusables') {
184-
const nakedname = split.pop()
201+
const nakedname = split.pop()!
185202
fullPath.push(...split)
186203
fullPath.push(`${nakedname}.md`)
187204
const markdown = getMarkdownContent(dir, fullPath.join(path.sep), englishRoot)
@@ -205,7 +222,7 @@ function getDataByDir(dottedPath, dir, englishRoot, langCode) {
205222
// genuinely give it the English equivalent content, which it
206223
// sometimes uses to correct some Liquid tags. At least other
207224
// good corrections might happen.
208-
if (error.code !== 'ENOENT') {
225+
if ((error as FileSystemError).code !== 'ENOENT') {
209226
throw error
210227
}
211228
}
@@ -226,25 +243,25 @@ function getDataByDir(dottedPath, dir, englishRoot, langCode) {
226243
}
227244

228245
if (first === 'product-examples' || first === 'glossaries' || first === 'release-notes') {
229-
const basename = split.pop()
246+
const basename = split.pop()!
230247
fullPath.push(...split)
231248
fullPath.push(`${basename}.yml`)
232249
return getYamlContent(dir, fullPath.join(path.sep), englishRoot)
233250
}
234251

235252
if (first === 'learning-tracks') {
236-
const key = split.pop()
237-
const basename = split.pop()
253+
const key = split.pop()!
254+
const basename = split.pop()!
238255
fullPath.push(...split)
239256
fullPath.push(`${basename}.yml`)
240257
const allData = getYamlContent(dir, fullPath.join(path.sep), englishRoot)
241-
return allData[key]
258+
return key ? allData[key] : undefined
242259
}
243260

244261
throw new Error(`Can't find the key '${dottedPath}' in the scope.`)
245262
}
246263

247-
function getSmartSplit(dottedPath) {
264+
function getSmartSplit(dottedPath: string): string[] {
248265
const split = dottedPath.split('.')
249266
const bits = []
250267
for (let i = 0, len = split.length; i < len; i++) {
@@ -284,47 +301,55 @@ function getSmartSplit(dottedPath) {
284301
// 2.1. read and parse data/variables/product.yml
285302
// -> cache HIT (Yay!)
286303
//
287-
const getYamlContent = memoize((root, relPath, englishRoot) => {
288-
// Certain Yaml files we know we always want the English one
289-
// no matter what the specified language is.
290-
// For example, we never want `data/variables/product.yml` translated
291-
// so we know to immediately fall back to the English one.
292-
if (ALWAYS_ENGLISH_YAML_FILES.has(relPath)) {
293-
// This forces it to read from English. Later, when it goes
294-
// into `getFileContent(...)` it will note that `root !== englishRoot`
295-
// so it won't try to fall back.
296-
root = englishRoot
297-
}
298-
const fileContent = getFileContent(root, relPath, englishRoot)
299-
return yaml.load(fileContent, { filename: relPath })
300-
})
304+
const getYamlContent = memoize(
305+
(root: string | undefined, relPath: string, englishRoot?: string): any => {
306+
// Certain Yaml files we know we always want the English one
307+
// no matter what the specified language is.
308+
// For example, we never want `data/variables/product.yml` translated
309+
// so we know to immediately fall back to the English one.
310+
if (ALWAYS_ENGLISH_YAML_FILES.has(relPath)) {
311+
// This forces it to read from English. Later, when it goes
312+
// into `getFileContent(...)` it will note that `root !== englishRoot`
313+
// so it won't try to fall back.
314+
root = englishRoot
315+
}
316+
const fileContent = getFileContent(root, relPath, englishRoot)
317+
return yaml.load(fileContent, { filename: relPath })
318+
},
319+
)
301320

302321
// The reason why this is memoized, is the same as for getYamlContent() above.
303-
const getMarkdownContent = memoize((root, relPath, englishRoot) => {
304-
// Certain reusables we never want to be pulled from the translations.
305-
// For example, certain reusables don't contain any English prose. Just
306-
// facts like numbers or hardcoded key words.
307-
// If this is the case, forcibly always draw from the English files.
308-
if (ALWAYS_ENGLISH_MD_FILES.has(relPath)) {
309-
root = englishRoot
310-
}
322+
const getMarkdownContent = memoize(
323+
(root: string | undefined, relPath: string, englishRoot?: string): string => {
324+
// Certain reusables we never want to be pulled from the translations.
325+
// For example, certain reusables don't contain any English prose. Just
326+
// facts like numbers or hardcoded key words.
327+
// If this is the case, forcibly always draw from the English files.
328+
if (ALWAYS_ENGLISH_MD_FILES.has(relPath)) {
329+
root = englishRoot
330+
}
311331

312-
const fileContent = getFileContent(root, relPath, englishRoot)
313-
return matter(fileContent).content.trimEnd()
314-
})
332+
const fileContent = getFileContent(root, relPath, englishRoot)
333+
return matter(fileContent).content.trimEnd()
334+
},
335+
)
315336

316-
const getFileContent = (root, relPath, englishRoot) => {
337+
const getFileContent = (
338+
root: string | undefined,
339+
relPath: string,
340+
englishRoot?: string,
341+
): string => {
317342
const filePath = root ? path.join(root, relPath) : relPath
318343
if (DEBUG_JIT_DATA_READS) console.log('READ', filePath)
319344
try {
320345
return fs.readFileSync(filePath, 'utf-8')
321346
} catch (err) {
322347
// It might fail because that particular data entry doesn't yet
323348
// exist in a translation
324-
if (err.code === 'ENOENT') {
349+
if ((err as FileSystemError).code === 'ENOENT') {
325350
// If looking it up as a file fails, give it one more chance if the
326351
// read was for a translation.
327-
if (root !== englishRoot) {
352+
if (englishRoot && root !== englishRoot) {
328353
// We can try again but this time using the English files
329354
return getFileContent(englishRoot, relPath, englishRoot)
330355
}
@@ -333,9 +358,9 @@ const getFileContent = (root, relPath, englishRoot) => {
333358
}
334359
}
335360

336-
function memoize(func) {
337-
const cache = new Map()
338-
return (...args) => {
361+
function memoize<T extends (...args: any[]) => any>(func: T): T {
362+
const cache = new Map<string, any>()
363+
return ((...args: any[]) => {
339364
if (process.env.NODE_ENV === 'development') {
340365
// It is very possible that certain files, when caching is disabled,
341366
// are read multiple times in short succession. E.g. `product.yml`.
@@ -374,5 +399,5 @@ function memoize(func) {
374399
if (Array.isArray(value)) return [...value]
375400
if (typeof value === 'object') return { ...value }
376401
return value
377-
}
402+
}) as T
378403
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { DataDirectory } from '@/tests/helpers/data-directory'
1313

1414
describe('get-data', () => {
15-
let dd
15+
let dd: DataDirectory
1616
const enDirBefore = languages.en.dir
1717
// Only `en` is available in tests, so pretend we also have Japanese
1818
languages.ja = Object.assign({}, languages.en, {})
@@ -219,7 +219,7 @@ front: >'matter
219219
`.trim()
220220

221221
describe('get-data on corrupt translations', () => {
222-
let dd
222+
let dd: DataDirectory
223223
const enDirBefore = languages.en.dir
224224
// Only `en` is available in vitest tests, so pretend we also have Japanese
225225
languages.ja = Object.assign({}, languages.en, {})

0 commit comments

Comments
 (0)