Files
WRNexusJS/packages/router/test/authz-discovery.test.ts
ClintchizandClaude Opus 5 e136fbc56a fix(router): quietly skip permissions.gen.{ts,js} in authz scan
Task 10 fix round 1: the coordinator's plan doc (41fb82b9) recorded that
generated authz type files should be skipped before the isSafeIslandName
check, but the code change never landed. isSafeIslandName rejects the dot
in the stripped basename "permissions.gen", so every app running Task 12's
codegen would warn on every boot.

Add a quiet skip for *.gen.ts / *.gen.js immediately after the extension
guard, before the name check. Add tests: a .gen.ts file is skipped without
a console.warn (spied), and a .gen.js file is skipped the same way while a
legitimately named .js declaration is still discovered.

Also corrects the scanDir extraExtensions doc comment, which incorrectly
implied app/schemas passes it too (only app/authz does).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 20:09:16 +05:30

68 lines
2.5 KiB
TypeScript

import { describe, expect, spyOn, test } from "bun:test";
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { buildRouter } from "../src/index.ts";
function appWithAuthz(files: Record<string, string>): string {
const root = mkdtempSync(join(tmpdir(), "wrnexus-authz-"));
const dir = join(root, "app", "authz");
mkdirSync(dir, { recursive: true });
mkdirSync(join(root, "app", "pages"), { recursive: true });
for (const [name, body] of Object.entries(files)) writeFileSync(join(dir, name), body, "utf8");
return join(root, "app");
}
describe("app/authz discovery", () => {
test("collects .ts and .js declarations by filename", () => {
const appDir = appWithAuthz({
"blog.ts": "export default {};",
"billing.js": "export default {};",
});
const router = buildRouter(appDir);
expect(router.authz.map((entry) => entry.name).sort()).toEqual(["billing", "blog"]);
});
test("ignores non-module files", () => {
const appDir = appWithAuthz({ "blog.ts": "export default {};", "notes.md": "# hi" });
expect(buildRouter(appDir).authz.map((entry) => entry.name)).toEqual(["blog"]);
});
test("skips unsafe names", () => {
const appDir = appWithAuthz({
"ok.ts": "export default {};",
"bad name!.ts": "export default {};",
});
expect(buildRouter(appDir).authz.map((entry) => entry.name)).toEqual(["ok"]);
});
test("an app with no authz directory yields an empty list", () => {
const root = mkdtempSync(join(tmpdir(), "wrnexus-authz-none-"));
mkdirSync(join(root, "app", "pages"), { recursive: true });
expect(buildRouter(join(root, "app")).authz).toEqual([]);
});
test("quietly skips generated permissions.gen.ts without warning", () => {
const appDir = appWithAuthz({
"permissions.gen.ts": "export type Foo = 1;",
"blog.ts": "export default {};",
});
const warnSpy = spyOn(console, "warn").mockImplementation(() => {});
try {
const router = buildRouter(appDir);
expect(router.authz.map((entry) => entry.name)).toEqual(["blog"]);
expect(warnSpy).not.toHaveBeenCalled();
} finally {
warnSpy.mockRestore();
}
});
test("skips permissions.gen.js too, while a legitimately named declaration is still discovered", () => {
const appDir = appWithAuthz({
"permissions.gen.js": "export const x = 1;",
"billing.js": "export default {};",
});
expect(buildRouter(appDir).authz.map((entry) => entry.name)).toEqual(["billing"]);
});
});