40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import type { Constraint, ConstraintContext, ConstraintResult, StateView } from './types.js';
|
|
|
|
export const evaluateConstraints = (
|
|
constraints: Constraint[],
|
|
ctx: ConstraintContext,
|
|
view: StateView
|
|
): ConstraintResult => {
|
|
for (const constraint of constraints) {
|
|
const missing = constraint.requires(ctx).filter((req) => !view.has(req));
|
|
if (missing.length > 0 && ctx.mode === 'precheck') {
|
|
return { kind: 'unknown', missing };
|
|
}
|
|
const result = constraint.test(ctx, view);
|
|
if (result.kind === 'deny') {
|
|
return {
|
|
...result,
|
|
constraintName: result.constraintName ?? constraint.name,
|
|
};
|
|
}
|
|
if (result.kind !== 'allow') {
|
|
return result;
|
|
}
|
|
}
|
|
return { kind: 'allow' };
|
|
};
|
|
|
|
export interface ActionWithConstraints {
|
|
buildConstraints(ctx: ConstraintContext, args: unknown): Constraint[];
|
|
}
|
|
|
|
export const evaluateActionConstraints = <Args>(
|
|
action: ActionWithConstraints,
|
|
ctx: ConstraintContext,
|
|
view: StateView,
|
|
args: Args
|
|
): ConstraintResult => {
|
|
const constraints = action.buildConstraints(ctx, args);
|
|
return evaluateConstraints(constraints, ctx, view);
|
|
};
|