Initial Commit
This commit is contained in:
39
packages/foundation/data/mime/tests/dep-graph.test.ts
Normal file
39
packages/foundation/data/mime/tests/dep-graph.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Dependency-graph guard for @suaveplan/mime.
|
||||
*
|
||||
* Asserts that the compiled package.json declares only the allowed direct
|
||||
* dependencies and that no disallowed peer imports appear at runtime.
|
||||
*/
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import pkg from "../package.json";
|
||||
|
||||
const ALLOWED_DEPS = new Set([
|
||||
"@suaveplan/error",
|
||||
"@suaveplan/types",
|
||||
"tslib",
|
||||
"zod",
|
||||
]);
|
||||
|
||||
describe("dependency graph", () => {
|
||||
it("has no unexpected production dependencies", { timeout: 5000 }, () => {
|
||||
const deps = Object.keys(pkg.dependencies ?? {});
|
||||
for (const dep of deps) {
|
||||
expect(ALLOWED_DEPS.has(dep), `Unexpected dep: ${dep}`).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("does not depend on Node-only packages", { timeout: 5000 }, () => {
|
||||
const deps = Object.keys({
|
||||
...pkg.dependencies,
|
||||
...pkg.devDependencies,
|
||||
});
|
||||
const nodeOnly = deps.filter(
|
||||
(d) =>
|
||||
d.startsWith("node:") ||
|
||||
d === "fs" ||
|
||||
d === "path" ||
|
||||
d === "crypto"
|
||||
);
|
||||
expect(nodeOnly).toEqual([]);
|
||||
});
|
||||
});
|
||||
40
packages/foundation/data/mime/tests/no-disallowed.test.ts
Normal file
40
packages/foundation/data/mime/tests/no-disallowed.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Guard test: verifies the package surface does not rely on
|
||||
* `Math.random()` or `Date.now()` directly in its runtime code.
|
||||
*
|
||||
* MIME detection is a pure function of its inputs — no time-based or
|
||||
* random-based side effects should be needed.
|
||||
*/
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
detectFromMagicBytes,
|
||||
formatContentType,
|
||||
getMimeEntry,
|
||||
parseContentType,
|
||||
} from "../src/index.js";
|
||||
|
||||
describe("no disallowed side-effects", () => {
|
||||
it("parseContentType is deterministic", { timeout: 5000 }, () => {
|
||||
const a = parseContentType("text/html; charset=utf-8");
|
||||
const b = parseContentType("text/html; charset=utf-8");
|
||||
expect(a).toEqual(b);
|
||||
});
|
||||
|
||||
it("formatContentType is deterministic", { timeout: 5000 }, () => {
|
||||
const parsed = parseContentType("text/plain; charset=utf-8");
|
||||
expect(formatContentType(parsed)).toBe(formatContentType(parsed));
|
||||
});
|
||||
|
||||
it("detectFromMagicBytes is deterministic", { timeout: 5000 }, () => {
|
||||
const png = new Uint8Array([
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
||||
]);
|
||||
const r1 = detectFromMagicBytes(png);
|
||||
const r2 = detectFromMagicBytes(png);
|
||||
expect(r1).toEqual(r2);
|
||||
});
|
||||
|
||||
it("getMimeEntry is deterministic", { timeout: 5000 }, () => {
|
||||
expect(getMimeEntry("image/png")).toEqual(getMimeEntry("image/png"));
|
||||
});
|
||||
});
|
||||
8
packages/foundation/data/mime/tests/setup/polyfills.ts
Normal file
8
packages/foundation/data/mime/tests/setup/polyfills.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
// Ensure `globalThis.crypto` is available in bare-Node vitest runs.
|
||||
import { webcrypto } from "node:crypto";
|
||||
|
||||
type WritableGlobal = { crypto?: Crypto };
|
||||
const g = globalThis as WritableGlobal;
|
||||
if (g.crypto === undefined) {
|
||||
g.crypto = webcrypto as unknown as Crypto;
|
||||
}
|
||||
52
packages/foundation/data/mime/tests/tree-shake.test.ts
Normal file
52
packages/foundation/data/mime/tests/tree-shake.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Tree-shake guard: verifies subpath imports work independently and the
|
||||
* `sideEffects` allowlist is narrowly scoped (only the magic-byte
|
||||
* signature registry is preserved).
|
||||
*/
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import pkg from "../package.json";
|
||||
|
||||
describe("tree-shake compatibility", () => {
|
||||
it("package.json sideEffects allowlist is narrow", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
// The magic-byte signature registry registers entries via the
|
||||
// side-effecting `signatures/index.ts` module — keep it on the
|
||||
// sideEffects allowlist so bundlers don't tree-shake the
|
||||
// registration loop. Every OTHER module must be side-effect-free.
|
||||
expect(pkg.sideEffects).toEqual([
|
||||
"**/detection/from-magic-bytes/signatures/index.{ts,js}",
|
||||
]);
|
||||
});
|
||||
|
||||
it("has subpath exports for core modules", { timeout: 5000 }, () => {
|
||||
const exports = pkg.exports as Record<string, unknown>;
|
||||
expect(exports["."]).toBeDefined();
|
||||
expect(exports["./content-type"]).toBeDefined();
|
||||
expect(exports["./detection"]).toBeDefined();
|
||||
expect(exports["./db"]).toBeDefined();
|
||||
expect(exports["./charset"]).toBeDefined();
|
||||
expect(exports["./errors"]).toBeDefined();
|
||||
expect(exports["./schemas"]).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("subpath import smoke test", () => {
|
||||
it("can import from content-type subpath", { timeout: 30000 }, async () => {
|
||||
// Dynamic import simulates tree-shaking consumer
|
||||
const m = await import("../src/content-type/index.js");
|
||||
expect(typeof m.parseContentType).toBe("function");
|
||||
expect(typeof m.formatContentType).toBe("function");
|
||||
});
|
||||
|
||||
it("can import from charset subpath", { timeout: 30000 }, async () => {
|
||||
const m = await import("../src/charset/index.js");
|
||||
expect(typeof m.sniffBom).toBe("function");
|
||||
});
|
||||
|
||||
it("can import from db subpath", { timeout: 30000 }, async () => {
|
||||
const m = await import("../src/db/index.js");
|
||||
expect(typeof m.getMimeEntry).toBe("function");
|
||||
expect(Array.isArray(m.BUILTIN_DB)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user