/** * ConditionalRuleEngine - Core rule evaluation engine for conditional behaviors * * Evaluates declarative condition rules (from QueryBuilder or manual JSON) against * form state to determine field visibility, read-only state, disabled state, and * which validators should apply. * * @spec CONDITIONAL-VALIDATION.md * @requirement Tasks 3.1-3.12: ConditionalRuleEngine implementation * * Features: * - Simple rule evaluation (field operator value) * - Composite rules (AND/OR combinations with nesting) * - Conditional validators (apply validator only when condition met) * - Relationship validators (cross-field validation with safe expression eval) * - Behavioral flags (visibility, readOnly, disabled) * - Error handling with safe defaults * * Security: * - Uses expr-eval for safe expression evaluation (no eval()) * - Defaults to safe behavior on errors (visible, not disabled, not read-only) * * @example * ```typescript * const isVisible = ConditionalRuleEngine.isFieldVisible( * component.conditions, * { country: 'US', age: 25 } * ); * * const behaviors = ConditionalRuleEngine.applyConditionalBehaviors( * component.conditions, * formValues * ); * ``` */ import React from 'react'; import type { ConditionType, FormComponentConditions, ConditionalDataRule, ChoiceBasedFieldRule } from '../FormBuilder/types/FormSchema'; /** * Form field value type (aligned with FormValidator) */ export type FormValueType = string | number | boolean | Date | bigint | symbol | File | FileList | string[] | number[] | React.ReactNode | null | undefined | any; /** * ConditionalRuleEngine class * * @spec CONDITIONAL-VALIDATION.md - Core rule evaluation engine * @requirement Phase 1: Conditional visibility, readOnly, disabled behaviors */ export declare class ConditionalRuleEngine { /** * Evaluate a conditional rule against form values * * Handles both simple rules (field operator value) and composite rules (AND/OR). * Returns false for malformed rules. * * @spec CONDITIONAL-VALIDATION.md - evaluateCondition method * @requirement Task 3.2: Implement evaluateCondition with simple and composite handling * * @param rule - ConditionalRule or CompositeConditionalRule * @param formValues - Current form field values (key = field name, value = field value) * @returns true if condition met, false otherwise * * @example * ```typescript * const rule = { field: 'age', operator: 'greaterThan', value: 18 }; * const isAdult = ConditionalRuleEngine.evaluateCondition(rule, { age: 25 }); * // isAdult = true * ``` */ static evaluateCondition(rule: ConditionType, formValues: Record): boolean; /** * Evaluate simple field comparison rule * * Supports operators: equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, * lessThanOrEqual, in, notIn, contains, notContains. * * Handles both camelCase (greaterThan) and lowercase (greaterthan) operator formats * for compatibility with QueryBuilder output. * * @spec CONDITIONAL-VALIDATION.md - evaluateSimpleRule method * @requirement Task 3.3: Implement evaluateSimpleRule supporting all operators * * @param rule - Simple conditional rule with field, operator, value * @param formValues - Current form field values * @returns true if comparison is true, false otherwise * * @example * ```typescript * const rule = { field: 'email', operator: 'contains', value: '@' }; * const hasAt = evaluateSimpleRule(rule, { email: 'test@example.com' }); * // hasAt = true * ``` */ private static evaluateSimpleRule; /** * Evaluate composite rule with AND/OR logic * * Recursively evaluates nested rules with AND (all must be true) or OR * (at least one must be true) logic. * * @spec CONDITIONAL-VALIDATION.md - evaluateCompositeRule method * @requirement Task 3.4: Implement evaluateCompositeRule for AND/OR logic * * @param rule - Composite rule with condition ('and'|'or') and rules array * @param formValues - Current form field values * @returns true if composite condition met, false otherwise * * @example * ```typescript * const rule = { * condition: 'and', * rules: [ * { field: 'age', operator: 'greaterThan', value: 18 }, * { field: 'country', operator: 'equal', value: 'US' } * ] * }; * const isEligible = evaluateCompositeRule(rule, { age: 25, country: 'US' }); * // isEligible = true * ``` */ private static evaluateCompositeRule; /** * Check if field should be visible * * Evaluates visibleWhen condition. Defaults to true (visible) if no condition * is defined or on error. * * @spec CONDITIONAL-VALIDATION.md - isFieldVisible method * @requirement Task 3.8: Implement isFieldVisible (defaults to true if no condition) * * @param conditions - FormComponentConditions containing visibleWhen rule * @param formValues - Current form field values * @returns true if field should be visible, false if hidden * * @example * ```typescript * const conditions = { * visibleWhen: { field: 'showEmail', operator: 'equal', value: true } * }; * const visible = isFieldVisible(conditions, { showEmail: true }); * // visible = true * ``` */ static isFieldVisible(conditions: FormComponentConditions | undefined, formValues: Record): boolean; /** * Check if field should be read-only * * Evaluates readOnlyWhen condition. Defaults to false (editable) if no * condition is defined or on error. * * @spec CONDITIONAL-VALIDATION.md - isFieldReadOnly method * @requirement Task 3.9: Implement isFieldReadOnly (defaults to false if no condition) * * @param conditions - FormComponentConditions containing readOnlyWhen rule * @param formValues - Current form field values * @returns true if field should be read-only, false if editable * * @example * ```typescript * const conditions = { * readOnlyWhen: { field: 'isVerified', operator: 'equal', value: true } * }; * const readOnly = isFieldReadOnly(conditions, { isVerified: true }); * // readOnly = true * ``` */ static isFieldReadOnly(conditions: FormComponentConditions | undefined, formValues: Record): boolean; /** * Check if field should be disabled * * Evaluates disabledWhen condition. Defaults to false (enabled) if no * condition is defined or on error. * * @spec CONDITIONAL-VALIDATION.md - isFieldDisabled method * @requirement Task 3.10: Implement isFieldDisabled (defaults to false if no condition) * * @param conditions - FormComponentConditions containing disabledWhen rule * @param formValues - Current form field values * @returns true if field should be disabled, false if enabled * * @example * ```typescript * const conditions = { * disabledWhen: { field: 'orderStatus', operator: 'equal', value: 'completed' } * }; * const disabled = isFieldDisabled(conditions, { orderStatus: 'completed' }); * // disabled = true * ``` */ static isFieldDisabled(conditions: FormComponentConditions | undefined, formValues: Record): boolean; /** * Check if field should be hidden * * Evaluates hideWhen condition. Defaults to false (visible) if no condition * is defined or on error. * * @param conditions - FormComponentConditions containing hideWhen rule * @param formValues - Current form field values * @returns true if field should be hidden, false if visible * * @example * ```typescript * const conditions = { * hideWhen: { field: 'hideEmail', operator: 'equal', value: true } * }; * const hidden = isFieldHidden(conditions, { hideEmail: true }); * // hidden = true * ``` */ static isFieldHidden(conditions: FormComponentConditions | undefined, formValues: Record): boolean; /** * Check if field should be required * * Evaluates requiredWhen condition. Defaults to false (not required) if no condition * is defined or on error. * * @param conditions - FormComponentConditions containing requiredWhen rule * @param formValues - Current form field values * @returns true if field should be required, false if optional * * @example * ```typescript * const conditions = { * requiredWhen: { field: 'requireDetails', operator: 'equal', value: true } * }; * const required = isFieldRequired(conditions, { requireDetails: true }); * // required = true * ``` */ static isFieldRequired(conditions: FormComponentConditions | undefined, formValues: Record): boolean; /** * Get value to set for field if condition is met * * Evaluates setValueWhen condition and returns the value to assign if true. * Returns undefined if no condition is defined, condition not met, or on error. * * @param conditions - FormComponentConditions containing setValueWhen rule * @param formValues - Current form field values * @returns The value to set if condition met, undefined otherwise * * @example * ```typescript * const conditions = { * setValueWhen: { * condition: { field: 'country', operator: 'equal', value: 'US' }, * value: 'United States' * } * }; * const value = getConditionalValue(conditions, { country: 'US' }); * // value = 'United States' * ``` */ static getConditionalValue(conditions: FormComponentConditions | undefined, formValues: Record): any; /** * Evaluate conditional data availability * Returns true if any conditional data rule's condition is met * * @param conditionalDataRules - Array of ConditionalDataRule objects * @param formValues - Current form field values * @returns Index of first matching rule, or -1 if none match */ static evaluateConditionalDataRules(conditionalDataRules: ConditionalDataRule[] | undefined, formValues: Record): number; /** * Get filtered options for a dependent dropdown based on choice-based field rule * * If choiceBasedField rule exists and primary field has a value, * return only the mapped dependent options for that primary value. * Otherwise return all options. * * @param rule - ChoiceBasedFieldRule configuration * @param allDependentOptions - Complete list of dependent field options * @param formValues - Current form values * @param primaryFieldId - ID of primary field * @returns Filtered options array * * @example * ```typescript * const rule = { * primaryFieldId: 'dept-id', * choiceMapping: { * 'Marketing': ['Markers', 'Sticky Notes'], * 'Finance': ['Calculator'] * } * }; * * const filtered = ConditionalRuleEngine.getChoiceBasedOptions( * rule, * ['Markers', 'Sticky Notes', 'Calculator'], * { 'dept-id': 'Marketing' }, * 'dept-id' * ); * // Returns: ['Markers', 'Sticky Notes'] * ``` */ static getChoiceBasedOptions(rule: ChoiceBasedFieldRule, allDependentOptions: string[], formValues: Record, primaryFieldId: string): string[]; }