Skip to content

Commit d35127d

Browse files
authored
Typescript src/assets (#53110)
1 parent 0a72ea7 commit d35127d

10 files changed

+78
-62
lines changed

package-lock.json

+15-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"delete-orphan-translation-files": "tsx src/workflows/delete-orphan-translation-files.ts",
3434
"deleted-features-pr-comment": "tsx src/data-directory/scripts/deleted-features-pr-comment.ts",
3535
"dev": "cross-env npm start",
36-
"find-orphaned-assets": "node src/assets/scripts/find-orphaned-assets.js",
36+
"find-orphaned-assets": "tsx src/assets/scripts/find-orphaned-assets.ts",
3737
"find-orphaned-features": "tsx src/data-directory/scripts/find-orphaned-features/index.ts",
3838
"find-past-built-pr": "tsx src/workflows/find-past-built-pr.ts",
3939
"find-unused-variables": "tsx src/content-linter/scripts/find-unsed-variables.ts",
@@ -259,7 +259,7 @@
259259
"express": "4.21.1",
260260
"express-rate-limit": "7.4.0",
261261
"fastest-levenshtein": "1.0.16",
262-
"file-type": "19.4.1",
262+
"file-type": "19.6.0",
263263
"flat": "^6.0.1",
264264
"github-slugger": "^2.0.0",
265265
"glob": "11.0.0",

src/assets/lib/image-density.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const IMAGE_DENSITY: Record<string, string>

src/assets/scripts/deleted-assets-pr-comment-1.js src/assets/scripts/deleted-assets-pr-comment-1.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@
1818
// [end-readme]
1919

2020
import { program } from 'commander'
21-
import main from './deleted-assets-pr-comment.js'
21+
import main from './deleted-assets-pr-comment'
2222

2323
program
2424
.description('If applicable, print a snippet of Markdown about deleted assets')
25-
.arguments('owner repo base_sha head_sha', 'Simulate what the Actions workflow does')
25+
.arguments('owner repo base_sha head_sha')
2626
.parse(process.argv)
2727

28-
const opts = program.opts()
29-
const args = program.args
28+
type MainArgs = {
29+
owner: string
30+
repo: string
31+
baseSHA: string
32+
headSHA: string
33+
}
34+
const opts = program.opts() as MainArgs
3035

31-
console.log(await main(...args, { ...opts }))
36+
console.log(await main(opts))

src/assets/scripts/deleted-assets-pr-comment.js src/assets/scripts/deleted-assets-pr-comment.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,22 @@ if (!GITHUB_TOKEN) {
1313
// When this file is invoked directly from action as opposed to being imported
1414
if (import.meta.url.endsWith(process.argv[1])) {
1515
const owner = context.repo.owner
16-
const repo = context.payload.repository.name
17-
const baseSHA = context.payload.pull_request.base.sha
18-
const headSHA = context.payload.pull_request.head.sha
16+
const repo = context.payload.repository?.name || ''
17+
const baseSHA = context.payload.pull_request?.base.sha
18+
const headSHA = context.payload.pull_request?.head.sha
1919

20-
const markdown = await main(owner, repo, baseSHA, headSHA)
20+
const markdown = await main({ owner, repo, baseSHA, headSHA })
2121
core.setOutput('markdown', markdown)
2222
}
2323

24-
async function main(owner, repo, baseSHA, headSHA) {
25-
const octokit = github.getOctokit(GITHUB_TOKEN)
24+
type MainArgs = {
25+
owner: string
26+
repo: string
27+
baseSHA: string
28+
headSHA: string
29+
}
30+
async function main({ owner, repo, baseSHA, headSHA }: MainArgs) {
31+
const octokit = github.getOctokit(GITHUB_TOKEN as string)
2632
// get the list of file changes from the PR
2733
const response = await octokit.rest.repos.compareCommitsWithBasehead({
2834
owner,
@@ -32,6 +38,10 @@ async function main(owner, repo, baseSHA, headSHA) {
3238

3339
const { files } = response.data
3440

41+
if (!files) {
42+
throw new Error('No files found in the PR')
43+
}
44+
3545
const oldFilenames = []
3646
for (const file of files) {
3747
const { filename, status } = file

src/assets/scripts/find-orphaned-assets.js src/assets/scripts/find-orphaned-assets.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const EXCEPTIONS = new Set([
3232
'assets/images/site/apple-touch-icon-76x76.png',
3333
])
3434

35-
function isExceptionPath(imagePath) {
35+
function isExceptionPath(imagePath: string) {
3636
// We also check for .DS_Store because any macOS user that has opened
3737
// a folder with images will have this on disk. It won't get added
3838
// to git anyway thanks to our .DS_Store.
@@ -53,9 +53,15 @@ program
5353
.option('--exclude-translations', "Don't search in translations/")
5454
.parse(process.argv)
5555

56-
main(program.opts(), program.args)
56+
type MainOptions = {
57+
json: boolean
58+
verbose: boolean
59+
exit: boolean
60+
excludeTranslations: boolean
61+
}
62+
main(program.opts())
5763

58-
async function main(opts) {
64+
async function main(opts: MainOptions) {
5965
const { json, verbose, exit, excludeTranslations } = opts
6066

6167
const walkOptions = {
@@ -164,7 +170,7 @@ async function main(opts) {
164170
}
165171
}
166172

167-
function getTotalDiskSize(filePaths) {
173+
function getTotalDiskSize(filePaths: Set<string>) {
168174
let sum = 0
169175
for (const filePath of filePaths) {
170176
sum += fs.statSync(filePath).size

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

+8-14
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,26 @@ import { fileURLToPath } from 'url'
1010
import path from 'path'
1111
import walk from 'walk-sync'
1212
import sharp from 'sharp'
13-
import { chain } from 'lodash-es'
1413
const __dirname = path.dirname(fileURLToPath(import.meta.url))
1514

1615
const imagesPath = path.join(__dirname, '../assets/images')
1716
const imagesExtensions = ['.jpg', '.jpeg', '.png', '.gif']
1817

19-
const files = chain(walk(imagesPath, { directories: false })).filter((relativePath) => {
18+
const files = walk(imagesPath, { directories: false }).filter((relativePath) => {
2019
return imagesExtensions.includes(path.extname(relativePath.toLowerCase()))
2120
})
22-
const infos = await Promise.all(
21+
const images = await Promise.all(
2322
files.map(async (relativePath) => {
2423
const fullPath = path.join(imagesPath, relativePath)
2524
const image = sharp(fullPath)
2625
const { width, height } = await image.metadata()
27-
const size = width * height
26+
const size = (width || 0) * (height || 0)
2827
return { relativePath, width, height, size }
2928
}),
3029
)
31-
const images = files
32-
.map((relativePath, i) => {
33-
return { relativePath, ...infos[i] }
30+
images
31+
.sort((a, b) => b.size - a.size)
32+
.forEach((image) => {
33+
const { relativePath, width, height } = image
34+
console.log(`${width} x ${height} - ${relativePath}`)
3435
})
35-
.orderBy('size', 'desc')
36-
.value()
37-
38-
images.forEach((image) => {
39-
const { relativePath, width, height } = image
40-
console.log(`${width} x ${height} - ${relativePath}`)
41-
})

src/assets/scripts/validate-asset-images.js src/assets/scripts/validate-asset-images.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import path from 'path'
1919
import { program } from 'commander'
2020
import chalk from 'chalk'
2121
import cheerio from 'cheerio'
22+
// @ts-ignore see https://github.com/sindresorhus/file-type/issues/652
2223
import { fileTypeFromFile } from 'file-type'
2324
import walk from 'walk-sync'
2425
import isSVG from 'is-svg'
@@ -43,7 +44,7 @@ const EXPECT = {
4344
'.ico': 'image/x-icon',
4445
'.pdf': 'application/pdf',
4546
'.webp': 'image/webp',
46-
}
47+
} as Record<string, string>
4748

4849
const CRITICAL = 'critical'
4950
const WARNING = 'warning'
@@ -56,7 +57,7 @@ program
5657

5758
main(program.opts())
5859

59-
async function main(opts) {
60+
async function main(opts: { dryRun: boolean; verbose: boolean }) {
6061
let errors = 0
6162

6263
const files = walk(ASSETS_ROOT, { includeBasePath: true, directories: false }).filter(
@@ -71,7 +72,11 @@ async function main(opts) {
7172
)
7273
},
7374
)
74-
const results = (await Promise.all(files.map(checkFile))).filter(Boolean)
75+
const results = (await Promise.all(files.map(checkFile))).filter(Boolean) as [
76+
level: string,
77+
filePath: string,
78+
error: string,
79+
][]
7580
for (const [level, filePath, error] of results) {
7681
console.log(
7782
level === CRITICAL ? chalk.red(level) : chalk.yellow(level),
@@ -94,7 +99,7 @@ async function main(opts) {
9499
process.exitCode = errors
95100
}
96101

97-
async function checkFile(filePath) {
102+
async function checkFile(filePath: string) {
98103
const ext = path.extname(filePath)
99104

100105
const { size } = await fs.stat(filePath)
@@ -113,7 +118,7 @@ async function checkFile(filePath) {
113118
}
114119
try {
115120
checkSVGContent(content)
116-
} catch (error) {
121+
} catch (error: any) {
117122
return [CRITICAL, filePath, error.message]
118123
}
119124
} else if (EXPECT[ext]) {
@@ -135,15 +140,15 @@ async function checkFile(filePath) {
135140
// All is well. Nothing to complain about.
136141
}
137142

138-
function checkSVGContent(content) {
143+
function checkSVGContent(content: string) {
139144
const $ = cheerio.load(content)
140145
const disallowedTagNames = new Set(['script', 'object', 'iframe', 'embed'])
141146
$('*').each((i, element) => {
142-
const { tagName } = element
147+
const { tagName } = $(element).get(0)
143148
if (disallowedTagNames.has(tagName)) {
144149
throw new Error(`contains a <${tagName}> tag`)
145150
}
146-
for (const key in element.attribs) {
151+
for (const key in $(element).get(0).attribs) {
147152
// Looks for suspicious event handlers on tags.
148153
// For example `<path oNload="alert(1)"" d="M28 0l4.59 4.59-9.76`
149154
// We don't need to do a case-sensitive regex here because cheerio

src/assets/tests/static-assets.js src/assets/tests/static-assets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { describe, expect, test, vi } from 'vitest'
66
import { get } from '#src/tests/helpers/e2etest.js'
77
import { checkCachingHeaders } from '#src/tests/helpers/caching-headers.js'
88

9-
function getNextStaticAsset(directory) {
9+
function getNextStaticAsset(directory: string) {
1010
const root = path.join('.next', 'static', directory)
1111
const files = fs.readdirSync(root)
1212
if (!files.length) throw new Error(`Can't find any files in ${root}`)

tsconfig.json

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
{
22
"compilerOptions": {
33
"target": "ES2022",
4-
"lib": [
5-
"dom",
6-
"dom.iterable",
7-
"esnext"
8-
],
4+
"lib": ["dom", "dom.iterable", "esnext"],
95
"allowJs": true,
106
"skipLibCheck": true,
117
"strict": true,
@@ -30,9 +26,5 @@
3026
"docs-internal-data",
3127
"src/code-scanning/scripts/generate-code-scanning-query-list.ts"
3228
],
33-
"include": [
34-
"*.d.ts",
35-
"**/*.ts",
36-
"**/*.tsx"
37-
]
29+
"include": ["*.d.ts", "**/*.ts", "**/*.tsx"]
3830
}

0 commit comments

Comments
 (0)