Ban handwritten re-exports

This commit is contained in:
murashit 2026-06-24 06:39:14 +09:00
parent 439aca3eb0
commit 15d9753789
2 changed files with 57 additions and 1 deletions

View file

@ -46,6 +46,17 @@ const removedChatStateEscapeHatchRestrictions = [
message: "Use a named ChatAction instead of reintroducing the generic state patch escape hatch.",
},
];
const handWrittenReExportRestrictions = [
{
selector: "ExportNamedDeclaration[source.value]",
message: "Do not add hand-written re-exports. Import from the owning module directly unless this file is an explicit public boundary.",
},
{
selector: "ExportAllDeclaration[source.value]",
message:
"Do not add hand-written export-all barrels. Import from the owning module directly unless this file is an explicit public boundary.",
},
];
const chatSignalAdapterRestrictions = [
{
selector: "ImportDeclaration[source.value='@preact/signals']",
@ -209,6 +220,7 @@ const appServerClientProjectionTypeRestrictions = [
},
];
const baseSourceSyntaxRestrictions = [
...handWrittenReExportRestrictions,
...removedChatStateEscapeHatchRestrictions,
...generatedAppServerThreadImportRestrictions,
...appServerClientProjectionTypeRestrictions,
@ -295,7 +307,11 @@ export default defineConfig([
files: ["tests/**/*.{ts,tsx}"],
rules: {
...testTypeScriptRelaxations,
...restrictedSyntaxRule([...generatedAppServerThreadImportRestrictions, ...chatSignalAdapterRestrictions]),
...restrictedSyntaxRule([
...handWrittenReExportRestrictions,
...generatedAppServerThreadImportRestrictions,
...chatSignalAdapterRestrictions,
]),
},
},
{

View file

@ -101,6 +101,46 @@ export const status = signal("idle");
expect(messages).toContain("no-restricted-syntax");
});
it("reports hand-written named re-exports", async () => {
const messages = await lintSource(
"src/shared/text/preview.ts",
`
export { shortThreadId } from "../id/thread-id";
export type { Thread } from "../../domain/threads/model";
`,
);
expect(messages.filter((message) => message === "no-restricted-syntax")).toHaveLength(2);
});
it("reports hand-written export-all barrels", async () => {
const messages = await lintSource(
"src/shared/text/preview.ts",
`
export * from "../id/thread-id";
`,
);
expect(messages).toContain("no-restricted-syntax");
});
it("allows local exports from owning modules", async () => {
const messages = await lintSource(
"src/shared/text/preview.ts",
`
const limit = 80;
export function truncate(value: string): string {
return value.slice(0, limit);
}
export { limit };
`,
);
expect(messages).not.toContain("no-restricted-syntax");
});
it("reports non-turn app-server protocol imports outside app-server", async () => {
const messages = await lintSource(
"src/features/chat/application/pending-requests/pending-request-actions.ts",