diff --git a/biome.jsonc b/biome.jsonc index 8e3f3b70..ad12f89b 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -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", diff --git a/scripts/lint/no-generated-app-server-import-shapes.grit b/scripts/lint/no-generated-app-server-import-shapes.grit deleted file mode 100644 index 9af38a1b..00000000 --- a/scripts/lint/no-generated-app-server-import-shapes.grit +++ /dev/null @@ -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") - } -} diff --git a/scripts/lint/no-generated-app-server-server-request-imports.grit b/scripts/lint/no-generated-app-server-server-request-imports.grit new file mode 100644 index 00000000..9c213430 --- /dev/null +++ b/scripts/lint/no-generated-app-server-server-request-imports.grit @@ -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") + } +} diff --git a/scripts/lint/no-generated-app-server-thread-alias-imports.grit b/scripts/lint/no-generated-app-server-thread-alias-imports.grit new file mode 100644 index 00000000..e415e70b --- /dev/null +++ b/scripts/lint/no-generated-app-server-thread-alias-imports.grit @@ -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") + } +} diff --git a/scripts/lint/no-generated-app-server-turn-protocol-imports.grit b/scripts/lint/no-generated-app-server-turn-protocol-imports.grit new file mode 100644 index 00000000..7ac4807d --- /dev/null +++ b/scripts/lint/no-generated-app-server-turn-protocol-imports.grit @@ -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") +} diff --git a/tests/scripts/grit-policy.test.mjs b/tests/scripts/grit-policy.test.mjs index 39fa3faf..d31940b6 100644 --- a/tests/scripts/grit-policy.test.mjs +++ b/tests/scripts/grit-policy.test.mjs @@ -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.",