Initial Commit
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const srcRoot = join(here, "..", "src");
|
||||
const distRoot = join(here, "..", "dist");
|
||||
|
||||
function walk(dir: string, out: string[] = []): string[] {
|
||||
if (!existsSync(dir)) return out;
|
||||
for (const entry of readdirSync(dir)) {
|
||||
const p = join(dir, entry);
|
||||
if (statSync(p).isDirectory()) walk(p, out);
|
||||
else if (p.endsWith(".ts") || p.endsWith(".js")) out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const FORBIDDEN_NODE_PATTERNS = [
|
||||
/from\s+["']node:/,
|
||||
/from\s+["']fs["']/,
|
||||
/from\s+["']path["']/,
|
||||
/from\s+["']crypto["']/,
|
||||
];
|
||||
|
||||
describe("purity", () => {
|
||||
it("source files do not import Node-only APIs at the top level", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const files = walk(srcRoot).filter(
|
||||
(f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts")
|
||||
);
|
||||
const offenders: string[] = [];
|
||||
for (const f of files) {
|
||||
const text = readFileSync(f, "utf8");
|
||||
for (const rx of FORBIDDEN_NODE_PATTERNS) {
|
||||
if (rx.test(text)) offenders.push(`${f}: ${rx.source}`);
|
||||
}
|
||||
}
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
it("@ffmpeg/core-mt is referenced only inside dynamic imports or comments", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const files = walk(srcRoot).filter(
|
||||
(f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts")
|
||||
);
|
||||
for (const f of files) {
|
||||
const text = readFileSync(f, "utf8");
|
||||
const lines = text.split("\n");
|
||||
for (const line of lines) {
|
||||
if (!line.includes("@ffmpeg/core-mt")) continue;
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith("//")) continue;
|
||||
if (trimmed.startsWith("*")) continue;
|
||||
if (line.includes("import(")) continue;
|
||||
throw new Error(`disallowed reference in ${f}: ${line}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("@ffmpeg/core is never reached via static import", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const files = walk(srcRoot).filter(
|
||||
(f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts")
|
||||
);
|
||||
// Forbidden: `import … from "@ffmpeg/core"` / `import "@ffmpeg/core"`.
|
||||
const STATIC_IMPORT =
|
||||
/^\s*import\b[^;]*from\s+["']@ffmpeg\/core(?:-mt)?["']/;
|
||||
for (const f of files) {
|
||||
if (f.includes("ffmpeg-shim.d.ts")) continue;
|
||||
const lines = readFileSync(f, "utf8").split("\n");
|
||||
for (const line of lines) {
|
||||
if (STATIC_IMPORT.test(line)) {
|
||||
throw new Error(`static import in ${f}: ${line}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("importing the root module mutates no global state", {
|
||||
timeout: 5000,
|
||||
}, async () => {
|
||||
// The act of importing the module is the verification — no exception
|
||||
// means no top-level throw, and no spec covers any mutation outside
|
||||
// the module's own ESM closure.
|
||||
const mod = await import("../src/index.js");
|
||||
expect(mod.FfmpegWasmCodec).toBeDefined();
|
||||
});
|
||||
|
||||
it("dist/ — when built — contains no node: references", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
if (!existsSync(distRoot)) {
|
||||
// pre-build environment — skip
|
||||
return;
|
||||
}
|
||||
const files = walk(distRoot);
|
||||
for (const f of files) {
|
||||
const text = readFileSync(f, "utf8");
|
||||
for (const rx of FORBIDDEN_NODE_PATTERNS) {
|
||||
expect(rx.test(text)).toBe(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user