export abstract class BooleanExpression { abstract evaluate( t:T ):boolean; NOT():BooleanExpression { return new NotExpression( this ); } AND( matcher:BooleanExpression):BooleanExpression { return new AndExpression( [ this, matcher ] ); } OR( matcher:BooleanExpression):BooleanExpression { return new OrExpression( [ this, matcher ] ); } AND_ALL( matchers:BooleanExpression[] ):BooleanExpression { if ( matchers.length === 0 ) { return this; } let outputExpression = this.AND( matchers[ 0 ] ); for ( let i = 1; i < matchers.length; i++ ) { outputExpression = outputExpression.AND( matchers[ i ] ); } return outputExpression; } OR_ANY( matchers:BooleanExpression[] ):BooleanExpression { if ( matchers.length === 0 ) { return this; } let outputExpression = this.OR( matchers[ 0 ] ); for ( let i = 1; i < matchers.length; i++ ) { outputExpression = outputExpression.OR( matchers[ i ] ); } return outputExpression; } } export class NotExpression extends BooleanExpression { private _matcher:BooleanExpression; constructor( matcher:BooleanExpression ) { super(); this._matcher = matcher; } evaluate( t:T ) { return ! this._matcher.evaluate( t ); } NOT() { return this._matcher; } } export abstract class ListInputExpression extends BooleanExpression { protected _matchers:BooleanExpression[]; constructor( matchers:BooleanExpression[] ) { super(); this._matchers = matchers; } } export class AndExpression extends ListInputExpression { evaluate( t:T ) { return this._matchers.every( m => m.evaluate( t ) ); } AND( matcher:BooleanExpression ) { this._matchers.push( matcher ); return this; } } export class OrExpression extends ListInputExpression { evaluate( t:T ) { return this._matchers.some( m => m.evaluate( t ) ); } OR( matcher:BooleanExpression ) { this._matchers.push( matcher ); return this; } }