mirror of https://github.com/artf/grapesjs.git
committed by
GitHub
6 changed files with 353 additions and 23 deletions
@ -0,0 +1,106 @@ |
|||
import EditorModel from '../../../editor/model/Editor'; |
|||
import DataVariable from '../DataVariable'; |
|||
import { evaluateVariable, isDataVariable } from '../utils'; |
|||
import { Expression, LogicGroup } from './DataCondition'; |
|||
import { LogicalGroupStatement } from './LogicalGroupStatement'; |
|||
import { Operator } from './operators'; |
|||
import { GenericOperation, GenericOperator } from './operators/GenericOperator'; |
|||
import { LogicalOperator } from './operators/LogicalOperator'; |
|||
import { NumberOperator, NumberOperation } from './operators/NumberOperator'; |
|||
import { StringOperator, StringOperation } from './operators/StringOperations'; |
|||
|
|||
export class Condition { |
|||
private condition: Expression | LogicGroup | boolean; |
|||
private em: EditorModel; |
|||
|
|||
constructor(condition: Expression | LogicGroup | boolean, opts: { em: EditorModel }) { |
|||
this.condition = condition; |
|||
this.em = opts.em; |
|||
} |
|||
|
|||
evaluate(): boolean { |
|||
return this.evaluateCondition(this.condition); |
|||
} |
|||
|
|||
/** |
|||
* Recursively evaluates conditions and logic groups. |
|||
*/ |
|||
private evaluateCondition(condition: any): boolean { |
|||
if (typeof condition === 'boolean') return condition; |
|||
|
|||
if (this.isLogicGroup(condition)) { |
|||
const { logicalOperator, statements } = condition; |
|||
const operator = new LogicalOperator(logicalOperator); |
|||
const logicalGroup = new LogicalGroupStatement(operator, statements, { em: this.em }); |
|||
return logicalGroup.evaluate(); |
|||
} |
|||
|
|||
if (this.isExpression(condition)) { |
|||
const { left, operator, right } = condition; |
|||
const evaluateLeft = evaluateVariable(left, this.em); |
|||
const evaluateRight = evaluateVariable(right, this.em); |
|||
const op = this.getOperator(evaluateLeft, operator); |
|||
|
|||
const evaluated = op.evaluate(evaluateLeft, evaluateRight); |
|||
return evaluated; |
|||
} |
|||
|
|||
throw new Error('Invalid condition type.'); |
|||
} |
|||
|
|||
/** |
|||
* Factory method for creating operators based on the data type. |
|||
*/ |
|||
private getOperator(left: any, operator: string): Operator { |
|||
if (this.isOperatorInEnum(operator, GenericOperation)) { |
|||
return new GenericOperator(operator as GenericOperation); |
|||
} else if (typeof left === 'number') { |
|||
return new NumberOperator(operator as NumberOperation); |
|||
} else if (typeof left === 'string') { |
|||
return new StringOperator(operator as StringOperation); |
|||
} |
|||
throw new Error(`Unsupported data type: ${typeof left}`); |
|||
} |
|||
|
|||
/** |
|||
* Extracts all data variables from the condition, including nested ones. |
|||
*/ |
|||
getDataVariables(): DataVariable[] { |
|||
const variables: DataVariable[] = []; |
|||
this.extractVariables(this.condition, variables); |
|||
return variables; |
|||
} |
|||
|
|||
/** |
|||
* Recursively extracts variables from expressions or logic groups. |
|||
*/ |
|||
private extractVariables(condition: boolean | LogicGroup | Expression, variables: DataVariable[]): void { |
|||
if (this.isExpression(condition)) { |
|||
if (isDataVariable(condition.left)) variables.push(condition.left); |
|||
if (isDataVariable(condition.right)) variables.push(condition.right); |
|||
} else if (this.isLogicGroup(condition)) { |
|||
condition.statements.forEach((stmt) => this.extractVariables(stmt, variables)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Checks if a condition is a LogicGroup. |
|||
*/ |
|||
private isLogicGroup(condition: any): condition is LogicGroup { |
|||
return condition && typeof condition.logicalOperator !== 'undefined' && Array.isArray(condition.statements); |
|||
} |
|||
|
|||
/** |
|||
* Checks if a condition is an Expression. |
|||
*/ |
|||
private isExpression(condition: any): condition is Expression { |
|||
return condition && typeof condition.left !== 'undefined' && typeof condition.operator === 'string'; |
|||
} |
|||
|
|||
/** |
|||
* Checks if an operator exists in a specific enum. |
|||
*/ |
|||
private isOperatorInEnum(operator: string, enumObject: any): boolean { |
|||
return Object.values(enumObject).includes(operator); |
|||
} |
|||
} |
|||
@ -1,15 +1,24 @@ |
|||
import { LogicalOperator } from './operators/LogicalOperator'; |
|||
import { Expression, LogicGroup } from './DataCondition'; |
|||
import { evaluateCondition } from './evaluateCondition'; |
|||
import { Condition } from './Condition'; |
|||
import EditorModel from '../../../editor/model/Editor'; |
|||
|
|||
export class LogicalGroupStatement { |
|||
private em: EditorModel; |
|||
|
|||
constructor( |
|||
private operator: LogicalOperator, |
|||
private statements: (Expression | LogicGroup | boolean)[], |
|||
) {} |
|||
opts: { em: EditorModel }, |
|||
) { |
|||
this.em = opts.em; |
|||
} |
|||
|
|||
evaluate(): boolean { |
|||
const results = this.statements.map((statement) => evaluateCondition(statement)); |
|||
const results = this.statements.map((statement) => { |
|||
const condition = new Condition(statement, { em: this.em }); |
|||
return condition.evaluate(); |
|||
}); |
|||
return this.operator.evaluate(results); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
import EditorModel from '../../editor/model/Editor'; |
|||
import { DataConditionType } from './conditional_variables/DataCondition'; |
|||
import DataVariable, { DataVariableType } from './DataVariable'; |
|||
|
|||
export function isDataVariable(variable: any) { |
|||
return variable?.type === DataVariableType; |
|||
} |
|||
|
|||
export function isDataCondition(variable: any) { |
|||
return variable?.type === DataConditionType; |
|||
} |
|||
|
|||
export function evaluateVariable(variable: any, em: EditorModel) { |
|||
return isDataVariable(variable) ? new DataVariable(variable, { em }).getDataValue() : variable; |
|||
} |
|||
Loading…
Reference in new issue