Skip to content

Commit 47763c5

Browse files
author
Peter Bengtsson
authored
Script to find orphaned assets (#23567)
* script/find-orphaned-assets.mjs to list orphan images * better filtering
1 parent c200f12 commit 47763c5

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

script/find-orphaned-assets.mjs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env node
2+
3+
// [start-readme]
4+
//
5+
// Print a list of all the asset files that can't be found mentioned
6+
// in any of the source files (content & code).
7+
//
8+
// [end-readme]
9+
10+
import fs from 'fs'
11+
import path from 'path'
12+
import program from 'commander'
13+
import walk from 'walk-sync'
14+
15+
program
16+
.description('Print all images that are in ./assets/ but not found in any markdown')
17+
.option('-e, --exit', 'Exit script by count of orphans (useful for CI)')
18+
.option('-v, --verbose', 'Verbose outputs')
19+
.option('--json', 'Output in JSON format')
20+
.option('--exclude-translations', "Don't search in translations/")
21+
.parse(process.argv)
22+
23+
main(program.opts(), program.args)
24+
25+
async function main(opts) {
26+
const { json, verbose, exit, excludeTranslations } = opts
27+
28+
const walkOptions = {
29+
directories: false,
30+
includeBasePath: true,
31+
}
32+
const sourceFiles = []
33+
const roots = [
34+
'content',
35+
'data',
36+
'tests',
37+
'components',
38+
'script',
39+
'stylesheets',
40+
'contributing',
41+
'pages',
42+
]
43+
if (!excludeTranslations) {
44+
roots.push('translations')
45+
}
46+
47+
for (const root of roots) {
48+
sourceFiles.push(
49+
...walk(
50+
root,
51+
Object.assign(
52+
{
53+
globs: ['!**/*.+(png|csv|graphql|json|svg)'],
54+
},
55+
walkOptions
56+
)
57+
)
58+
)
59+
}
60+
// Add exceptions
61+
sourceFiles.push('CONTRIBUTING.md')
62+
sourceFiles.push('README.md')
63+
verbose && console.log(`${sourceFiles.length.toLocaleString()} source files found in total.`)
64+
65+
const allImages = new Set(
66+
walk(
67+
'assets',
68+
Object.assign(
69+
{
70+
globs: ['!**/*.+(md)'],
71+
},
72+
walkOptions
73+
)
74+
).filter((filePath) => !filePath.endsWith('.md'))
75+
)
76+
77+
verbose && console.log(`${allImages.size.toLocaleString()} images found in total.`)
78+
79+
for (const markdownFile of sourceFiles) {
80+
const content = fs.readFileSync(markdownFile, 'utf-8')
81+
for (const imagePath of allImages) {
82+
const needle = imagePath.split(path.sep).slice(-2).join('/')
83+
if (content.includes(needle)) {
84+
allImages.delete(imagePath)
85+
}
86+
}
87+
}
88+
89+
if (verbose && allImages.size) {
90+
console.log('The following files are not mentioned anywhere in any Markdown file')
91+
}
92+
if (json) {
93+
console.log(JSON.stringify([...allImages], undefined, 2))
94+
} else {
95+
for (const imagePath of [...allImages].sort((a, b) => a.localeCompare(b))) {
96+
console.log(imagePath)
97+
}
98+
}
99+
100+
if (verbose) {
101+
console.log(`${allImages.size.toLocaleString()} orphans left.`)
102+
const totalDiskSize = getTotalDiskSize(allImages)
103+
console.log(`Total disk size of all of these: ${(totalDiskSize / 1024 / 1024).toFixed(1)}MB`)
104+
}
105+
106+
if (exit) {
107+
process.exit(allImages.size)
108+
}
109+
}
110+
111+
function getTotalDiskSize(filePaths) {
112+
let sum = 0
113+
for (const filePath of filePaths) {
114+
sum += fs.statSync(filePath).size
115+
}
116+
return sum
117+
}

0 commit comments

Comments
 (0)