diff --git a/apps/api/src/judge/ast.ts b/apps/api/src/judge/ast.ts index 7fc5a4f..2f55fff 100644 --- a/apps/api/src/judge/ast.ts +++ b/apps/api/src/judge/ast.ts @@ -1,3 +1,4 @@ +import type { AstRule } from "@oj2/contract" import { Language, Parser, type Node } from "web-tree-sitter" // 语法 wasm 内嵌成资源。原来是 `Bun.resolveSync(pkg + "/" + name, import.meta.dir)`, // 编译成单二进制后 import.meta.dir 是 /$bunfs/root,解析不到 node_modules。见 vendor/jieba.ts @@ -6,17 +7,9 @@ import pythonWasmPath from "tree-sitter-python/tree-sitter-python.wasm" with { t // web-tree-sitter 自己的运行时 wasm,Parser.init() 要用 import treeSitterWasmPath from "web-tree-sitter/web-tree-sitter.wasm" with { type: "file" } -export interface AstRule { - engine?: string - target?: string - outer?: string - inner?: string - label?: string - message?: string - exact?: number - min?: number - max?: number -} +// AstRule 的形状在契约里(astRuleSchema)—— 原来这份和前端两份各写各的。 +// 这里 re-export,判题机的调用方不用再去 import 契约。 +export type { AstRule } from "@oj2/contract" export interface AstResult { description: string diff --git a/apps/api/src/judge/run.ts b/apps/api/src/judge/run.ts index d2d82f3..b8f7128 100644 --- a/apps/api/src/judge/run.ts +++ b/apps/api/src/judge/run.ts @@ -1,5 +1,6 @@ import { createHash } from "node:crypto" +import { astRuleSchema } from "@oj2/contract" import { and, eq, inArray } from "drizzle-orm" import { config } from "../config" @@ -54,9 +55,19 @@ function templateForLanguage(value: unknown, language: string) { return typeof template === "string" ? template : null } +/** + * 取某个语言的 AST 规则。逐条过 astRuleSchema 而不是整片 `as AstRule[]` 硬转 —— + * 这是从库里读出来的 JSONB,形状不对(比如 engine 是个 evaluateRule 不认识的值) + * 时丢掉那一条,行为和 evaluateRule 的 `default: return null` 一致,只是提前到了 + * 这里、并且不再骗类型系统。 + */ function astRulesForLanguage(value: unknown, language: string): AstRule[] { const rules = objectValue(value)[language] - return Array.isArray(rules) ? (rules as AstRule[]) : [] + if (!Array.isArray(rules)) return [] + return rules.flatMap((rule) => { + const parsed = astRuleSchema.safeParse(rule) + return parsed.success ? [parsed.data] : [] + }) } async function requestJudge( diff --git a/apps/web/src/admin/problem/components/AstRulesEditor.vue b/apps/web/src/admin/problem/components/AstRulesEditor.vue index 3c5aedf..caf906b 100644 --- a/apps/web/src/admin/problem/components/AstRulesEditor.vue +++ b/apps/web/src/admin/problem/components/AstRulesEditor.vue @@ -1,24 +1,14 @@