检查结果汇总
策略的具体实现如下。
ts
export function defineAnswerCheckCatalog<Value, App>(
definitions: readonly AnswerChecker<Value, App>[],
) {
const checks = readonlyCatalog(
definitions.map((check) => {
if (typeof check.check !== 'function') throw new TypeError('Invalid answer checker');
return Object.freeze({ id: check.id, check: check.check.bind(check) });
}),
(id) => new TypeError(`Unknown answer checker: ${id}`),
);
return Object.freeze({
...checks,
// Severity only escalates: `failed` wins over `unavailable`, which wins over `passed`.
check(
request: { checkIds: readonly string[]; value: Value },
context: OperationContext<App>,
): AnswerCheck<Value> {
context.signal.throwIfAborted();
const issues: AnswerIssue[] = [];
let status: AnswerCheck<Value>['status'] = 'passed',
value = request.value;
if (new Set(request.checkIds).size !== request.checkIds.length)
throw new TypeError('Duplicate selected check id');
for (const id of request.checkIds) {
context.signal.throwIfAborted();
const result = nativeSubFlowSync(context, 'check', id, () =>
snapshotAnswerCheck(
synchronous(
checks.require(id).check(value, context),
'Answer checkers must be synchronous',
),
id,
),
);
context.signal.throwIfAborted();
if (Object.hasOwn(result, 'value')) value = result.value!;
issues.push(...result.issues);
if (result.status === 'failed') status = 'failed';
else if (status !== 'failed' && result.status !== 'passed') status = 'unavailable';
}
return { status, value, issues };
},
});
}