59 lines
2.3 KiB
JavaScript
59 lines
2.3 KiB
JavaScript
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
|
|
import { extname, join, relative } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const root = fileURLToPath(new URL('../', import.meta.url))
|
|
const textExtensions = new Set(['.css', '.html', '.js', '.json', '.md', '.mjs', '.ts', '.vue', '.yml', '.yaml'])
|
|
const textFileNames = new Set(['Dockerfile', 'nginx.conf', '.dockerignore', '.gitignore'])
|
|
const ignoredDirectories = new Set(['.git', 'dist', 'node_modules'])
|
|
const problems = []
|
|
|
|
function walk(directory) {
|
|
for (const name of readdirSync(directory)) {
|
|
if (ignoredDirectories.has(name)) continue
|
|
const path = join(directory, name)
|
|
const stats = statSync(path)
|
|
if (stats.isDirectory()) {
|
|
walk(path)
|
|
continue
|
|
}
|
|
if (!textExtensions.has(extname(name)) && !textFileNames.has(name) && !name.startsWith('.env')) continue
|
|
|
|
const text = readFileSync(path, 'utf8')
|
|
const file = relative(root, path)
|
|
if (/\r/.test(text)) problems.push(`${file}: use LF line endings`)
|
|
text.split('\n').forEach((line, index) => {
|
|
if (/[ \t]+$/.test(line)) problems.push(`${file}:${index + 1}: trailing whitespace`)
|
|
})
|
|
}
|
|
}
|
|
|
|
walk(root)
|
|
|
|
const config = JSON.parse(readFileSync(join(root, 'public/overlays/overlays.json'), 'utf8'))
|
|
if (!Array.isArray(config)) problems.push('public/overlays/overlays.json: expected an array')
|
|
const ids = new Set()
|
|
const files = new Set()
|
|
for (const [index, item] of (Array.isArray(config) ? config : []).entries()) {
|
|
const id = typeof item?.id === 'string' ? item.id.trim() : ''
|
|
const name = typeof item?.name === 'string' ? item.name.trim() : ''
|
|
const file = typeof item?.file === 'string' ? item.file.trim() : ''
|
|
if (!id || !name || !/^[A-Za-z0-9][A-Za-z0-9._ -]*\.(?:png|jpe?g|webp)$/i.test(file) || file.includes('..')) {
|
|
problems.push(`public/overlays/overlays.json: invalid entry ${index + 1}`)
|
|
}
|
|
if (ids.has(id)) problems.push(`public/overlays/overlays.json: duplicate id ${id}`)
|
|
if (files.has(file)) problems.push(`public/overlays/overlays.json: duplicate file ${file}`)
|
|
if (file && !existsSync(join(root, 'public/overlays', file))) {
|
|
problems.push(`public/overlays/overlays.json: missing file ${file}`)
|
|
}
|
|
ids.add(id)
|
|
files.add(file)
|
|
}
|
|
|
|
if (problems.length) {
|
|
console.error(problems.join('\n'))
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('Quality checks passed.')
|