mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-08-28 02:44:59 +00:00
117 lines
3.1 KiB
JavaScript
117 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
import { readFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
|
|
const forbiddenShimPatterns = [
|
|
/Downloading Electron binary/,
|
|
/Electron failed to install correctly/,
|
|
/(?:^|[\\/])install\.js/,
|
|
];
|
|
|
|
const artifacts = [
|
|
{
|
|
file: 'desktop/out/main/index.js',
|
|
requiredSymbols: ['app', 'BrowserWindow'],
|
|
},
|
|
{
|
|
file: 'desktop/out/preload/index.cjs',
|
|
requiredSymbols: ['contextBridge', 'ipcRenderer'],
|
|
},
|
|
];
|
|
|
|
function parseBindings(bindings) {
|
|
return new Set(
|
|
bindings
|
|
.split(',')
|
|
.map((binding) =>
|
|
binding
|
|
.trim()
|
|
.split(/\s+as\s+/)[0]
|
|
?.trim()
|
|
)
|
|
.filter(Boolean)
|
|
);
|
|
}
|
|
|
|
function electronBindings(source) {
|
|
const namedImport = source.match(/\bimport\s*{([^}]+)}\s*from\s*["']electron["']/s);
|
|
const destructuredRequire = source.match(
|
|
/\b(?:const|let|var)\s*{([^}]+)}\s*=\s*require\(\s*["']electron["']\s*\)/s
|
|
);
|
|
const namespaceRequire = source.match(
|
|
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\(\s*["']electron["']\s*\)/
|
|
);
|
|
|
|
return {
|
|
named: namedImport
|
|
? parseBindings(namedImport[1])
|
|
: destructuredRequire
|
|
? parseBindings(destructuredRequire[1])
|
|
: new Set(),
|
|
namespace: namespaceRequire?.[1],
|
|
};
|
|
}
|
|
|
|
export function validateElectronArtifact(source, requiredSymbols) {
|
|
const errors = [];
|
|
|
|
for (const pattern of forbiddenShimPatterns) {
|
|
if (pattern.test(source)) {
|
|
errors.push(`contains bundled Electron installer shim pattern ${pattern}`);
|
|
}
|
|
}
|
|
|
|
const bindings = electronBindings(source);
|
|
if (bindings.named.size === 0 && !bindings.namespace) {
|
|
errors.push('does not import the runtime-provided Electron module');
|
|
}
|
|
|
|
for (const symbol of requiredSymbols) {
|
|
const namedBinding = bindings.named.has(symbol);
|
|
const namespaceBinding =
|
|
bindings.namespace && new RegExp(`\\b${bindings.namespace}\\.${symbol}\\b`).test(source);
|
|
if (!namedBinding && !namespaceBinding) {
|
|
errors.push(`does not bind required Electron API symbol ${symbol} from Electron`);
|
|
}
|
|
}
|
|
|
|
return errors;
|
|
}
|
|
|
|
async function main() {
|
|
let failed = false;
|
|
|
|
for (const artifact of artifacts) {
|
|
const absolutePath = path.join(rootDir, artifact.file);
|
|
let source;
|
|
|
|
try {
|
|
source = await readFile(absolutePath, 'utf8');
|
|
} catch {
|
|
failed = true;
|
|
console.error(`Desktop Electron artifact check failed: ${artifact.file} is missing.`);
|
|
continue;
|
|
}
|
|
|
|
const errors = validateElectronArtifact(source, artifact.requiredSymbols);
|
|
if (errors.length > 0) {
|
|
failed = true;
|
|
for (const error of errors) {
|
|
console.error(`Desktop Electron artifact check failed: ${artifact.file} ${error}.`);
|
|
}
|
|
} else {
|
|
console.log(`Desktop Electron artifact check passed: ${artifact.file}`);
|
|
}
|
|
}
|
|
|
|
if (failed) {
|
|
process.exitCode = 1;
|
|
}
|
|
}
|
|
|
|
if (path.resolve(process.argv[1] || '') === fileURLToPath(import.meta.url)) {
|
|
await main();
|
|
}
|