@o3r/rules-engine
Version:
This module provides a rule engine that can be executed on your Otter application to customize your application (translations, placeholders and configs) based on a json file generated by your CMS.
1,222 lines (1,198 loc) • 71.2 kB
TypeScript
import * as i0 from '@angular/core';
import { PipeTransform, ModuleWithProviders, InjectionToken } from '@angular/core';
import * as rxjs from 'rxjs';
import { Observable, BehaviorSubject } from 'rxjs';
import * as _o3r_core from '@o3r/core';
import { RulesEngineAction, ItemIdentifier, Logger, DevtoolsCommonOptions, OtterMessageContent, MessageDataTypes, ConnectContentMessage, RequestMessagesContentMessage, DevtoolsServiceInterface, AsyncStoreItem, SetActionPayload, UpdateActionPayload, AsyncRequest, SetAsyncStoreItemEntitiesActionPayload, FailAsyncStoreItemEntitiesActionPayload, FromApiActionPayload, Serializer, RulesEngineActionHandler } from '@o3r/core';
import * as _o3r_rules_engine from '@o3r/rules-engine';
import * as i3 from '@o3r/logger';
import { Logger as Logger$1 } from '@o3r/logger';
import * as i1 from '@angular/common';
import * as _ngrx_store from '@ngrx/store';
import { ActionReducer, Action, ReducerTypes, ActionCreator, Store } from '@ngrx/store';
import * as _ngrx_entity from '@ngrx/entity';
import { EntityState } from '@ngrx/entity';
import * as _ngrx_effects from '@ngrx/effects';
import { Actions } from '@ngrx/effects';
/** Represents all the supported facts types TOCHECK utils.Date vs Date */
type Facts = string | number | boolean | null | Date | Record<string, unknown> | unknown[];
/** Fact basic value type */
type FactBasicValues = number | boolean | string | string[] | boolean[] | number[] | undefined;
/** Map of fact name / type pairs */
interface FactDefinitions {
[factName: string]: unknown;
}
/** Return type of a fact factory */
type FactFactoryReturn<T> = Observable<T> | Promise<T> | T;
/** Set of facts */
type FactSet<T extends FactDefinitions> = {
[P in keyof T]: FactFactoryReturn<T[P] | undefined | null>;
};
/** Fact stream type */
type FactValueStream<T = unknown> = Observable<T | undefined>;
/** Fact stream */
interface Fact<T = unknown> {
/** Fact ID */
id: string;
/** Stream of the fact fact value */
value$: FactValueStream<T>;
}
/**
* Rule Engine operator
*/
interface Operator<LeftExposed = unknown, RightExposed = unknown, LeftSupported = LeftExposed, RightSupported = RightExposed> {
/** Operator name to use in condition */
name: string;
/** Priority in the dropdown display */
orderingWeight?: number;
/** Left Hand Value validator function */
validateLhs?: unknown extends LeftSupported ? (operand: unknown) => boolean : (operand: unknown) => operand is LeftSupported;
/** Right Hand Value validator function */
validateRhs?: unknown extends RightSupported ? (operand: unknown) => boolean : (operand: unknown) => operand is RightSupported;
/** Evaluate the values */
evaluator: (lhs: LeftSupported, rhs: RightSupported, operatorFactValues?: Record<string, Facts>) => boolean;
/** List of facts names that the operator can depend on */
factImplicitDependencies?: string[];
}
/**
* Rule Engine unary operator
*/
interface UnaryOperator<L = unknown> {
/** Operator name to use in condition */
name: string;
/** Left Hand Value validator function */
validateLhs?: unknown extends L ? (operand: unknown) => boolean : (operand: unknown) => operand is L;
/** Evaluate the values */
evaluator: (lhs: L) => boolean;
}
/**
* Alias for supported simple types in AEM to be used in the operators to avoid repetition of the
* (string | boolean | Date | number)
* This type reference is specifically handled by the rule operator extractor.
*/
type SupportedSimpleTypes = string | boolean | Date | number | null | undefined;
/**
* Any input that can be used as single parameter for Date constructor (Date, string, number)
*/
type DateInput = Date | string | number;
/**
* Execute Operator
* @param lhs Left hand side
* @param rhs Right hand side
* @param operator Operator to compare values
* @param operatorFacts Facts that operator can depend on
*/
declare function executeOperator<L = unknown, R = unknown>(lhs: L, rhs: R, operator: Operator<L, R>, operatorFacts?: Record<string, Facts | undefined>): boolean;
/**
* Validate a number operand
* @param operand value of one of the operands
*/
declare function numberValidator(operand: unknown): operand is number | string;
/**
* Validate an operand is a range of numbers
* @param operatorInput value of one of the operands
*/
declare function isRangeNumber(operatorInput: unknown): operatorInput is [number | string, number | string];
/**
* Verifies if the parameter is a valid date for the operator (getTime function available returning a number)
* @param operatorInput
*/
declare const isValidDate: (operatorInput: any) => operatorInput is Date;
/**
* Verifies if the parameter is a valid input for Date constructor (new Date returns a valid date)
* @param operatorInput
*/
declare const isValidDateInput: (operatorInput: any) => operatorInput is DateInput;
/**
* Verifies if the parameter is a valid date range
* @param operatorInput
*/
declare const isValidDateRange: (operatorInput: any) => operatorInput is [DateInput, DateInput];
/**
* Verifies if the parameter is a valid time input
* @param operatorInput
*/
declare const isValidTimeInput: (operatorInput: any) => operatorInput is string;
/**
* Verifies if the parameter is a valid time range
* @param operatorInput
*/
declare const isValidTimeRange: (operatorInput: any) => operatorInput is [string, string];
/**
* Validate that a value is a supported simple type
* @param value value to validate
*/
declare function isSupportedSimpleTypes(value: unknown): value is SupportedSimpleTypes;
/**
* Validate that a value is a string
* @param value
*/
declare function isString(value: unknown): value is string;
/**
* Parse input to return RegExp
* @param inputRegExp
*/
declare function parseRegExp(inputRegExp: string): RegExp;
/**
* Check if any of the variable's value is equal to a specific value
* @title contains
*/
declare const arrayContains: Operator<SupportedSimpleTypes[], SupportedSimpleTypes>;
/**
* Check if the specified text value is included in the text variable
* @title contains
*/
declare const stringContains: Operator<string, string>;
/**
* Check if every value of the variable is different from a specific value
* @title does not contain
*/
declare const notArrayContains: Operator<SupportedSimpleTypes[], SupportedSimpleTypes>;
/**
* Check if the specified text value is not included in the text variable
* @title does not contain
*/
declare const notStringContains: Operator<string, string>;
/**
* Check if every value of the variable equals a specific value
* @title all equal to
*/
declare const allEqual: Operator<SupportedSimpleTypes[], SupportedSimpleTypes>;
/**
* Check if every numerical value of the variable is greater than a specific value
* @title all >
*/
declare const allGreater: Operator<SupportedSimpleTypes[], number | string>;
/**
* Check if every value of the variable is in a specific list
* @title all in
*/
declare const allIn: Operator<SupportedSimpleTypes[], SupportedSimpleTypes[]>;
/**
* Check if every value of the variable is not in a specific list
* @title none in
*/
declare const allNotIn: Operator<SupportedSimpleTypes[], SupportedSimpleTypes[]>;
/**
* Check if every numerical value of the variable is lower than a specific value
* @title all <
*/
declare const allLower: Operator<number[], number | string>;
/**
* Check if every string value of the variable matches a specific pattern
* @title all match
*/
declare const allMatch: Operator<string[], string>;
/**
* Check if every value of the variable is included in a specified range
* @title all between
*/
declare const allRangeNumber: Operator<number[], [number | string, number | string]>;
/**
* Check if at least one of the values of the variable equals a specific value
* @title one equal to
*/
declare const oneEquals: Operator<SupportedSimpleTypes[], SupportedSimpleTypes>;
/**
* Check if one of the values of the variable is greater than a specific value
* @title one >
*/
declare const oneGreater: Operator<number[], number | string>;
/**
* Check if at least one of the values of the variable is equal to one in a specified list
* @title one in
*/
declare const oneIn: Operator<SupportedSimpleTypes[], SupportedSimpleTypes[]>;
/**
* Check if one of the values of the variable is lower than a specific value
* @title one <
*/
declare const oneLower: Operator<number[], number | string>;
/**
* Check if one of the values of the variable matches a specific pattern
* @title one matches
*/
declare const oneMatches: Operator<string[], string>;
/**
* Check if one of the values of the variable is included in a specified range
* @title one between
*/
declare const oneRangeNumber: Operator<number[], [number | string, number | string]>;
/**
* Check if the number of values of the variable is equal to a specific value
* @title number of =
*/
declare const lengthEquals: Operator<any[], number | string>;
/**
* Check if the number of values of the variable is different from a specific value
* @title number of ≠
*/
declare const lengthNotEquals: Operator<any[], number | string>;
/**
* Check if the number of values of the variable is lower or equal to a specific value
* @title number of ≤
*/
declare const lengthLessThanOrEquals: Operator<any[], number | string>;
/**
* Check if the number of values of the variable is lower than a specific value
* @title number of <
*/
declare const lengthLessThan: Operator<any[], number | string>;
/**
* Check if the number of values of the variable is greater or equal to a specific value
* @title number of ≥
*/
declare const lengthGreaterThanOrEquals: Operator<any[], number | string>;
/**
* Check if the number of values of the variable is greater than a specific value
* @title number of >
*/
declare const lengthGreaterThan: Operator<any[], number | string>;
/** List of all default array operators */
declare const arrayBasedOperators: (Operator<SupportedSimpleTypes[], SupportedSimpleTypes, SupportedSimpleTypes[], SupportedSimpleTypes> | Operator<string, string, string, string> | Operator<SupportedSimpleTypes[], string | number, SupportedSimpleTypes[], string | number> | Operator<SupportedSimpleTypes[], SupportedSimpleTypes[], SupportedSimpleTypes[], SupportedSimpleTypes[]> | Operator<number[], string | number, number[], string | number> | Operator<string[], string, string[], string> | Operator<number[], [string | number, string | number], number[], [string | number, string | number]> | Operator<any[], string | number, any[], string | number>)[];
/**
* Check if a variable is equal to a specific value
* @title is equal to
*/
declare const equals: Operator;
/**
* Check if a variable is different from a specific value
* @title is not equal to
*/
declare const notEquals: Operator;
/**
* Check if the variable's value is included in a specified list
* @title is in
*/
declare const inArray: Operator<SupportedSimpleTypes, SupportedSimpleTypes[]>;
/**
* Check if the variable's value is not included in the value list
* @title is not in
*/
declare const notInArray: Operator<SupportedSimpleTypes, SupportedSimpleTypes[]>;
/**
* Check if the text variable is part of the specified value
* @title within
*/
declare const inString: Operator<string, string>;
/**
* Check if the text variable is not part of the specified value
* @title not within
*/
declare const notInString: Operator<string, string>;
/**
* Check if the variable and its value are defined
* @title is defined
*/
declare const isDefined: UnaryOperator<any>;
/**
* Check if the variable and its value are undefined
* @title is not defined
*/
declare const isUndefined: UnaryOperator<any>;
/**
* Check if the text variable matches the specified RegExp pattern
* @title matches the pattern
*/
declare const matchesPattern: Operator<string, string>;
/** List of all default basic operators */
declare const basicOperators: (Operator<string, string, string, string> | Operator<unknown, unknown, unknown, unknown> | Operator<SupportedSimpleTypes, SupportedSimpleTypes[], SupportedSimpleTypes, SupportedSimpleTypes[]> | UnaryOperator<any>)[];
/**
* Check if a date variable is in a specified date range
* @title is between
*/
declare const inRangeDate: Operator<Date, [DateInput, DateInput], DateInput>;
/**
* Check if the value of the variable is in the next x minutes
* @title is in next minutes
* @returns false for dates before `now` and for dates after `now` + `nextMinutes`, true for dates between `now` and `now` + `nextMinutes`
*/
declare const dateInNextMinutes: Operator<Date, number, DateInput, string | number>;
/**
* Check if the value of the variable is not in the next x minutes
* @title is not in next minutes
* @returns false for dates before `now` and for dates between `now` and `now` + `nextMinutes`, true for dates after `now` + `nextMinutes`
*/
declare const dateNotInNextMinutes: Operator<Date, number, DateInput, string | number>;
/**
* Check if a date variable is prior than a specified date
* @title is before
*/
declare const dateBefore: Operator<Date, DateInput, DateInput>;
/**
* Check if a date variable is posterior than a specified date
* @title is after
*/
declare const dateAfter: Operator<Date, DateInput, DateInput>;
/**
* Check if a date variable is the same as a specified date
* @title is equal to
*/
declare const dateEquals: Operator<Date, DateInput, DateInput>;
/**
* Check if a date variable is different from a specified date
* @title is not equal
*/
declare const dateNotEquals: Operator<Date, DateInput, DateInput>;
declare const dateBasedOperators: (Operator<Date, [DateInput, DateInput], DateInput, [DateInput, DateInput]> | Operator<Date, number, DateInput, string | number> | Operator<Date, DateInput, DateInput, DateInput>)[];
/**
* Check if the number variable is greater or equal to a specific value
* @title ≥
*/
declare const greaterThanOrEqual: Operator<number, number, number | string, number | string>;
/**
* Check if the number variable is greater than a specific value
* @title >
*/
declare const greaterThan: Operator<number, number, number | string, number | string>;
/**
* Check if the number variable is lower or equal to a specific value
* @title ≤
*/
declare const lessOrEqual: Operator<number, number, number | string, number | string>;
/**
* Check if the number variable is lower than a specific value
* @title <
*/
declare const lessThan: Operator<number, number, number | string, number | string>;
/** List of all default number based operators */
declare const numberBasedOperators: Operator<number, number, string | number, string | number>[];
declare const operatorList: (_o3r_rules_engine.Operator<_o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes, _o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes> | _o3r_rules_engine.Operator<string, string, string, string> | _o3r_rules_engine.Operator<_o3r_rules_engine.SupportedSimpleTypes[], string | number, _o3r_rules_engine.SupportedSimpleTypes[], string | number> | _o3r_rules_engine.Operator<_o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes[]> | _o3r_rules_engine.Operator<number[], string | number, number[], string | number> | _o3r_rules_engine.Operator<string[], string, string[], string> | _o3r_rules_engine.Operator<number[], [string | number, string | number], number[], [string | number, string | number]> | _o3r_rules_engine.Operator<any[], string | number, any[], string | number> | _o3r_rules_engine.Operator<unknown, unknown, unknown, unknown> | _o3r_rules_engine.Operator<_o3r_rules_engine.SupportedSimpleTypes, _o3r_rules_engine.SupportedSimpleTypes[], _o3r_rules_engine.SupportedSimpleTypes, _o3r_rules_engine.SupportedSimpleTypes[]> | _o3r_rules_engine.UnaryOperator<any> | _o3r_rules_engine.Operator<Date, [_o3r_rules_engine.DateInput, _o3r_rules_engine.DateInput], _o3r_rules_engine.DateInput, [_o3r_rules_engine.DateInput, _o3r_rules_engine.DateInput]> | _o3r_rules_engine.Operator<Date, number, _o3r_rules_engine.DateInput, string | number> | _o3r_rules_engine.Operator<Date, _o3r_rules_engine.DateInput, _o3r_rules_engine.DateInput, _o3r_rules_engine.DateInput> | _o3r_rules_engine.Operator<number, number, string | number, string | number>)[];
type NativeTypes = string | boolean | number;
/** Generic operand */
interface Operand<T extends string, U extends NativeTypes = NativeTypes> {
/** Operand type */
type: T;
/** Static value */
value: U;
}
/** Operand based on fact */
interface OperandFact extends Operand<'FACT', string> {
/** JSONPath to deep read the fact value */
path?: string;
}
/** Condition available operand types */
type GenericOperand = OperandFact | Operand<'RUNTIME_FACT', string> | Operand<'LITERAL'>;
/** Condition object interface with unary operator */
interface UnaryOperation {
/** Left Hand Side */
lhs: GenericOperand;
/** Operator */
operator: string;
}
/** Condition object interface */
interface BinaryOperation {
/** Left Hand Side */
lhs: GenericOperand;
/** Right Hand Side */
rhs: GenericOperand;
/** Operator */
operator: string;
}
/** Nested Condition */
type NestedCondition = UnaryOperation | BinaryOperation | TopLevelCondition;
/** All Condition */
type AllConditions = {
all: NestedCondition[];
any?: never;
not?: never;
};
/** Any Condition */
type AnyConditions = {
any: NestedCondition[];
all?: never;
not?: never;
};
/** Not Condition */
type NotCondition = {
not: NestedCondition;
all?: never;
any?: never;
};
/** Top level Condition in the rule definition */
type TopLevelCondition = AllConditions | AnyConditions | NotCondition | UnaryOperation | BinaryOperation;
/** Event emitted in case the rule condition is passed */
interface RuleEvent {
/** Type (or name) of the event */
type: string;
/** list of parameter associated to the event */
params?: Record<string, any>;
}
/** Base for the Rule definition */
interface Rule {
/** Unique id associated to a rule*/
id: string;
/** Runtime facts that are needed for the rule execution (sent by the CMS) */
inputRuntimeFacts: string[];
/** Runtime facts that are created/updated by the rule*/
outputRuntimeFacts: string[];
/** Name of the rule*/
name: string;
/** rootElement of the rule, that contains either a block, either an action list */
rootElement: AllBlock;
}
/**
* List of possible types of actions resulted as output of a rule execution
* @deprecated the actions are now depending of executing modules
*/
type ActionTypes = 'SET_FACT' | 'UPDATE_CONFIG' | 'UPDATE_ASSET' | 'UPDATE_LOCALISATION' | 'UPDATE_PLACEHOLDER';
/** Types associated to the condition blocks that are supported */
type ConditionBlockTypes = 'IF_ELSE';
/** Interface common to all elements */
interface RuleElement {
/** Type of the element*/
elementType: string;
}
/** Interface common to all actions */
interface ActionBlock extends RuleElement, RulesEngineAction {
elementType: 'ACTION';
actionType: string;
value: any;
}
/** Interface of action that sets or updates a temporary fact */
interface ActionSetTemporaryFactBlock extends ActionBlock {
actionType: 'SET_FACT';
fact: string;
}
/** Interface of block Rule */
interface RuleBlock extends RuleElement {
elementType: 'RULE_BLOCK';
blockType: ConditionBlockTypes;
}
/** All supported blocks (supporting nested structure) */
type AllBlock = IfElseBlock | (ActionBlock & Record<string, any>);
/** Block representing an 'if else' condition. If no condition specified it will execute success elements only */
interface IfElseBlock extends RuleBlock {
blockType: 'IF_ELSE';
successElements: AllBlock[];
failureElements: AllBlock[];
condition?: TopLevelCondition;
}
/** Interface of a ruleset as it's specified in the json file */
interface Ruleset {
/** Unique id of the ruleset*/
id: string;
/** Name of the ruleset */
name: string;
/** Optional ruleset description */
description?: string;
/** List of rules associated to the ruleset */
rules: Rule[];
/** Optional date range where the ruleset will be executed*/
validityRange?: {
from?: string;
to?: string;
};
/**
* Components linked to the ruleset. If present the ruleset will not be active by default.
* 'or' condition: If at least one component has subscribed, the ruleset will become active.
*/
linkedComponents?: {
or: ItemIdentifier[];
};
}
/** Performance object supporting NodeJs Performance and Web Performance reporting */
type CrossPlatformPerformance = {
/** @see Performance.mark */
mark: (...x: Parameters<Performance['mark']>) => ReturnType<Performance['mark']> | void;
/** @see Performance.measure */
measure: (measureName: string, startOrMeasureOptions?: string, endMark?: string) => ReturnType<Performance['measure']> | void;
};
/** Fact stream object to handle fact reference change */
interface FactObject<T> {
/** Subject of fact stream */
subject: BehaviorSubject<Observable<T> | undefined>;
/** Stream of the fact value */
value$: Observable<T | undefined>;
}
/** Rule Engine constructor options */
interface RulesEngineOptions {
/** List of facts */
facts?: Fact<Facts>[];
/** List of rules */
rules?: Ruleset[];
/** List of custom operators */
operators?: Operator<any, any>[];
/** Delay before fact stream defaulting value */
factDefaultDelay?: number;
/**
* Skip the rule and fact circular dependency checks
* Turn to true to increase the speed of the upsert of a rule
*/
skipCircularDependencyChecks?: boolean;
/**
* Provide debugger instance to the rules engine
*/
debugger?: EngineDebugger;
/**
* Instance of the performance reporter to use for performance measurements.
* @default window.performance on browser only, undefined on node
*/
performance?: CrossPlatformPerformance;
/**
* Name of the rules engine instance
* @default RulesEngine
*/
rulesEngineInstanceName?: string;
/**
* Client to log the warning and error message
*/
logger?: Logger;
}
/** Rule as stored in the rules engine */
interface EngineRule extends Rule {
/** stream of the rule conditions result */
result$: BehaviorSubject<ActionBlock[]>;
}
/** Rule as stored in the rules engine */
interface EngineRuleset {
/** Optional date range where the ruleset will be executed, it supports a dateString or a timestamp as number, more info on javascript Date() documentation */
validityRange?: {
from?: string | number;
to?: string | number;
};
/**
* Components linked to the ruleset. If present the ruleset will not be active by default.
* 'or' condition: If at least one component has subscribed, the ruleset will become active.
*/
linkedComponents?: {
or: ItemIdentifier[];
};
/** Unique id of the ruleset*/
id: string;
/** Stores the result of each rules from the ruleset */
rulesResultsSubject$: Observable<ActionBlock[]>;
}
/** Timestamp of a rules engine output event */
interface TimedEvent {
/** Timestamp value when the event occurs */
timestamp: number;
/** Duration of the execution */
duration?: number;
}
/** Fact change triggering the evaluation of a rule/execution of a ruleset */
interface EvaluationReason {
/** Name of the fact that changed */
factName: string;
/** New value of the fact */
newValue?: Facts;
/** Old value of the fact */
oldValue?: Facts;
}
/** Result object resulted at the end of a rule evaluation */
interface RuleEvaluation extends TimedEvent {
/** Identifier of the evaluation (ruleset name + rule name) */
id: string;
/** Evaluated rule identifier */
rule: Pick<Rule, 'id' | 'name'>;
/** Actions outputted by the rule evaluation */
outputActions: ActionBlock[] | undefined;
/** Map containing the facts changes triggering the rule evaluation */
triggers: Record<string, Record<string, EvaluationReason>>;
/** Error object in case of rule evaluation failure */
error?: any;
/** Runtime facts with values at the end of rule evaluation */
temporaryFacts?: Record<string, Facts>;
/** Flag to notify if the rules evaluation comes from an old ruleset execution */
cached?: boolean;
}
/** Wrapped rule evaluation output */
interface RuleEvaluationOutput {
/** Actions emitted at the end of rule evaluation */
actions: ActionBlock[] | undefined;
/** Rule evaluation output object */
evaluation?: RuleEvaluation;
/** Error object emitted at the end of rule evaluation, if any */
error?: any;
}
/** Base object resulted at the end of a ruleset execution */
interface BaseRulesetExecution {
/** Id of the ruleset execution */
executionId: string;
/** Id of the ruleset which was executed */
rulesetId: string;
/** Name of the executed ruleset */
rulesetName: string;
/** Counter of executions for the ruleset */
executionCounter: number;
/** All input facts affecting the ruleset */
inputFacts: {
factName: string;
value: Facts;
}[];
/** Runtime facts used across the ruleset */
temporaryFacts?: Record<string, Facts>;
/** Facts changes that triggered the execution of the ruleset */
triggers: Record<string, Record<string, EvaluationReason>>;
/** List of evaluated rules accros ruleset execution */
rulesEvaluations: RuleEvaluation[];
}
/** Debug event emitted in case of successful ruleset execution */
interface RulesetExecutionEvent extends BaseRulesetExecution, TimedEvent {
/** Event type */
type: 'RulesetExecution';
/** List of the actions emitted at the end of ruleset execution */
outputActions: ActionBlock[];
}
/** Debug event emitted in case of ruleset execution failure */
interface RulesetExecutionErrorEvent extends BaseRulesetExecution, TimedEvent {
/** Event type */
type: 'RulesetExecutionError';
/** List of rules causing the execution error*/
rulesCausingTheError: Pick<Rule, 'name' | 'id'>[];
/** List of outputted errors */
errors: any[];
}
/** Debug event emitted when active rulesets are changing */
interface ActiveRulesetsEvent extends TimedEvent {
/** Event type */
type: 'ActiveRulesets';
/** List of active rulesets */
rulesets: Pick<Ruleset, 'name' | 'id'>[];
}
/** Debug event emitted each time the Rules Engine outputs a list of actions */
interface AllActionsEvent extends TimedEvent {
/** event type */
type: 'AllActions';
/** List of emitted actions */
actions: ActionBlock[];
}
/** Debug event emitted when rulesets are registered to the rules engine */
interface AvailableRulesets extends TimedEvent {
/** Event type */
type: 'AvailableRulesets';
/** Registered rulesets list */
availableRulesets: Pick<Ruleset, 'name' | 'id'>[];
}
/** Debug event emitted when facts are updated */
interface AvailableFactsSnapshot extends TimedEvent {
/** Event type */
type: 'AvailableFactsSnapshot';
/** List of all facts */
facts: {
factName: string;
value: Facts;
}[];
}
/** Type of possible debug events emitted by Rules Engine */
type DebugEvent = RulesetExecutionEvent | RulesetExecutionErrorEvent | ActiveRulesetsEvent | AllActionsEvent | AvailableRulesets | AvailableFactsSnapshot;
/** Rules engine */
declare class RulesEngine {
/** Map of registered fact stream, this map is mutated by the ruleset executors */
private readonly factMap;
/** Subject containing the rulesets and the results stream*/
private readonly rulesetMapSubject;
/** Map of available operators */
operators: Record<string, Operator<unknown, unknown>>;
/** List of events for the current state of the rules engine */
readonly events$: Observable<ActionBlock[]>;
/** Delay before fact stream defaulting value */
factDefaultDelay?: number;
/**
* Instance of engine debug object; Undefined if debugMode is not active
*/
readonly engineDebug?: EngineDebugger;
/** Name of the rules engine instance */
readonly rulesEngineInstanceName: string;
/**
* Performance reporter to use for performance measurements.
* @default window.performance on browser only, undefined on node
*/
readonly performance: _o3r_rules_engine.CrossPlatformPerformance | undefined;
/**
* Log the engine errors
*/
readonly logger?: Logger$1;
/**
* Flag to check if the run is in debug mode or not
*/
get debugMode(): boolean;
/**
* Rules engine
* @param options rules engine options
*/
constructor(options?: RulesEngineOptions);
/**
* Attach debug events to actions stream if debug engine is activated
*/
private handleActionsStreamOutput;
/**
* Create the actions stream event based on provided active rulesets ids; Handle debug too
* @param ruleSets
*/
private prepareActionsStream;
/**
* Create or retrieve a fact stream
* The fact stream created will be registered in the engine
* @param id ID of the fact to retrieve
* @param factValue$ Value stream for the fact
*/
retrieveOrCreateFactStream<T = Facts>(id: string, factValue$?: Observable<T>): Observable<T | undefined>;
/**
* Retrieve the promise of the latest value of a fact.
* Return undefined if the fact is not defined.
* @param id ID of the fact to retrieve
*/
retrieveFactValue<T = unknown>(id: string): Promise<T | undefined> | undefined;
/**
* Update or insert fact in rules engine
* @param facts fact list to add / update
*/
upsertFacts<T = unknown>(facts: Fact<T> | Fact<T>[]): void;
/**
* Update or insert rule in rules engine
* @param rulesets
*/
upsertRulesets(rulesets: Ruleset[]): void;
/**
* Update or insert operator in rules engine
* @param operators operator list to add / update
*/
upsertOperators(operators: (Operator<any, any> | UnaryOperator<any>)[]): void;
/**
* Operator to apply on a stream of rulesets ids
* Returns a stream of actions outputted by the rules engine, corresponding to the rulesetsIds
*/
getEventStream<T extends ActionBlock = ActionBlock>(): (rulesetsIds$: Observable<string[] | undefined>) => Observable<T[]>;
/** Get the list of registered facts names */
getRegisteredFactsNames(): string[];
}
declare class RulesetExecutor {
/** retrieveFactFunc */
protected readonly rulesEngine: RulesEngine;
/** Map of available operators */
protected readonly operators: Record<string, Operator<unknown, unknown>>;
/** Delay before fact stream defaulting value */
readonly factDefaultDelay?: number;
/** Ruleset associated to the current executor*/
readonly ruleset: Ruleset;
/** Ruleset plugged to the fact stream, that contains actions stream result */
readonly engineRuleset: EngineRuleset;
private executionCounter;
/**
* Create a new ruleset executor
* @param ruleset Ruleset to evaluate
* @param rulesEngine Instance of the rules engine
*/
constructor(ruleset: Ruleset, rulesEngine: RulesEngine);
/**
* Recursively explores a rule to identify and collect input facts.
* Input facts are identified based on the 'FACT' type and operator-specific implicit dependencies.
* @param currentObject The current object being explored.
* @param ruleInputFacts A set to store the identified input facts for the rule.
*/
private collectRuleInputFacts;
/**
* Report performance mark for a rule run
* @param rule Rule to measure
* @param status status of the rule evaluation
*/
protected performanceMark(rule: Rule, status: 'start' | 'end'): void;
/**
* Get operand value stream according to its type
* @param operand operand of the condition
* @param factsValue
* @param runtimeFactValues
*/
protected getOperandValue(operand: GenericOperand | undefined, factsValue: Record<string, Facts | undefined>, runtimeFactValues: Record<string, Facts>): unknown;
/**
* Process a root rule from a ruleset, and return the associated actions to be processed
* Will also update the runtimeFactValues map that is ruleset wise
* Note that runtimeFactValues will be mutated by all the runtime facts actions executed
* @param rule
* @param factsValue
* @param runtimeFactValues
* @protected
*/
protected evaluateRule(rule: Rule, factsValue: Record<string, Facts | undefined>, runtimeFactValues: Record<string, Facts>): ActionBlock[];
/**
* Recursively process a block to extract all the actions keeping the order
* Note that runtimeFactValues will be mutated by all the runtime facts actions executed
* @param element
* @param factsValue
* @param runtimeFactValues This runtime fact map will be mutated by all the runtime facts actions executed
* @param actions
* @protected
*/
protected evaluateBlock(element: AllBlock, factsValue: Record<string, Facts | undefined>, runtimeFactValues: Record<string, Facts>, actions?: ActionBlock[]): ActionBlock[];
/**
* Returns true if the element is a IfElse block
* @param element
* @protected
*/
protected isIfElseBlock(element: AllBlock): element is IfElseBlock;
/**
* Returns true if the element is an action block
* @param element
* @protected
*/
protected isActionBlock(element: AllBlock): element is ActionBlock;
/**
* Returns true if the action sets a temporary fact
* @param element
* @protected
*/
protected isActionSetTemporaryFactBlock(element: ActionBlock): element is ActionSetTemporaryFactBlock;
/**
* Evaluate a condition block
* @param nestedCondition
* @param factsValue
* @param runtimeFactValues
* @protected
*/
protected evaluateCondition(nestedCondition: NestedCondition, factsValue: Record<string, Facts | undefined>, runtimeFactValues: Record<string, Facts>): boolean;
/**
* Find rule input facts
* @param obj
*/
protected readonly findRuleInputFacts: (obj: AllBlock) => string[];
/**
* Plug ruleset to fact streams and trigger a first evaluation
*/
protected plugRuleset(): EngineRuleset;
}
interface EngineDebuggerOptions {
/**
* Limit of events to keep in the stack before subscribing to the debugEvents$ stream.
* @default undefined no limit
*/
eventsStackLimit?: number;
}
/**
* Rules engine debugger object to emit debug events
*/
declare class EngineDebugger {
private registeredRuleEngine?;
private registeredRulesets;
private readonly debugEventsSubject$;
private performanceMeasures$;
private readonly requestFactsSnapshot;
/** Stream emitting a debug event when is fired; timeline is kept */
readonly debugEvents$: Observable<DebugEvent>;
/** Retrieved the rules engine plugged to the debugger */
get rulesEngine(): RulesEngine | undefined;
/**
* Instantiate a rules engine debugger
* @param options Options to configure the debugger
*/
constructor(options?: EngineDebuggerOptions);
private initializePerformanceObserver;
private createBaseExecutionOutputObject;
private rulesetExecution;
private rulesetExecutionError;
/**
* Plug the debugger to a Rule Engine
* @param rulesEngine
*/
registerRuleEngine(rulesEngine: RulesEngine): void;
/**
* Handle ruleset execution debug info
* @param currRes
* @param prevRes
* @param allExecutionsValid
* @param rulesetInputFacts
* @param runtimeFactValues
* @param executionCounter
* @param ruleset
*/
handleDebugRulesetExecutionInfo(currRes: RuleEvaluationOutput[], prevRes: RuleEvaluationOutput[] | undefined, allExecutionsValid: boolean, rulesetInputFacts: string[], runtimeFactValues: Record<string, Facts>, executionCounter: number, ruleset: Ruleset): {
executionCounter: number;
rulesetOutputExecution: RuleEvaluation[];
allExecutionsValid: boolean;
rulesetTriggers: Record<string, Record<string, EvaluationReason>>;
};
/**
* Emits an 'AvailableRulesets' debug event when rulesets are registered to the rules engine
* @param rulesets
*/
addAvailableRulesets(rulesets: Ruleset[]): void;
/**
* Computes and emits an 'ActiveRulesets' debug event when the active rulesets are changing
* @param ruleSetExecutorMap map off all rulesets executors
* @param restrictiveRuleSets ids of the rulesets to activate; if not provided all registered rulesets will be considered as active
*/
activeRulesetsChange(ruleSetExecutorMap: Record<string, RulesetExecutor>, restrictiveRuleSets?: string[]): void;
/**
* Emits an 'AllActions' debug event each time the rules engine outputs the list of actions
* @param actions list of outputted actions
*/
allActionsChange(actions: ActionBlock[]): void;
/**
* Emits a 'RulesetExecution' debug event at the output of a successful ruleset execution
* @param ruleset
* @param executionCounter
* @param rulesetInputFacts
* @param allOutputActions
* @param runtimeFactValues
* @param rulesetTriggers
* @param rulesExecutions
*/
addRulesetExecutionEvent(ruleset: Ruleset, executionCounter: number, rulesetInputFacts: string[], allOutputActions: ActionBlock[], runtimeFactValues: Record<string, Facts>, rulesetTriggers: Record<string, Record<string, EvaluationReason>>, rulesExecutions: RuleEvaluation[]): void;
/**
* Emits a 'RulesetExecutionError' debug event at the output of a failing ruleset execution
* @param ruleset
* @param rulesetInputFacts
* @param executionCounter
* @param runtimeFactValues
* @param rulesetTriggers
* @param rulesExecutions
*/
addRulesetExecutionErrorEvent(ruleset: Ruleset, rulesetInputFacts: string[], executionCounter: number, runtimeFactValues: Record<string, Facts>, rulesetTriggers: Record<string, Record<string, EvaluationReason>>, rulesExecutions: RuleEvaluation[]): void;
/**
* Emits a 'AvailableFactsSnapshot' debug event when a fact value is updated
* @param _id
* @param factValue$
*/
addAvailableFactsSnapshotEvent(_id: string, factValue$: Observable<any>): void;
/**
* Returns a list of fact name and value pairs
* @param factsNames List of facts names to get the value for
*/
getFactsSnapshot(factsNames: string[]): Promise<{
factName: string;
value: any;
}[]>;
}
/**
* Determine if the condition is a properties condition
* @param condition Condition to analyze
*/
declare function isConditionProperties(condition: any): condition is BinaryOperation | UnaryOperation;
/**
* Determine if the given operand is a Fact operand
* @param operand Operand to analyze
*/
declare function isOperandFact(operand: any): operand is OperandFact;
/**
* Determine if the given operand is a Inner Fact operand
* @param operand Operand to analyze
*/
declare function isOperandRuntimeFact(operand: any): operand is Operand<'RUNTIME_FACT', string>;
/**
* Determine if the given operand is a Static Value operand
* @param operand Operand to analyze
*/
declare function isOperandLiteral(operand: any): operand is Operand<'LITERAL'>;
/**
* Determine if the given condition is All based child conditions
* @param condition Condition node
*/
declare function isAllConditions(condition: any): condition is AllConditions;
/**
* Determine if the given condition is Any based child conditions
* @param condition Condition node
*/
declare function isAnyConditions(condition: any): condition is AnyConditions;
/**
* Determine if the given condition is Not based child conditions
* @param condition Condition node
*/
declare function isNotCondition(condition: any): condition is NotCondition;
declare class FactsSnapshotComponent {
/**
* Full list of available facts with their current value
*/
readonly facts: i0.InputSignal<{
factName: string;
value: Facts;
}[]>;
/**
* Search terms
*/
readonly search: i0.WritableSignal<string>;
/**
* Filtered list of facts using search terms
*/
readonly filteredFacts: i0.Signal<{
factName: string;
value: Facts;
}[]>;
static ɵfac: i0.ɵɵFactoryDeclaration<FactsSnapshotComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<FactsSnapshotComponent, "o3r-facts-snapshot", never, { "facts": { "alias": "facts"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
}
type RulesetExecutionStatus = 'Error' | 'Active' | 'Deactivated' | 'NoEffect';
/**
* Model of a RulesetExecution with more information for debug purpose
*/
type RulesetExecutionDebug = (RulesetExecutionEvent | RulesetExecutionErrorEvent) & {
isActive: boolean;
status: RulesetExecutionStatus;
rulesetInformation: Ruleset | undefined;
};
declare class RulesetHistoryPresComponent {
private readonly cd;
/**
* Reflects the state of each ruleset expanded elements.
* Each ruleset entry contains a list of subpanel that can be collapsed or expanded.
* Ruleset whole panel status is store the 'ruleset' entry.
* @example
* Expanded ruleset with rule overview collapsed:
* {'rulesetId': {'ruleset' : true, 'ruleOverview': false}}
* @note Collapsing a ruleset will not reset the subpanel expansion status
*/
expansionStatus: {
[key: string]: {
[subpanel: string]: boolean;
};
};
rulesetExecutions: RulesetExecutionDebug[];
executionDurationFormat: string;
/**
* Toggle a ruleset subpanel
* @param ruleId
* @param subpanel element to collapse. 'ruleset' will toggle the whole panel but won't reset the subpanels states.
*/
toggleExpansion(ruleId: string, subpanel: string): void;
static ɵfac: i0.ɵɵFactoryDeclaration<RulesetHistoryPresComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<RulesetHistoryPresComponent, "o3r-ruleset-history-pres", never, { "rulesetExecutions": { "alias": "rulesetExecutions"; "required": false; }; "executionDurationFormat": { "alias": "executionDurationFormat"; "required": false; }; }, {}, never, never, true, never>;
}
declare class RuleConditionPresComponent {
private _condition?;
/**
* Left hand operator as it will be displayed in the template.
* In the case of a fact with a json path, will resolve the whole fact path, else will only display the value
*/
lhs: string;
/**
* Right hand operator as it will be displayed in the template.
* In the case of a fact with a json path, will resolve the whole fact path, else will only display the value
*/
rhs: string | undefined;
/**
* Rule condition that will be flattened by the component setter
*/
set condition(condition: TopLevelCondition | undefined);
get condition(): TopLevelCondition | undefined;
private getOperandName;
static ɵfac: i0.ɵɵFactoryDeclaration<RuleConditionPresComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<RuleConditionPresComponent, "o3r-rule-condition-pres", never, { "condition": { "alias": "condition"; "required": false; }; }, {}, never, never, true, never>;
}
/**
* @deprecated The Components and Pipes are now standalone, this module will be removed in v14
*/
declare class RulesetHistoryPresModule {
static ɵfac: i0.ɵɵFactoryDeclaration<RulesetHistoryPresModule, never>;
static ɵmod: i0.ɵɵNgModuleDeclaration<RulesetHistoryPresModule, never, [typeof i1.JsonPipe, typeof RulesetHistoryPresComponent, typeof RuleConditionPresComponent], [typeof RulesetHistoryPresComponent]>;
static ɵinj: i0.ɵɵInjectorDeclaration<RulesetHistoryPresModule>;
}
declare class O3rFallbackToPipe implements PipeTransform {
transform<T>(value: T, fallback?: string): T | string;
static ɵfac: i0.ɵɵFactoryDeclaration<O3rFallbackToPipe, never>;
static ɵpipe: i0.ɵɵPipeDeclaration<O3rFallbackToPipe, "o3rFallbackTo", true>;
}
declare class O3rJsonOrStringPipe implements PipeTransform {
/**
* @inheritDoc
*/
transform(value: any): string;
static ɵfac: i0.ɵɵFactoryDeclaration<O3rJsonOrStringPipe, never>;
static ɵpipe: i0.ɵɵPipeDeclaration<O3rJsonOrStringPipe, "o3rJsonOrString", true>;
}
/**
* Compute the status of the execution depending on its execution event type, the output and whether the execution
* is still active
* @param rulesetExecution
* @param isActive
*/
declare const getStatus: (rulesetExecution: RulesetExecutionErrorEvent | RulesetExecutionEvent, isActive: boolean) => RulesetExecutionStatus;
/**
* Transform the output of the debug reports into the model for the ruleset history debug panel
* @param events
* @param rulesetMap
*/
declare const rulesetReportToHistory: (events: DebugEvent[], rulesetMap: Record<string, Ruleset>) => RulesetExecutionDebug[];
interface RulesEngineDevtoolsServiceOptions extends DevtoolsCommonOptions {
/** Size of events list emitted by rules engine; When undefined all history will be kept */
rulesEngineStackLimit?: number;
}
/** Rules Engine debug event Message Content */
interface RulesEngineDebugEventsContentMessage extends OtterMessageContent<'rulesEngineEvents'> {
/** Map of registered rulesets */
rulesetMap: Record<string, Ruleset>;
/** List of event from the Rules Engine Debugger */
events: DebugEvent[];
}
type RulesEngineMessageContents = RulesEngineDebugEventsContentMessage;
/** List of possible DataTypes for RulesEngine messages */
type RulesEngineMessageDataTypes = MessageDataTypes<RulesEngineMessageContents>;
/** List of all messages for configuration purpose */
type AvailableRulesEngineMessageContents = RulesEngineMessageContents | ConnectContentMessage | RequestMessagesContentMessage<RulesEngineMessageDataTypes>;
declare const isRulesEngineMessage: (message: any) => message is AvailableRulesEngineMessageContents;
declare class RulesEngineDevtoolsConsoleService implements DevtoolsServiceInterface {
/** Name of the Window property to access to the devtools */
static readonly windowModuleName = "rulesEngine";
private readonly rulesEngineDevtools;
private readonly options;
constructor();
/** @inheritDoc */
activate(): void;
/** Return the list of debug events emitted by rules engine */
getCurrentRulesEngineEventsStack(): Promise<void>;
/** Returns the list of active rulesets (name and id) at the moment when the function is called */
getActiveRulesets(): Promise<void>;
/** Returns the list of available rulesets (name and id) at the moment when the function is called */
getAvailableRulesets(): Promise<void>;
/** Returns the list of output actions emitted by the rules engine at the moment when the function is called */
getAllOutputActions(): Promise<void>;
/**
* Get the list of executions for the given ruleset
* @param rulesetId
*/
getRulesetExecutions(rulesetId: string): Promise<void>;
/**
* Check if the ruleset is activ in the moment when the function is called
* @param rulesetId
* @returns True if the ruleset is active; False if the ruleset is inactive or it does not exist
*/
isRulesetActive(rulesetId: string): Promise<void>;
/**
* Get the list of rules executed for the specified ruleset
* @param rulesetId
*/
getRulesEvaluationsForRuleset(rulesetId: string): Promise<void>;
/**
* Get the list of input facts (name, current value) for the specified ruleset, at the moment when the function is called
* @param rulesetId
*/
getInputFactsForRuleset(rulesetId: string): Promise<void>;
/**
* Get the list of triggers for the specified ruleset
* @param rulesetId
*/
getTriggersForRuleset(rulesetId: string): Promise<void>;
/**
* Get the list of outputed actions emitted by the given ruleset, at the moment when the function is called
* @param rulesetId
*/
getOutputActionsForRuleset(rulesetId: string): Promise<void>;
/** Get the list of fact names and corresponding values */
getAllFactsSnapshot(): Promise<void>;
/**
* Retrieve the ruleset information (rules, linkedComponents, validity range etc.) for a ruleset id
* @param rulesetId
*/
getRulesetInformation(rulesetId: string): Promise<void>;
static ɵfac: i0.ɵɵFactoryDeclaration<RulesEngineDevtoolsConsoleService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<RulesEngineDevtoolsConsoleService>;
}
declare class RulesEngineDevtoolsMessageService implements DevtoolsServiceInterface {
private readonly rulesEngineDevtools;
private readonly logger;
private readonly options;
private readonly forceEmitRulesEngineReport;
private readonly sendMessage;
private readonly destroyRef;
constructor();
/**
* Function to trigger a re-send a requested messages to the Otter Chrome DevTools extension
* @param only restricted list of messages to re-send
*/
private handleReEmitRequest;
/**
* Function to handle the incoming messages from Otter Chrome DevTools extension
* @param message
*/
private handleEvents;
private readonly serializeError;
/**
* Serialize exceptions in a way that will display the error message after a JSON.stringify(