实现示例type Node = { type: 'ID' | 'AND' | 'OR' | 'WITH'; left?: Node; right?: Node; id?: string; exception?: string }
function tokenize(expr: string): string[] { return expr.replace(/\(|\)/g, m => ` ${m} `).trim().split(/\s+/) }
function parse(tokens: string[]): Node {
const stack: Node[] = []
const ops: string[] = []
function reduce(op: string) {
const r = stack.pop() as Node
const l = stack.pop() as Node
stack.push({ type: op as any, left: l, right: r })
}
for (const t of tokens) {
if (t === '(') ops.push(t)
else if (t === ')') { while (ops.length && ops[ops.length - 1] !== '(') reduce(ops.pop() as string); ops.pop() }
else if (t === 'AND' || t === 'OR') { while (ops.length && ops[ops.length - 1] !== '(') reduce(ops.pop() as string); ops.push(t) }
else if (t === 'WITH') { const prev = stack.pop() as Node; const next = tokens.shift() as string; stack.push({ type: 'WITH', left: prev, right: { type: 'ID', id: next }, exception: next }) }
else stack.push({ type: 'ID', id: t })
}
while (ops.length) reduce(ops.pop() as string)
return stack[0]
}
function containsDenied(ast: Node, deny: Set<string>): boolean {
if (ast.type === 'ID') return deny.has(ast.id || '')
if (ast.type === 'WITH') return deny.has(ast.left?.id || '')
if (ast.type === 'AND') return containsDenied(ast.left as Node, deny) || containsDenied(ast.right as Node, deny)
if (ast.type === 'OR') return containsDenied(ast.left as Node, deny) && containsDenied(ast.right as Node, deny)
return false
}
function evaluate(expr: string, deny: Set<string>): { ok: boolean; errors: string[] } {
const tokens = tokenize(expr)
const ast = parse(tokens)
const bad = containsDenied(ast, deny)
return { ok: !bad, errors: bad ? ['license-denied'] : [] }
}
审计与发布治理审计表达式与冲突结果;命中禁止许可证阻断并输出建议。例外审批需设到期与影响范围;产线默认拒绝未审批项。

发表评论 取消回复