import {hasProperty} from './util.js'; export type LogicalComposition = LogicalNot | LogicalAnd | LogicalOr | T; export interface LogicalOr { or: LogicalComposition[]; } export interface LogicalAnd { and: LogicalComposition[]; } export interface LogicalNot { not: LogicalComposition; } export function isLogicalOr(op: LogicalComposition): op is LogicalOr { return hasProperty(op, 'or'); } export function isLogicalAnd(op: LogicalComposition): op is LogicalAnd { return hasProperty(op, 'and'); } export function isLogicalNot(op: LogicalComposition): op is LogicalNot { return hasProperty(op, 'not'); } export function forEachLeaf(op: LogicalComposition, fn: (op: T) => void) { if (isLogicalNot(op)) { forEachLeaf(op.not, fn); } else if (isLogicalAnd(op)) { for (const subop of op.and) { forEachLeaf(subop, fn); } } else if (isLogicalOr(op)) { for (const subop of op.or) { forEachLeaf(subop, fn); } } else { fn(op); } } export function normalizeLogicalComposition( op: LogicalComposition, normalizer: (o: T) => T, ): LogicalComposition { if (isLogicalNot(op)) { return {not: normalizeLogicalComposition(op.not, normalizer)}; } else if (isLogicalAnd(op)) { return {and: op.and.map((o) => normalizeLogicalComposition(o, normalizer))}; } else if (isLogicalOr(op)) { return {or: op.or.map((o) => normalizeLogicalComposition(o, normalizer))}; } else { return normalizer(op); } }