Initial Commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
|
||||
const PKG = resolve(__dirname, "..");
|
||||
const SRC = resolve(PKG, "src");
|
||||
|
||||
interface PackageJson {
|
||||
readonly exports: Record<string, unknown>;
|
||||
readonly dependencies?: Record<string, string>;
|
||||
readonly peerDependencies?: Record<string, string>;
|
||||
readonly devDependencies?: Record<string, string>;
|
||||
}
|
||||
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(resolve(PKG, "package.json"), "utf8")
|
||||
) as PackageJson;
|
||||
|
||||
const EXEMPT_NO_MD = new Set(["index.ts"]);
|
||||
|
||||
function walk(dir: string): string[] {
|
||||
const out: string[] = [];
|
||||
for (const entry of readdirSync(dir)) {
|
||||
const full = join(dir, entry);
|
||||
const s = statSync(full);
|
||||
if (s.isDirectory()) out.push(...walk(full));
|
||||
else out.push(full);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
describe("dep-graph", () => {
|
||||
it("every subpath export points to a real file (post-build) and has a matching source", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const subpaths = Object.keys(pkg.exports).filter(
|
||||
(k) => k !== "./package.json"
|
||||
);
|
||||
for (const subpath of subpaths) {
|
||||
const target = (
|
||||
pkg.exports[subpath] as {
|
||||
import?: { default: string };
|
||||
}
|
||||
)?.import?.default;
|
||||
expect(target, `${subpath} has import.default`).toBeDefined();
|
||||
}
|
||||
expect(subpaths.length).toBeGreaterThanOrEqual(12);
|
||||
});
|
||||
|
||||
it("every impl .ts has a sibling .md", { timeout: 5000 }, () => {
|
||||
const files = walk(SRC);
|
||||
const tsFiles = files.filter(
|
||||
(f) =>
|
||||
f.endsWith(".ts") &&
|
||||
!f.endsWith(".test.ts") &&
|
||||
!f.endsWith(".bench.ts") &&
|
||||
!f.endsWith(".types.ts") &&
|
||||
!f.endsWith("/index.ts") &&
|
||||
!f.endsWith(".spec-conformance.test.ts")
|
||||
);
|
||||
for (const file of tsFiles) {
|
||||
const base = file.slice(0, -3);
|
||||
const md = `${base}.md`;
|
||||
if (EXEMPT_NO_MD.has(file.split("/").pop() ?? "")) continue;
|
||||
expect(existsSync(md), `${file} missing sibling .md`).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("dependencies match the allowlist", { timeout: 5000 }, () => {
|
||||
const allowed = new Set([
|
||||
"@opentelemetry/api",
|
||||
"@suaveplan/error",
|
||||
"@suaveplan/surrealdb",
|
||||
"@suaveplan/types",
|
||||
"surrealdb",
|
||||
"tslib",
|
||||
"zod",
|
||||
]);
|
||||
for (const dep of Object.keys(pkg.dependencies ?? {})) {
|
||||
expect(allowed.has(dep), `unexpected runtime dep: ${dep}`).toBe(
|
||||
true
|
||||
);
|
||||
}
|
||||
expect(Object.keys(pkg.peerDependencies ?? {})).toEqual([
|
||||
"better-auth",
|
||||
]);
|
||||
});
|
||||
|
||||
it("no source file exceeds 300 lines", { timeout: 5000 }, () => {
|
||||
const files = walk(SRC).filter(
|
||||
(f) =>
|
||||
f.endsWith(".ts") &&
|
||||
!f.endsWith(".test.ts") &&
|
||||
!f.endsWith(".bench.ts")
|
||||
);
|
||||
for (const file of files) {
|
||||
const lines = readFileSync(file, "utf8").split("\n").length;
|
||||
expect(
|
||||
lines,
|
||||
`${file} has ${lines} lines (>300)`
|
||||
).toBeLessThanOrEqual(300);
|
||||
}
|
||||
});
|
||||
|
||||
it("no source file uses export *", { timeout: 5000 }, () => {
|
||||
const files = walk(SRC).filter((f) => f.endsWith(".ts"));
|
||||
for (const file of files) {
|
||||
const content = readFileSync(file, "utf8");
|
||||
expect(
|
||||
/\bexport \* from\b/.test(content),
|
||||
`${file} uses export *`
|
||||
).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("no source file imports from vitest or bun:test", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const files = walk(SRC).filter(
|
||||
(f) => f.endsWith(".ts") || f.endsWith(".test.ts")
|
||||
);
|
||||
for (const file of files) {
|
||||
const content = readFileSync(file, "utf8");
|
||||
expect(
|
||||
/from\s+["'](vitest|bun:test)["']/.test(content),
|
||||
`${file} imports from vitest/bun:test directly`
|
||||
).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("README quick-start uses betterAuthSurrealAdapter v1.6 factory", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const readme = readFileSync(resolve(PKG, "README.md"), "utf8");
|
||||
const quickStartIdx = readme.indexOf("## Quick start");
|
||||
expect(quickStartIdx).toBeGreaterThan(-1);
|
||||
// First non-install code block after `## Quick start` should use
|
||||
// `betterAuthSurrealAdapter`.
|
||||
const after = readme.slice(quickStartIdx);
|
||||
const firstFence = after.indexOf("```ts");
|
||||
const firstBlockEnd = after.indexOf("```", firstFence + 5);
|
||||
const firstBlock = after.slice(firstFence, firstBlockEnd);
|
||||
expect(firstBlock).toContain("betterAuthSurrealAdapter");
|
||||
expect(firstBlock).toContain("/adapter/v1.6");
|
||||
});
|
||||
|
||||
it("./adapter/v1.6 subpath export resolves", { timeout: 5000 }, () => {
|
||||
const subpath = pkg.exports["./adapter/v1.6"] as
|
||||
| { import?: { default: string; types: string } }
|
||||
| undefined;
|
||||
expect(subpath).toBeDefined();
|
||||
expect(subpath?.import?.default).toBe("./dist/adapter/v1.6.js");
|
||||
expect(subpath?.import?.types).toBe("./dist/adapter/v1.6.d.ts");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user