Split generated app-server import shape rules

This commit is contained in:
murashit 2026-06-26 07:31:14 +09:00
parent 7c5da3d520
commit 5ad3c18d34
6 changed files with 129 additions and 93 deletions

View file

@ -21,14 +21,23 @@
"**/src/**/*.ts",
"**/src/**/*.tsx",
"!**/src/app-server/connection/**",
"!**/src/app-server/protocol/turn.ts",
"!**/src/app-server/protocol/server-requests.ts"
]
},
// Shared source layering boundaries.
{
"path": "./scripts/lint/no-generated-app-server-import-shapes.grit",
"includes": ["**/src/**/*.ts", "**/src/**/*.tsx"]
"path": "./scripts/lint/no-generated-app-server-thread-alias-imports.grit",
"includes": ["**/src/app-server/connection/**/*.ts", "**/src/app-server/connection/**/*.tsx"]
},
{
"path": "./scripts/lint/no-generated-app-server-turn-protocol-imports.grit",
"includes": ["**/src/app-server/protocol/turn.ts"]
},
{
"path": "./scripts/lint/no-generated-app-server-server-request-imports.grit",
"includes": ["**/src/app-server/protocol/server-requests.ts"]
},
{
"path": "./scripts/lint/no-lower-level-boundary-imports.grit",

View file

@ -1,62 +0,0 @@
language js
private pattern js_non_import_module_reference() {
or {
JsExportNamedFromClause(),
JsExportFromClause(),
TsImportType(),
JsImportCallExpression()
}
}
private pattern js_static_module_reference() {
or {
JsImport(),
JsExportNamedFromClause(),
JsExportFromClause()
}
}
private pattern js_module_reference() {
or {
JsImport(),
JsExportNamedFromClause(),
JsExportFromClause(),
TsImportType(),
JsImportCallExpression()
}
}
or {
JsImport() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*generated/app-server/v2/Thread[\"']$" },
not { $stmt <: r".*\bThread\s+as\s+AppServerThread\b.*" },
register_diagnostic(span=$stmt, message="Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.", severity="error")
},
js_non_import_module_reference() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*generated/app-server/v2/Thread[\"']$" },
register_diagnostic(span=$stmt, message="Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.", severity="error")
},
js_static_module_reference() as $stmt where {
$filename <: r".*/src/app-server/protocol/turn\.ts$",
$stmt <: contains `$source` where {
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/v2/ThreadItem[\"']$" }
},
register_diagnostic(span=$stmt, message="Only generated ThreadItem is allowed in the turn protocol exception. Model other turn payload shapes locally.", severity="error")
},
js_module_reference() as $stmt where {
$filename <: r".*/src/app-server/protocol/server-requests\.ts$",
$stmt <: contains `$source` where {
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/(?:RequestId|ServerRequest)[\"']$" }
},
register_diagnostic(span=$stmt, message="Only generated RequestId and ServerRequest are allowed in the server request protocol exception.", severity="error")
},
`require($source)` as $stmt where {
$filename <: r".*/src/app-server/protocol/server-requests\.ts$",
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/(?:RequestId|ServerRequest)[\"']$" },
register_diagnostic(span=$stmt, message="Only generated RequestId and ServerRequest are allowed in the server request protocol exception.", severity="error")
}
}

View file

@ -0,0 +1,26 @@
language js
private pattern js_module_reference() {
or {
JsImport(),
JsExportNamedFromClause(),
JsExportFromClause(),
TsImportType(),
JsImportCallExpression()
}
}
or {
js_module_reference() as $stmt where {
$stmt <: contains `$source` where {
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/(?:RequestId|ServerRequest)[\"']$" }
},
register_diagnostic(span=$stmt, message="Only generated RequestId and ServerRequest are allowed in the server request protocol exception.", severity="error")
},
`require($source)` as $stmt where {
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/(?:RequestId|ServerRequest)[\"']$" },
register_diagnostic(span=$stmt, message="Only generated RequestId and ServerRequest are allowed in the server request protocol exception.", severity="error")
}
}

View file

@ -0,0 +1,22 @@
language js
private pattern js_non_import_module_reference() {
or {
JsExportNamedFromClause(),
JsExportFromClause(),
TsImportType(),
JsImportCallExpression()
}
}
or {
JsImport() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*generated/app-server/v2/Thread[\"']$" },
not { $stmt <: r".*\bThread\s+as\s+AppServerThread\b.*" },
register_diagnostic(span=$stmt, message="Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.", severity="error")
},
js_non_import_module_reference() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*generated/app-server/v2/Thread[\"']$" },
register_diagnostic(span=$stmt, message="Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.", severity="error")
}
}

View file

@ -0,0 +1,17 @@
language js
private pattern js_static_module_reference() {
or {
JsImport(),
JsExportNamedFromClause(),
JsExportFromClause()
}
}
js_static_module_reference() as $stmt where {
$stmt <: contains `$source` where {
$source <: r"^[\"'].*generated/app-server/.*[\"']$",
not { $source <: r"^[\"'].*generated/app-server/v2/ThreadItem[\"']$" }
},
register_diagnostic(span=$stmt, message="Only generated ThreadItem is allowed in the turn protocol exception. Model other turn payload shapes locally.", severity="error")
}

View file

@ -430,9 +430,7 @@ export type Request = ServerRequest;
expect(pluginMessages(report, "src/app-server/services/runtime-overrides.ts")).toEqual([
"Keep generated app-server types behind src/app-server adapters; expose Panel-owned models outside raw app-server boundaries.",
]);
expect(pluginMessages(report, "src/app-server/protocol/turn.ts")).toEqual([
"Keep generated app-server types behind src/app-server adapters; expose Panel-owned models outside raw app-server boundaries.",
]);
expect(pluginDiagnostics(report, "src/app-server/protocol/turn.ts")).toEqual([]);
expect(pluginDiagnostics(report, "src/app-server/protocol/server-requests.ts")).toEqual([]);
});
@ -615,8 +613,8 @@ export const format = formatDate;
expect(pluginDiagnostics(report, "src/domain/threads/format.ts")).toEqual([]);
});
it("keeps generated app-server import shapes behind narrow aliases and server request exceptions", async () => {
const cwd = await tempBiomeWorkspace(["no-generated-app-server-import-shapes.grit"]);
it("keeps generated app-server Thread imports behind the app-server alias", async () => {
const cwd = await tempBiomeWorkspace(["no-generated-app-server-thread-alias-imports.grit"]);
await writeFile(
path.join(cwd, "src/app-server/connection/thread.ts"),
`
@ -653,6 +651,55 @@ export type ConnectionThread = import("../../generated/app-server/v2/Thread").Th
export type { Thread } from "../../generated/app-server/v2/Thread";
`.trimStart(),
);
const report = biomeLint(
[
"src/app-server/connection/thread.ts",
"src/app-server/connection/aliased-thread.ts",
"src/app-server/connection/record-thread.ts",
"src/app-server/connection/import-type-thread.ts",
"src/app-server/connection/export-thread.ts",
],
cwd,
);
expect(pluginMessages(report, "src/app-server/connection/thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginDiagnostics(report, "src/app-server/connection/aliased-thread.ts")).toEqual([]);
expect(pluginMessages(report, "src/app-server/connection/record-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginMessages(report, "src/app-server/connection/import-type-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginMessages(report, "src/app-server/connection/export-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
});
it("keeps generated app-server turn protocol imports behind the ThreadItem exception", async () => {
const cwd = await tempBiomeWorkspace(["no-generated-app-server-turn-protocol-imports.grit"]);
await writeFile(
path.join(cwd, "src/app-server/protocol/turn.ts"),
`
import type { ThreadItem } from "../../generated/app-server/v2/ThreadItem";
import type { Thread } from "../../generated/app-server/v2/Thread";
export type TurnItem = ThreadItem;
export type TurnThread = Thread;
`.trimStart(),
);
const report = biomeLint(["src/app-server/protocol/turn.ts"], cwd);
expect(pluginMessages(report, "src/app-server/protocol/turn.ts")).toEqual([
"Only generated ThreadItem is allowed in the turn protocol exception. Model other turn payload shapes locally.",
]);
});
it("keeps generated app-server server request imports behind narrow exceptions", async () => {
const cwd = await tempBiomeWorkspace(["no-generated-app-server-server-request-imports.grit"]);
await writeFile(
path.join(cwd, "src/app-server/protocol/server-requests.ts"),
`
@ -672,31 +719,8 @@ export const loadedParams = params;
`.trimStart(),
);
const report = biomeLint(
[
"src/app-server/connection/thread.ts",
"src/app-server/connection/aliased-thread.ts",
"src/app-server/connection/record-thread.ts",
"src/app-server/connection/import-type-thread.ts",
"src/app-server/connection/export-thread.ts",
"src/app-server/protocol/server-requests.ts",
],
cwd,
);
const report = biomeLint(["src/app-server/protocol/server-requests.ts"], cwd);
expect(pluginMessages(report, "src/app-server/connection/thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginDiagnostics(report, "src/app-server/connection/aliased-thread.ts")).toEqual([]);
expect(pluginMessages(report, "src/app-server/connection/record-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginMessages(report, "src/app-server/connection/import-type-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginMessages(report, "src/app-server/connection/export-thread.ts")).toEqual([
"Import generated app-server Thread as AppServerThread, or use the Panel-owned domain Thread model.",
]);
expect(pluginMessages(report, "src/app-server/protocol/server-requests.ts")).toEqual([
"Only generated RequestId and ServerRequest are allowed in the server request protocol exception.",
"Only generated RequestId and ServerRequest are allowed in the server request protocol exception.",