mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
Keep chrome69 downleveling for Android 9 WebViews, but only hard-fail on logical assignment after transpile. Regex/polyfill feature detects and minified ternaries can contain `??`/`?.` character sequences that are not optional chaining or nullish coalescing operators.
94 lines
2.4 KiB
JavaScript
94 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
import { promises as fs } from 'node:fs';
|
||
import path from 'node:path';
|
||
import { transform } from 'esbuild';
|
||
|
||
// Android 9 / Amlogic TV WebViews are often Chrome 66–74.
|
||
// chrome83 still emits `??` (Chrome 80+), which white-screens those devices.
|
||
// chrome69 downlevels `??` / `?.` / logical assignment in application code.
|
||
const TARGET = 'chrome69';
|
||
// Hard-fail only on logical assignment: unambiguous and never appears in polyfill
|
||
// feature-detect regexes (e.g. `/()??/`) or minified ternaries (`E?.3:1`).
|
||
const UNSUPPORTED_LOGICAL_ASSIGNMENT = /(\?\?=|\|\|=|&&=)/;
|
||
|
||
async function pathExists(filePath) {
|
||
try {
|
||
await fs.access(filePath);
|
||
return true;
|
||
} catch {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
async function collectJavaScriptFiles(rootDir) {
|
||
const entries = await fs.readdir(rootDir, { withFileTypes: true });
|
||
const files = [];
|
||
|
||
for (const entry of entries) {
|
||
const entryPath = path.join(rootDir, entry.name);
|
||
|
||
if (entry.isDirectory()) {
|
||
files.push(...await collectJavaScriptFiles(entryPath));
|
||
continue;
|
||
}
|
||
|
||
if (entry.isFile() && entry.name.endsWith('.js')) {
|
||
files.push(entryPath);
|
||
}
|
||
}
|
||
|
||
return files;
|
||
}
|
||
|
||
async function transpileFile(filePath) {
|
||
const source = await fs.readFile(filePath, 'utf8');
|
||
const result = await transform(source, {
|
||
target: TARGET,
|
||
loader: 'js',
|
||
minify: true,
|
||
legalComments: 'none',
|
||
});
|
||
|
||
await fs.writeFile(filePath, result.code);
|
||
|
||
if (UNSUPPORTED_LOGICAL_ASSIGNMENT.test(result.code)) {
|
||
throw new Error(`${filePath} still contains logical assignment syntax after ${TARGET} transpilation.`);
|
||
}
|
||
}
|
||
|
||
async function main() {
|
||
const roots = process.argv.slice(2);
|
||
const assetRoots = roots.length > 0 ? roots : ['.next/static', '.vercel/output/static/_next/static'];
|
||
let processedFiles = 0;
|
||
let existingRoots = 0;
|
||
|
||
for (const root of assetRoots) {
|
||
const rootDir = path.resolve(process.cwd(), root);
|
||
|
||
if (!await pathExists(rootDir)) {
|
||
continue;
|
||
}
|
||
|
||
existingRoots += 1;
|
||
const files = await collectJavaScriptFiles(rootDir);
|
||
|
||
for (const file of files) {
|
||
await transpileFile(file);
|
||
processedFiles += 1;
|
||
}
|
||
}
|
||
|
||
if (existingRoots === 0) {
|
||
console.log(`No client asset directories found for ${TARGET} transpilation.`);
|
||
return;
|
||
}
|
||
|
||
console.log(`Transpiled ${processedFiles} client JavaScript asset(s) for ${TARGET}.`);
|
||
}
|
||
|
||
main().catch((error) => {
|
||
console.error(error);
|
||
process.exit(1);
|
||
});
|