Something went wrong. Try again.
Browser extension: detect and subscribe to standard.site publications on ATProto
Something went wrong. Try again.
3.5 kB · 91 lines
JavaScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192// Verifies that dist/ is a loadable MV3 extension: the manifest parses and// every file it references exists, and every local asset referenced from the// built HTML pages exists. Plain node, no dependencies.//// Usage: node scripts/verify-dist.mjs [distDir]
import { existsSync, readFileSync, readdirSync } from 'node:fs'import { dirname, join, resolve } from 'node:path'
const dist = resolve(process.argv[2] ?? 'dist')const problems = []let checked = 0
function requireFile(rel, why) { checked++ if (!existsSync(join(dist, rel))) problems.push(`missing ${rel} (${why})`)}
if (!existsSync(dist)) { console.error(`verify-dist: ${dist} does not exist — run \`npm run build\` first`) process.exit(1)}
let manifesttry { manifest = JSON.parse(readFileSync(join(dist, 'manifest.json'), 'utf8'))} catch (err) { console.error(`verify-dist: cannot read dist/manifest.json: ${err.message}`) process.exit(1)}
if (manifest.manifest_version !== 3) { problems.push(`manifest_version is ${manifest.manifest_version}, expected 3`)}
// Files the manifest references.for (const icon of Object.values(manifest.icons ?? {})) { requireFile(icon, 'manifest icons')}for (const icon of Object.values(manifest.action?.default_icon ?? {})) { requireFile(icon, 'action.default_icon')}if (manifest.background?.service_worker) { requireFile(manifest.background.service_worker, 'background.service_worker')}for (const cs of manifest.content_scripts ?? []) { for (const js of cs.js ?? []) requireFile(js, 'content_scripts js') for (const css of cs.css ?? []) requireFile(css, 'content_scripts css')}if (manifest.action?.default_popup) { requireFile(manifest.action.default_popup, 'action.default_popup')}for (const war of manifest.web_accessible_resources ?? []) { for (const res of war.resources ?? []) { if (!res.includes('*')) requireFile(res, 'web_accessible_resources') }}
// Pages created at runtime rather than referenced from the manifest.requireFile('offscreen.html', 'created by the worker via chrome.offscreen')requireFile('welcome.html', 'opened by the worker on install (src/lib/welcome.ts)')
// Vendored assets referenced from built JS as extension-root "/vendored/..."// string literals (reader icons in src/lib/readers.ts).for (const name of readdirSync(dist, { recursive: true }).filter((f) => f.endsWith('.js'))) { const js = readFileSync(join(dist, name), 'utf8') for (const m of js.matchAll(/"(\/vendored\/[\w.-]+)"/g)) { requireFile(m[1].slice(1), `referenced by ${name}`) } // A sourceMappingURL pointing at a file that did not ship reads as a // broken build to anyone reviewing it, and gives a 404 in devtools. const map = /\/\/# sourceMappingURL=(\S+)/.exec(js) if (map) requireFile(join(dirname(String(name)), map[1]), `sourcemap of ${name}`)}
// Local script/stylesheet references inside built HTML pages.for (const name of readdirSync(dist).filter((f) => f.endsWith('.html'))) { const html = readFileSync(join(dist, name), 'utf8') for (const m of html.matchAll(/(?:src|href)="([^"]+)"/g)) { const ref = m[1] if (/^[a-z]+:/i.test(ref) || ref.startsWith('#')) continue // external / anchor requireFile(ref.replace(/^\.?\//, '').split(/[?#]/)[0], `referenced by ${name}`) }}
if (problems.length > 0) { console.error(`verify-dist: FAILED (${problems.length} problem(s)):`) for (const p of problems) console.error(` - ${p}`) process.exit(1)}console.log(`verify-dist: OK — ${checked} referenced files present in ${dist}`)