返回 DeepSeek-Reasonix
error-display-contract.test.ts
根目录 / desktop / frontend / src / __tests__ / error-display-contract.test.ts
1 import assert from "node:assert/strict";
2 import { readdirSync, readFileSync } from "node:fs";
3 import { dirname, join, relative } from "node:path";
4 import { fileURLToPath } from "node:url";
5 import ts from "typescript";
6
7 // Prevent newly added inline error labels from bypassing the shared presenter.
8 // Raw diagnostics in explicit detail/code views remain verbatim by design.
9 const root = join(dirname(fileURLToPath(import.meta.url)), "..");
10 function files(directory: string): string[] {
11 return readdirSync(directory, { withFileTypes: true }).flatMap(entry =>
12 entry.name === "__tests__" ? [] : entry.isDirectory() ? files(join(directory, entry.name)) : [join(directory, entry.name)]);
13 }
14 const violations: string[] = [];
15 for (const file of files(root).filter(name => name.endsWith(".tsx") && !name.endsWith(".test.tsx"))) {
16 const source = ts.createSourceFile(file, readFileSync(file, "utf8"), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
17 function visit(node: ts.Node) {
18 if (ts.isJsxExpression(node) && node.expression && ts.isJsxElement(node.parent)) {
19 const expression = node.expression.getText(source);
20 const tag = node.parent.openingElement.tagName.getText(source);
21 if (/^(?:[a-zA-Z_$][\w$]*\??\.)*(?:\w*(?:Err|Error)|err|error)$/.test(expression)
22 && /^[a-z]/.test(tag) && !["pre", "code"].includes(tag)) {
23 violations.push(`${relative(root, file)}:${source.getLineAndCharacterOfPosition(node.pos).line + 1}: ${expression}`);
24 }
25 }
26 ts.forEachChild(node, visit);
27 }
28 visit(source);
29 }
30 assert.deepEqual(violations, [], "User-visible errors must go through ErrorMessage; raw details belong in explicit diagnostic views");
31 console.log("PASS error display contract: inline error surfaces use the shared presenter");
32
32 lines TYPESCRIPT