chore: scaffold toolchain for the Electron shell

Set up the package, compiler and quality gates before any app code so
every later change lands under the same rules: Node 26 via .nvmrc and
engines, TypeScript 7 in strict mode with the extra strictness flags,
swc for transpiling, oxlint with type-aware, Unicorn and security rules
(eslint-plugin-security and no-unsanitized loaded as JS plugins),
oxfmt, Vitest with a 100% coverage gate, and husky hooks that run the
checks and commitlint.

Type escape hatches, lint suppressions and coverage exemptions are
banned unless registered in exceptions.json. scripts/audit-exceptions
enforces that, and its test runs it against this repository, so an
unregistered suppression fails both the pre-commit hook and CI.

npm 11 blocks dependency install scripts by default. None are needed:
Electron downloads its binary on first use, swc's native binding comes
from optionalDependencies, fsevents ships prebuilt, and
electron-winstaller only serves Squirrel installers, which aren't used.
They are recorded as denied in allowScripts.
This commit is contained in:
2026-09-28 15:52:48 -05:00
commit 648a6dd29c
26 changed files with 14369 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
import { afterEach, expect, it } from 'vitest';
afterEach(() => {
process.exitCode = undefined;
});
it('passes on this repository', async () => {
await import('./audit-exceptions.ts');
expect(process.exitCode).toBe(0);
});
+5
View File
@@ -0,0 +1,5 @@
import { runAudit } from './lib/exceptions.ts';
process.exitCode = await runAudit(process.cwd(), (line) => {
console.log(line);
});
+219
View File
@@ -0,0 +1,219 @@
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { audit, parseRegistry, runAudit, unitCoverageExemptPaths } from './exceptions.ts';
const approved = (id: string, kind: string, paths: string[]): Record<string, unknown> => ({
id,
kind,
paths,
reason: 'test reason',
approvedBy: 'test approver',
});
describe('parseRegistry', () => {
it('accepts a well-formed registry', () => {
const registry = parseRegistry({
exceptions: [approved('LINT-1', 'lint-suppression', ['src/a.ts'])],
});
expect(registry.exceptions).toHaveLength(1);
});
it('rejects entries with an unknown kind', () => {
expect(() =>
parseRegistry({ exceptions: [approved('X-1', 'anything-goes', ['src/a.ts'])] }),
).toThrow(/kind/u);
});
it('rejects duplicate ids', () => {
expect(() =>
parseRegistry({
exceptions: [
approved('LINT-1', 'lint-suppression', ['src/a.ts']),
approved('LINT-1', 'lint-suppression', ['src/b.ts']),
],
}),
).toThrow(/duplicate id LINT-1/u);
});
it('rejects ids that the APPROVED(...) marker cannot express', () => {
expect(() =>
parseRegistry({ exceptions: [approved('lint one', 'lint-suppression', ['src/a.ts'])] }),
).toThrow(/id/u);
});
});
describe('audit', () => {
const registry = parseRegistry({
exceptions: [
approved('LINT-1', 'lint-suppression', ['src/a.ts']),
approved('COV-1', 'coverage-ignore', ['src/**/*.ts']),
approved('DTS-1', 'dts-shim', ['src/types/mdts.d.ts']),
approved('UNIT-1', 'unit-coverage', ['src/main/electron/**']),
],
});
const baseline = [
{ path: 'src/a.ts', content: 'export const a = 1;\n' },
{ path: 'src/types/mdts.d.ts', content: 'export {};\n' },
{ path: 'src/main/electron/menu.ts', content: 'export {};\n' },
];
it('passes a tree with no suppressions and no stale entries', () => {
const files = [
...baseline,
{ path: 'src/a.ts', content: 'x(); // oxlint-disable-line no-x -- APPROVED(LINT-1)\n' },
{ path: 'src/b.ts', content: '/* v8 ignore next -- APPROVED(COV-1) */\n' },
];
expect(audit(files, registry)).toStrictEqual([]);
});
it('flags an oxlint suppression without an approval marker', () => {
const files = [
...baseline,
{ path: 'src/a.ts', content: 'const a = 1;\n// oxlint-disable-next-line no-x\n' },
];
expect(audit(files, registry)).toStrictEqual([
'src/a.ts:2: suppression has no APPROVED(<id>) marker',
]);
});
it('treats eslint directives, c8 and istanbul comments the same way', () => {
const files = [
...baseline,
{
path: 'src/c.ts',
content: '/* eslint-disable no-x */\n/* c8 ignore next */\n// istanbul ignore else\n',
},
];
expect(audit(files, registry)).toStrictEqual([
'src/c.ts:1: suppression has no APPROVED(<id>) marker',
'src/c.ts:2: suppression has no APPROVED(<id>) marker',
'src/c.ts:3: suppression has no APPROVED(<id>) marker',
]);
});
it('ignores directive text inside string literals', () => {
const content = [
"const a = '// oxlint-disable';",
"const b = 'x(); /* v8 ignore next */';",
'const c = "it\\"s // eslint-disable";',
'const d = `// c8 ignore next`;',
"// a comment that doesn't disable anything",
'',
].join('\n');
const files = [...baseline, { path: 'src/d.ts', content }];
expect(audit(files, registry)).toStrictEqual([]);
});
it('flags an approval id that is not in the registry', () => {
const files = [
...baseline,
{ path: 'src/a.ts', content: '// oxlint-disable -- APPROVED(NOPE)\n' },
];
expect(audit(files, registry)).toStrictEqual([
'src/a.ts:1: APPROVED(NOPE) is not in exceptions.json',
]);
});
it('flags an approval whose entry does not cover the file', () => {
const files = [
...baseline,
{ path: 'src/other.ts', content: '// oxlint-disable-line -- APPROVED(LINT-1)\n' },
];
expect(audit(files, registry)).toStrictEqual([
'src/other.ts:1: APPROVED(LINT-1) does not cover this file',
]);
});
it('flags an approval of the wrong kind', () => {
const files = [
...baseline,
{ path: 'src/a.ts', content: '// oxlint-disable-line -- APPROVED(COV-1)\n' },
];
expect(audit(files, registry)).toStrictEqual([
'src/a.ts:1: APPROVED(COV-1) is a coverage-ignore exception, not lint-suppression',
]);
});
it('flags a declaration file with no dts-shim entry', () => {
const files = [...baseline, { path: 'src/types/other.d.ts', content: 'export {};\n' }];
expect(audit(files, registry)).toStrictEqual([
'src/types/other.d.ts: declaration file is not approved in exceptions.json',
]);
});
it('flags registry entries that no longer match any file', () => {
expect(audit([], registry)).toStrictEqual([
'exceptions.json: LINT-1 matches no files',
'exceptions.json: COV-1 matches no files',
'exceptions.json: DTS-1 matches no files',
'exceptions.json: UNIT-1 matches no files',
]);
});
});
describe('unitCoverageExemptPaths', () => {
it('lists the paths of unit-coverage entries only', () => {
const registry = parseRegistry({
exceptions: [
approved('UNIT-1', 'unit-coverage', ['src/main/electron/**', 'src/main/index.ts']),
approved('LINT-1', 'lint-suppression', ['src/a.ts']),
],
});
expect(unitCoverageExemptPaths(registry)).toStrictEqual([
'src/main/electron/**',
'src/main/index.ts',
]);
});
});
describe('runAudit', () => {
let root = '';
const lines: string[] = [];
const log = (line: string): void => {
lines.push(line);
};
beforeEach(async () => {
root = await mkdtemp(path.join(tmpdir(), 'audit-'));
lines.length = 0;
await mkdir(path.join(root, 'src'), { recursive: true });
await mkdir(path.join(root, 'node_modules', 'pkg'), { recursive: true });
await writeFile(
path.join(root, 'exceptions.json'),
JSON.stringify({ exceptions: [approved('LINT-1', 'lint-suppression', ['src/a.ts'])] }),
);
await writeFile(path.join(root, 'node_modules', 'pkg', 'index.d.ts'), 'export {};\n');
});
afterEach(async () => {
await rm(root, { recursive: true, force: true });
});
it('returns 0 and reports success for a clean tree', async () => {
await writeFile(path.join(root, 'src', 'a.ts'), '// oxlint-disable-line -- APPROVED(LINT-1)\n');
await expect(runAudit(root, log)).resolves.toBe(0);
expect(lines).toStrictEqual(['audit-exceptions: 1 approved exception, no problems']);
});
it('returns 1 and prints every problem', async () => {
await writeFile(path.join(root, 'src', 'a.ts'), '// oxlint-disable-line no-x\n');
await expect(runAudit(root, log)).resolves.toBe(1);
expect(lines).toStrictEqual(['src/a.ts:1: suppression has no APPROVED(<id>) marker']);
});
});
+153
View File
@@ -0,0 +1,153 @@
import { globSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { z } from 'zod';
const kinds = ['lint-suppression', 'coverage-ignore', 'dts-shim', 'unit-coverage'] as const;
type Kind = (typeof kinds)[number];
const entrySchema = z.strictObject({
id: z.string().regex(/^[A-Z0-9-]+$/u, 'id must be upper-case letters, digits and dashes'),
kind: z.enum(kinds),
paths: z.array(z.string().min(1)).min(1),
reason: z.string().min(1),
approvedBy: z.string().min(1),
});
const registrySchema = z
.object({ exceptions: z.array(entrySchema) })
.superRefine((registry, context) => {
const seen = new Set<string>();
for (const entry of registry.exceptions) {
if (seen.has(entry.id)) {
context.addIssue({ code: 'custom', message: `duplicate id ${entry.id}` });
}
seen.add(entry.id);
}
});
export type Registry = z.infer<typeof registrySchema>;
type Entry = Registry['exceptions'][number];
export interface SourceFile {
readonly path: string;
readonly content: string;
}
export const parseRegistry = (value: unknown): Registry => registrySchema.parse(value);
export const unitCoverageExemptPaths = (registry: Registry): string[] =>
registry.exceptions
.filter((entry) => entry.kind === 'unit-coverage')
.flatMap((entry) => entry.paths);
// Directive text inside string literals (test fixtures, messages) isn't a
// directive, so literals are blanked out before matching.
const stringLiteral = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`/gu;
const lintDirective = /(?:\/\/|\/\*)\s*(?:oxlint|eslint)-disable/u;
const coverageDirective = /(?:\/\/|\/\*)\s*(?:v8|c8|istanbul) ignore/u;
const approvalMarker = /APPROVED\(([^)]*)\)/u;
const matches = (entry: Entry, file: string): boolean =>
entry.paths.some((pattern) => path.posix.matchesGlob(file, pattern));
const directiveKind = (line: string): Kind | undefined => {
const code = line.replaceAll(stringLiteral, "''");
if (lintDirective.test(code)) {
return 'lint-suppression';
}
if (coverageDirective.test(code)) {
return 'coverage-ignore';
}
return undefined;
};
const checkLine = (
file: string,
lineNumber: number,
line: string,
byId: ReadonlyMap<string, Entry>,
): string | undefined => {
const kind = directiveKind(line);
if (kind === undefined) {
return undefined;
}
const where = `${file}:${String(lineNumber)}`;
const id = approvalMarker.exec(line)?.[1];
if (id === undefined) {
return `${where}: suppression has no APPROVED(<id>) marker`;
}
const entry = byId.get(id);
if (entry === undefined) {
return `${where}: APPROVED(${id}) is not in exceptions.json`;
}
if (entry.kind !== kind) {
return `${where}: APPROVED(${id}) is a ${entry.kind} exception, not ${kind}`;
}
if (!matches(entry, file)) {
return `${where}: APPROVED(${id}) does not cover this file`;
}
return undefined;
};
export const audit = (files: readonly SourceFile[], registry: Registry): string[] => {
const byId = new Map(registry.exceptions.map((entry) => [entry.id, entry]));
const shims = registry.exceptions.filter((entry) => entry.kind === 'dts-shim');
const problems: string[] = [];
for (const file of files) {
for (const [index, line] of file.content.split('\n').entries()) {
const problem = checkLine(file.path, index + 1, line, byId);
if (problem !== undefined) {
problems.push(problem);
}
}
if (file.path.endsWith('.d.ts') && !shims.some((entry) => matches(entry, file.path))) {
problems.push(`${file.path}: declaration file is not approved in exceptions.json`);
}
}
for (const entry of registry.exceptions) {
if (!files.some((file) => matches(entry, file.path))) {
problems.push(`exceptions.json: ${entry.id} matches no files`);
}
}
return problems;
};
const sourceGlobs = ['**/*.{ts,mts,cts,js,mjs,cjs}'];
const ignoredGlobs = [
'**/node_modules/**',
'dist/**',
'release/**',
'coverage/**',
'e2e/docs-fixture/**',
];
export const runAudit = async (root: string, log: (line: string) => void): Promise<number> => {
const registry = parseRegistry(
JSON.parse(await readFile(path.join(root, 'exceptions.json'), 'utf8')),
);
const relativePaths = globSync(sourceGlobs, { cwd: root, exclude: ignoredGlobs });
const files = await Promise.all(
relativePaths.map(async (relativePath) => ({
path: relativePath.split(path.sep).join('/'),
content: await readFile(path.join(root, relativePath), 'utf8'),
})),
);
const problems = audit(files, registry);
for (const problem of problems) {
log(problem);
}
if (problems.length > 0) {
return 1;
}
const count = registry.exceptions.length;
log(
`audit-exceptions: ${String(count)} approved exception${count === 1 ? '' : 's'}, no problems`,
);
return 0;
};