import { BlockDefinition, ComponentRegistryEntry, FieldBlockDefinition, ResolvableBoolean, ResolvableString } from "@ministryofjustice/hmpps-forge/core/components"; import { ZodType } from "zod"; import { EffectFunctionContext, EffectFunctionContext as EffectFunctionContext$1 } from "@ministryofjustice/hmpps-forge/core"; //#region forge-core/src/authoring/types/enums.d.ts /** * Discriminates the four kinds of registered function a call expression can * target: conditions test values, transformers reshape them, generators * produce them, and effects perform side effects in hooks. */ declare enum FunctionType { CONDITION = "FunctionType.Condition", TRANSFORMER = "FunctionType.Transformer", GENERATOR = "FunctionType.Generator", EFFECT = "FunctionType.Effect" } /** * Discriminates the structural nodes a form is built from: journeys contain * steps, steps contain blocks. */ declare enum StructureType { BLOCK = "StructureType.Block", JOURNEY = "StructureType.Journey", STEP = "StructureType.Step" } /** * Distinguishes field blocks, which collect answers, from basic blocks, * which only display content. */ declare enum BlockType { FIELD = "BlockType.field", BASIC = "BlockType.basic" } /** * Discriminates expression nodes: value expressions such as references, * pipelines, conditionals, and iterations, plus rule nodes such as * validations and tie-breakers. */ declare enum ExpressionType { REFERENCE = "ExpressionType.Reference", PIPELINE = "ExpressionType.Pipeline", NULLISH = "ExpressionType.Nullish", NEXT = "ExpressionType.Next", VALIDATION = "ExpressionType.Validation", ITERATE = "ExpressionType.Iterate", CONDITIONAL = "ExpressionType.Conditional", MATCH = "ExpressionType.Match", TIE_BREAKER = "ExpressionType.TieBreaker" } /** * Discriminates the per-item operations an iterate expression can apply to * a collection. */ declare enum IteratorType { MAP = "IteratorType.Map", FILTER = "IteratorType.Filter", FIND = "IteratorType.Find", SOME = "IteratorType.Some", EVERY = "IteratorType.Every", COUNT = "IteratorType.Count" } /** * Discriminates predicate nodes: a single condition test, or a logical * combination of other predicates. */ declare enum PredicateType { TEST = "PredicateType.Test", AND = "PredicateType.And", OR = "PredicateType.Or", XOR = "PredicateType.Xor", NOT = "PredicateType.Not" } /** * Discriminates the logical combinations of a subject-less condition * combinator tree, as used by match branches. Unlike PredicateType, whose * TEST leaves carry their own subject, these trees combine bare conditions * and take their subject from the surrounding match expression. */ declare enum ConditionCombinatorType { AND = "ConditionCombinatorType.And", OR = "ConditionCombinatorType.Or", XOR = "ConditionCombinatorType.Xor", NOT = "ConditionCombinatorType.Not" } /** * Discriminates lifecycle hooks: access hooks run on every request, submit * hooks run on form submission. */ declare enum HookType$1 { ACCESS = "HookType.Access", SUBMIT = "HookType.Submit" } /** * Discriminates the outcomes a hook can halt with: a redirect or a thrown * error. */ declare enum OutcomeType { REDIRECT = "Outcome.Redirect", THROW_ERROR = "Outcome.ThrowError" } //#endregion //#region forge-core/src/authoring/types/expressions.type.d.ts /** * Represents a reference to a value in the form context. * References are resolved at runtime to access data from various sources. * * @example * // Reference to a form field answer * { type: 'ExpressionType.Reference', path: ['answers', 'email'] } * * @example * // Reference to external data * { type: 'ExpressionType.Reference', path: ['data', 'user', 'role'] } * * @example * // Reference to current field (self) * { type: 'ExpressionType.Reference', path: ['@self'] } * * @example * // Reference to current collection item * { type: 'ExpressionType.Reference', path: ['@scope', '0', 'id'] } * * @example * // Reference to current loop metadata * { type: 'ExpressionType.Reference', path: ['@loop', '0', 'index0'] } */ interface ReferenceExpr extends ResolvableExpression { type: ExpressionType.REFERENCE; /** * Path segments to traverse to reach the target value. * Special paths include '@self' (current field), '@scope' (current iterator item), * and '@loop' (current iterator metadata). */ path: string[]; /** * Optional base expression to evaluate first. * When present, the reference evaluates the base expression and then * navigates into the result using the path segments. * * @example * // Navigate into the result of an iteration * { * type: 'ExpressionType.Reference', * base: { type: 'ExpressionType.Iterate', ... }, * path: ['goals'] * } */ base?: ResolvableValue; } /** * Represents a pipeline of sequential transformations. * The output of each step becomes the input to the next step, * allowing for complex data transformations through composition. * * @example * // Chain multiple transformations * { * type: 'ExpressionType.Pipeline', * input: { type: 'ExpressionType.Reference', path: ['answers', 'email'] }, * steps: [ * { type: 'FunctionType.Transformer', name: 'trim', arguments: [] }, * { type: 'FunctionType.Transformer', name: 'toLowerCase', arguments: [] }, * { type: 'FunctionType.Transformer', name: 'validateEmail', arguments: [] } * ] * } * * @example * // Transform with arguments * { * type: 'ExpressionType.Pipeline', * input: { type: 'ExpressionType.Reference', path: ['answers', 'price'] }, * steps: [ * { type: 'FunctionType.Transformer', name: 'multiply', arguments: [1.2] }, * { type: 'FunctionType.Transformer', name: 'round', arguments: [2] }, * { type: 'FunctionType.Transformer', name: 'formatCurrency', arguments: ['GBP'] } * ] * } */ interface PipelineExpr extends ResolvableExpression { type: ExpressionType.PIPELINE; /** * Initial value expression to be transformed. * This value is passed as input to the first step. */ input: ResolvableValue; /** * Ordered array of transformation steps. * Each step receives the output of the previous step as its input. */ steps: TransformerFunctionExpr[]; } /** * Base interface for all function call expressions with typed arguments. * This serves as the foundation for specific function types like conditions and transformers. */ interface BaseFunctionExpr { type: FunctionType; /** * Name of the registered function. * Must match a function in the appropriate registry. Built-in functions * register under PascalCase names, namespaced where grouped (e.g. * `'IsRequired'`, `'Date.Now'`, `'Array.Slice'`); custom functions use * whatever name they were registered with. */ name: string; /** Arguments to pass to the function. */ arguments: A; } /** * Represents a condition function call expression. * Condition functions evaluate to boolean values for validation and logic predicates. * * @example * // Required validation condition * { * type: 'FunctionType.Condition', * name: 'IsRequired', * arguments: [] * } * * @example * // Length validation with parameter * { * type: 'FunctionType.Condition', * name: 'hasMaxLength', * arguments: [100] * } * * @example * // Range validation with multiple parameters * { * type: 'FunctionType.Condition', * name: 'isBetween', * arguments: [10, 100] * } */ interface ConditionFunctionExpr extends BaseFunctionExpr { type: FunctionType.CONDITION; } /** * Generic function expression that can represent any function type. * Used when the specific function type is not known at compile time. */ type FunctionExpr = BaseFunctionExpr; /** * Represents a transformer function call expression. * Transformer functions modify values for formatting, extraction, or type conversion. * * @example * // Transform to uppercase * { * type: 'FunctionType.Transformer', * name: 'toUpperCase', * arguments: [] * } * * @example * // Extract regex capture group * { * type: 'FunctionType.Transformer', * name: 'regexCapture', * arguments: ['^item-(.+)$', 1] * } */ interface TransformerFunctionExpr extends BaseFunctionExpr, ResolvableExpression { type: FunctionType.TRANSFORMER; } /** * Represents a side effect to be executed during lifecycle hooks. * Effects handle actions like saving data, manipulating collections, * or triggering external operations. * * @example * // Save effect * { * type: 'FunctionType.Effect', * name: 'save', * arguments: [{ draft: true }] * } * * @example * // Add to collection effect * { * type: 'FunctionType.Effect', * name: 'addToCollection', * arguments: [ * { type: 'ExpressionType.Reference', path: ['answers', 'addresses'] }, * { street: '', city: '', postcode: '' } * ] * } */ interface EffectFunctionExpr extends BaseFunctionExpr { type: FunctionType.EFFECT; } /** * Represents a generator function call expression. * Generator functions produce values without requiring input. * Unlike conditions and transformers, generators do not receive a value to process. * * @example * // Generate current date * { * type: 'FunctionType.Generator', * name: 'Date.Now', * arguments: [] * } * * @example * // Generate UUID with prefix * { * type: 'FunctionType.Generator', * name: 'UUID', * arguments: ['prefix-'] * } */ interface GeneratorFunctionExpr extends BaseFunctionExpr, ResolvableExpression { type: FunctionType.GENERATOR; } /** * Configuration for Iterator.Map - transforms each item to a new shape. * * @example * Iterator.Map({ label: Item().path('name'), value: Item().path('id') }) */ interface MapIteratorConfig { type: IteratorType.MAP; /** * Template with Item() references - evaluated per item to produce output. * The template is instantiated for each item with Item() references resolved. */ yield: unknown; } /** * Configuration for Iterator.Filter - keeps items matching a predicate. * * @example * Iterator.Filter(Item().path('active').match(Condition.Equals(true))) */ interface FilterIteratorConfig { type: IteratorType.FILTER; /** * Predicate evaluated per item - items where predicate is true are kept. * Uses Item() references to access item properties. */ predicate: PredicateExpr; } /** * Configuration for Iterator.Find - returns first item matching a predicate. * * @example * Iterator.Find(Item().path('id').match(Condition.Equals(Params('userId')))) */ interface FindIteratorConfig { type: IteratorType.FIND; /** * Predicate evaluated per item - returns first item where predicate is true. * Returns undefined if no match found. */ predicate: PredicateExpr; } /** Stops at the first matching item. */ interface SomeIteratorConfig { type: IteratorType.SOME; predicate: PredicateExpr; } /** Stops at the first item that does not match. */ interface EveryIteratorConfig { type: IteratorType.EVERY; predicate: PredicateExpr; } /** Counts items matching the predicate. */ interface CountIteratorConfig { type: IteratorType.COUNT; predicate: PredicateExpr; } /** * Union of all iterator configuration types. */ type IteratorConfig = MapIteratorConfig | FilterIteratorConfig | FindIteratorConfig | SomeIteratorConfig | EveryIteratorConfig | CountIteratorConfig; /** Resolves the fallback only when the primary value is null or undefined. */ interface NullishExpr extends ResolvableExpression { type: ExpressionType.NULLISH; input: ResolvableValue; fallback?: ResolvableValue; } /** * Represents an iterate expression that applies an iterator to a source collection. * Created by the .each() method on reference/expression builders. * * @example * // Filter and map in sequence * Data('items') * .each(Iterator.Filter(Item().path('active').match(Condition.Equals(true)))) * .each(Iterator.Map({ label: Item().path('name'), value: Item().path('id') })) * * @example * // Transform with pipeline on result * Data('items') * .each(Iterator.Map(Item().path('name'))) * .pipe(Transformer.Array.Slice(0, 10)) */ interface IterateExpr extends ResolvableExpression { type: ExpressionType.ITERATE; /** * The input source expression (array or prior iterate result). * Can be a reference, pipeline, or another iterate expression for chaining. */ input: ResolvableValue; /** * The iterator configuration (Map, Filter, etc.) to apply per item. */ iterator: IteratorConfig; } /** * The type-level marker shared by every authoring expression that resolves to * a value at runtime - references, pipelines, iterations, and * generator/transformer chains. An interface rather than a union so IDE * hovers show one name; the optional-only member makes it a weak type, so * only types declaring the marker are assignable. Never set at runtime. * * `T` is the value the expression resolves to. It defaults to `any` because * references are untyped at authoring time - the extending expression types * inherit that default and stay assignable to every `ResolvableExpression`. * A builder that knows its resolved type can narrow it and be checked for real. */ interface ResolvableExpression { readonly __resolves?: T; } /** * Widens a declared argument type so a caller can pass either a literal of * that type or any authoring expression that resolves to one at runtime. */ type Resolvable = T | ResolvableExpression; /** * Represents any expression that evaluates to a value. * This is the base type for all expressions in the form system. */ type ResolvableValue = ReferenceExpr | TransformerFunctionExpr | GeneratorFunctionExpr | PipelineExpr | IterateExpr | NullishExpr | ResolvableValue[] | string | number | boolean | null | Record; /** * Represents a test predicate that evaluates a condition against a subject. * * @example * // Test if field is required (not empty) * { * type: 'PredicateType.Test', * subject: { type: 'ExpressionType.Reference', path: ['@self'] }, * negate: false, * condition: { type: 'FunctionType.Condition', name: 'IsRequired', arguments: [] } * } * * @example * // Test if email is NOT valid (negated) * { * type: 'PredicateType.Test', * subject: { type: 'ExpressionType.Reference', path: ['answers', 'email'] }, * negate: true, * condition: { type: 'FunctionType.Condition', name: 'Email.IsValidEmail', arguments: [] } * } */ interface PredicateTestExpr { type: PredicateType.TEST; /** The value expression to test. */ subject: ResolvableValue; /** * Whether to negate the condition result. * If true, the predicate passes when the condition returns false. */ negate: boolean; /** The registered condition function to evaluate against the subject. */ condition: ConditionFunctionExpr; } /** * Represents an AND logical predicate where all operands must be true. * * @example * // AND logic - all must be true * { * type: 'PredicateType.And', * operands: [ * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} }, * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} } * ] * } */ interface PredicateAndExpr { type: PredicateType.AND; /** * Array of predicates that must all be true. * Requires at least 2 operands for logical AND. */ operands: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]; } /** * Represents an OR logical predicate where at least one operand must be true. * * @example * // OR logic - at least one must be true * { * type: 'PredicateType.Or', * operands: [ * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} }, * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} } * ] * } */ interface PredicateOrExpr { type: PredicateType.OR; /** * Array of predicates where at least one must be true. * Requires at least 2 operands for logical OR. */ operands: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]; } /** * Represents an XOR logical predicate where exactly one operand must be true. * * @example * // XOR logic - exactly one must be true * { * type: 'PredicateType.Xor', * operands: [ * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} }, * { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} } * ] * } */ interface PredicateXorExpr { type: PredicateType.XOR; /** * Array of predicates where exactly one must be true. * Requires at least 2 operands for logical XOR. */ operands: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]; } /** * Represents a NOT logical predicate that inverts the operand's result. * * @example * // NOT logic - invert the result * { * type: 'PredicateType.Not', * operand: { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} } * } */ interface PredicateNotExpr { type: PredicateType.NOT; /** * Single predicate to negate. * NOT requires exactly one operand. */ operand: PredicateExpr; } /** Boolean collection iterators can be used directly as guards and logical operands. */ interface CollectionPredicateExpr extends IterateExpr { iterator: SomeIteratorConfig | EveryIteratorConfig; } /** * Represents any predicate expression that evaluates to true or false. * Used for validation rules, conditional logic, and guards. */ type PredicateExpr = CollectionPredicateExpr | PredicateTestExpr | PredicateAndExpr | PredicateOrExpr | PredicateXorExpr | PredicateNotExpr; /** * Represents a conditional expression that evaluates to different values based on a predicate. * Follows the if-then-else pattern * * @example * // Simple validation rule * { * type: 'ExpressionType.Conditional', * predicate: { * type: 'PredicateType.Test', * subject: { type: 'ExpressionType.Reference', path: ['@self'] }, * negate: true, * condition: { type: 'FunctionType.Condition', name: 'IsRequired', arguments: [] } * }, * thenValue: 'This field is required', * elseValue: false * } * * @example * // Conditional field visibility (dependentWhen) * { * type: 'ExpressionType.Conditional', * predicate: { * type: 'PredicateType.Test', * subject: { type: 'ExpressionType.Reference', path: ['answers', 'hasChildren'] }, * negate: false, * condition: { type: 'FunctionType.Condition', name: 'Equals', arguments: [true] } * }, * thenValue: true, * elseValue: false * } * * @example * // Nested conditionals for complex logic * { * type: 'ExpressionType.Conditional', * predicate: { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} }, * thenValue: { * type: 'ExpressionType.Conditional', * predicate: { type: 'PredicateType.Test', subject: {...}, negate: false, condition: {...} }, * thenValue: 'Option A', * elseValue: 'Option B' * }, * elseValue: 'Option C' * } */ interface ConditionalExpr { type: ExpressionType.CONDITIONAL; /** The condition to evaluate. */ predicate: PredicateExpr; /** * The value to return when the predicate evaluates to true. * If omitted, defaults to true. */ thenValue?: ResolvableValue; /** * The value to return when the predicate evaluates to false. * If omitted, defaults to false. */ elseValue?: ResolvableValue; } /** * Represents an AND condition combinator where all operands must be true. * Operands are bare conditions or nested combinators; the match subject is * applied to every condition leaf. * * @example * // AND logic - all must be true * { * type: 'ConditionCombinatorType.And', * operands: [ * { type: 'FunctionType.Condition', name: 'IsRequired', arguments: [] }, * { type: 'FunctionType.Condition', name: 'Number.IsGreaterThan', arguments: [18] } * ] * } */ interface ConditionAndExpr { type: ConditionCombinatorType.AND; /** * Array of condition branches that must all be true. * Requires at least 2 operands for logical AND. */ operands: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]; } /** * Represents an OR condition combinator where at least one operand must be true. * Operands are bare conditions or nested combinators; the match subject is * applied to every condition leaf. * * @example * // OR logic - at least one must be true * { * type: 'ConditionCombinatorType.Or', * operands: [ * { type: 'FunctionType.Condition', name: 'Equals', arguments: ['ACTIVE'] }, * { type: 'FunctionType.Condition', name: 'Equals', arguments: ['PENDING'] } * ] * } */ interface ConditionOrExpr { type: ConditionCombinatorType.OR; /** * Array of condition branches where at least one must be true. * Requires at least 2 operands for logical OR. */ operands: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]; } /** * Represents an XOR condition combinator where exactly one operand must be true. * Operands are bare conditions or nested combinators; the match subject is * applied to every condition leaf. * * @example * // XOR logic - exactly one must be true * { * type: 'ConditionCombinatorType.Xor', * operands: [ * { type: 'FunctionType.Condition', name: 'Equals', arguments: ['ACTIVE'] }, * { type: 'FunctionType.Condition', name: 'String.IsEmpty', arguments: [] } * ] * } */ interface ConditionXorExpr { type: ConditionCombinatorType.XOR; /** * Array of condition branches where exactly one must be true. * Requires at least 2 operands for logical XOR. */ operands: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]; } /** * Represents a NOT condition combinator that inverts the operand's result. * The operand is a bare condition or a nested combinator; the match subject * is applied to every condition leaf. * * @example * // NOT logic - invert the result * { * type: 'ConditionCombinatorType.Not', * operand: { type: 'FunctionType.Condition', name: 'Equals', arguments: ['ACTIVE'] } * } */ interface ConditionNotExpr { type: ConditionCombinatorType.NOT; /** * Single condition branch to negate. * NOT requires exactly one operand. */ operand: ConditionBranchExpr; } /** * Represents any subject-less combination of conditions. * Unlike PredicateExpr, combinators carry no subject of their own; the * surrounding match expression supplies it to every condition leaf. */ type ConditionCombinatorExpr = ConditionAndExpr | ConditionOrExpr | ConditionXorExpr | ConditionNotExpr; /** * Represents anything a match branch can test its subject against: * a single condition, or a combinator tree over conditions. */ type ConditionBranchExpr = ConditionFunctionExpr | ConditionCombinatorExpr; /** An ordered condition branch or native strict-equality case. */ type MatchBranch = MatchConditionBranch | { expected: ResolvableValue; value: ResolvableValue; }; /** * Represents a single branch in a match expression. * Each branch pairs a condition with a value to return when the condition matches. * The condition may be a single condition function or a combinator tree of them; * the match subject is applied to every condition leaf in that tree. */ interface MatchConditionBranch { /** The condition, or combinator tree of conditions, to evaluate against the match subject. */ condition: ConditionBranchExpr; /** The value to return when this branch's condition matches. */ value: ResolvableValue; } /** * Represents a match expression that evaluates a subject against multiple branches. * Returns the value of the first branch whose condition matches, or the otherwise value. * * @example * // Match on status * { * type: 'ExpressionType.Match', * subject: { type: 'ExpressionType.Reference', path: ['data', 'status'] }, * branches: [ * { condition: { type: 'FunctionType.Condition', name: 'Equals', arguments: ['ACTIVE'] }, value: 'Active' }, * { condition: { type: 'FunctionType.Condition', name: 'Equals', arguments: ['CLOSED'] }, value: 'Closed' }, * ], * otherwise: 'Unknown' * } */ interface MatchExpr { type: ExpressionType.MATCH; /** The value to test each branch's condition against. */ subject: ResolvableValue; /** Ordered array of branches. The first matching branch's value is returned. */ branches: MatchBranch[]; /** * The value to return when no branch matches. * If omitted, defaults to undefined. */ otherwise?: ResolvableValue; } /** * Represents a redirect outcome in a hook. * When matched, halts hook processing and redirects to the specified path. * * @example * // Unconditional redirect * redirect({ goto: '/overview' }) * * @example * // Conditional redirect * redirect({ * when: Data('needsSetup').match(Condition.Equals(true)), * goto: '/setup', * }) */ interface RedirectOutcome { type: OutcomeType.REDIRECT; /** Optional condition that must be true for this redirect to occur. */ when?: PredicateExpr; /** The path to redirect to. */ goto: string | ResolvableValue; } /** * Represents an error outcome in a hook. * When matched, halts hook processing and returns an error outcome. * * @example * // Not found error * throwError({ * when: Data('notFound').match(Condition.Equals(true)), * status: 404, * message: 'Item not found', * }) * * @example * // Dynamic error message * throwError({ * when: Data('saveError').match(Condition.IsRequired()), * status: 500, * message: Format('Failed to save: %1', Data('saveError')), * }) */ interface ThrowErrorOutcome { type: OutcomeType.THROW_ERROR; /** Optional condition that must be true for this error to be thrown. */ when?: PredicateExpr; /** HTTP status code to return. */ status: number; /** Error message to return. */ message: string | ResolvableValue; } /** * Union type for all hook outcomes. * Used in the `next` array of access and submit hooks. */ type HookOutcome = RedirectOutcome | ThrowErrorOutcome; /** * Lifecycle hook for access control and data loading. * * Access hooks are evaluated in sequence. Each hook: * 1. Evaluates `when` condition (if present) * 2. If `when` is false → skip to next hook * 3. If `when` is true (or absent) → execute effects * 4. Evaluate `next` outcomes - first match halts (redirect or error) * 5. If no outcome matches → CONTINUE to next hook * * @example * // Effects-only hook (always executes, continues) * access({ effects: [loadUserData()] }) * * @example * // Conditional redirect * access({ * when: Data('user').not.match(Condition.IsRequired()), * next: [redirect({ goto: '/login' })], * }) * * @example * // Error response * access({ * effects: [checkPermissions()], * next: [ * throwError({ * when: Data('notFound').match(Condition.Equals(true)), * status: 404, * message: 'Item not found', * }), * redirect({ goto: '/overview' }), * ], * }) */ interface AccessHook { type: HookType$1.ACCESS; /** Condition for this hook to execute. If omitted, always executes. */ when?: PredicateExpr; /** Effects to execute when hook runs (data loading, analytics, etc.) */ effects?: EffectFunctionExpr[]; /** Outcomes to evaluate - first match halts (redirect or throws error) */ next?: HookOutcome[]; } /** * Submission hook for handling form submissions. * Controls validation, effects, and navigation when users submit forms. * * @example * // Simple save and redirect * submit({ * validate: true, * onValid: { * effects: [saveData()], * next: [redirect({ goto: '/confirmation' })], * }, * }) * * @example * // Error handling on save failure * submit({ * validate: true, * onValid: { * effects: [saveGoal()], * next: [ * throwError({ * when: Data('saveError').match(Condition.IsRequired()), * status: 500, * message: Format('Failed to save: %1', Data('saveError')), * }), * redirect({ goto: '/goals/overview' }), * ], * }, * }) */ interface SubmitHook { type: HookType$1.SUBMIT; /** * Optional trigger condition for this hook. * If omitted, the hook triggers on any form submission. */ when?: PredicateExpr; /** * Optional guard conditions that must be met for the hook to proceed. * Guards act as a security layer, preventing hooks in certain states. */ guards?: PredicateExpr; /** * Whether to validate form fields before proceeding. * When true, validates the default validation group; when passed a group * list, validates those groups instead. * When false (default), no fresh validation runs — branches route on the * step's already-recorded validity. */ validate?: boolean | { groups: string[]; }; /** * Actions to execute regardless of validation result, before any routing * to onValid or onInvalid. */ onAlways?: { /** Effects to execute */ effects?: EffectFunctionExpr[]; /** Outcomes to evaluate - first match halts (redirect or throws error) */ next?: HookOutcome[]; }; /** * Actions to execute when the step's recorded validation state is valid. * With validate false this can still run, since a step with no recorded * failures reads as valid. */ onValid?: { /** Effects to execute */ effects?: EffectFunctionExpr[]; /** Outcomes to evaluate - first match halts (redirect or throws error) */ next?: HookOutcome[]; }; /** * Actions to execute when the step's recorded validation state has * failures, whether recorded by this hook's validation or earlier in the * same request. */ onInvalid?: { /** Effects to execute */ effects?: EffectFunctionExpr[]; /** Outcomes to evaluate - first match halts (redirect or throws error) */ next?: HookOutcome[]; }; } //#endregion //#region forge-core/src/authoring/builders/types.d.ts /** * A value that can be returned from a conditional or match branch. * Can be a literal string or a value expression. */ type BranchValue = string | ResolvableValue; /** * Public interface for a negated chain position, reached via `.not`. * Negation only applies to a condition test, so the only continuations * are `.match()` and a further `.not` to toggle the negation back. */ interface ChainableNegation { /** * Test the value against a condition, negated. */ match(condition: ConditionFunctionExpr): PredicateTestExpr; /** * Toggle the negation back off. */ readonly not: ChainableNegation; } /** * Public interface for chainable iterable expressions. * Created by .each(Iterator.Map/Filter) on references or expressions. */ interface ChainableIterable extends ResolvableExpression { /** * Chain a Find iterator. * Returns a ChainableExpr since Find returns a single item, not an array. */ each(iterator: FindIteratorConfig): ChainableExpr; /** Test the collection directly as a predicate. */ each(iterator: SomeIteratorConfig | EveryIteratorConfig): CollectionPredicateExpr; /** Count matching items and continue with the resulting number. */ each(iterator: CountIteratorConfig): ChainableExpr; /** * Chain a Map or Filter iterator. */ each(iterator: MapIteratorConfig | FilterIteratorConfig): ChainableIterable; /** * Navigate into a property of the iteration result. * Useful after Iterator.Find() to extract a specific property from the found item. */ path(key: string): ChainableExpr; /** * Transform the output array through a pipeline. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** * Test the output array against a condition. */ match(condition: ConditionFunctionExpr): PredicateTestExpr; /** * Negate the next condition test. */ readonly not: ChainableNegation; } /** * Public interface for chainable value expressions. * Only exposes the fluent API methods - internal methods like build() are hidden. */ interface ChainableExpr extends ResolvableExpression { /** * Navigate into a property of the expression result. * Creates a reference with this expression as its base. */ path(key: string): ChainableExpr; /** * Transform the value through a pipeline of transformers. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** * Enter per-item iteration mode with a Find iterator. * Returns a ChainableExpr since Find returns a single item, not an array. */ each(iterator: FindIteratorConfig): ChainableExpr; /** Test the collection directly as a predicate. */ each(iterator: SomeIteratorConfig | EveryIteratorConfig): CollectionPredicateExpr; /** Count matching items and continue with the resulting number. */ each(iterator: CountIteratorConfig): ChainableExpr; /** * Enter per-item iteration mode with a Map or Filter iterator. */ each(iterator: MapIteratorConfig | FilterIteratorConfig): ChainableIterable; /** * Test the value against a condition. */ match(condition: ConditionFunctionExpr): PredicateTestExpr; /** * Negate the next condition test. */ readonly not: ChainableNegation; } /** * Public interface for chainable reference expressions. * Extends ChainableExpr with path navigation. */ interface ChainableRef extends ResolvableExpression { /** * Navigate to a nested property. * Supports dot notation: .path('user.address.city') */ path(key: string): ChainableRef; /** * Transform the value through a pipeline of transformers. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** * Enter per-item iteration mode with a Find iterator. * Returns a ChainableExpr since Find returns a single item. */ each(iterator: FindIteratorConfig): ChainableExpr; /** Test the collection directly as a predicate. */ each(iterator: SomeIteratorConfig | EveryIteratorConfig): CollectionPredicateExpr; /** Count matching items and continue with the resulting number. */ each(iterator: CountIteratorConfig): ChainableExpr; /** * Enter per-item iteration mode with a Map or Filter iterator. */ each(iterator: MapIteratorConfig | FilterIteratorConfig): ChainableIterable; /** * Test the value against a condition. */ match(condition: ConditionFunctionExpr): PredicateTestExpr; /** * Negate the next condition test. */ readonly not: ChainableNegation; } /** * Public interface for conditional expressions, returned by when() and Conditional(). * The chain continues with .then() and .else(); the finished conditional is * assignable anywhere a Resolvable* value is accepted. */ interface ChainableConditional { /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** Transforms the selected branch value without evaluating other branches. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** * Sets the value to return when the predicate evaluates to true. */ then(value: BranchValue): ChainableConditional; /** * Sets the value to return when the predicate evaluates to false. */ else(value: BranchValue): ChainableConditional; } /** * Public interface for match expressions, returned by match(). * The chain continues with .branch() and .otherwise(); the finished match is * assignable anywhere a Resolvable* value is accepted. */ interface ChainableMatch { /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** Transforms the selected branch value without evaluating other branches. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** Adds an ordered case using native JavaScript strict equality. */ case(expected: ResolvableValue, value: BranchValue): ChainableMatch; /** * Adds a branch: when the condition matches the subject, the value is returned. */ branch(condition: ConditionBranchExpr, value: BranchValue): ChainableMatch; /** * Sets the fallback value when no branch matches. */ otherwise(value: BranchValue): ChainableMatch; } /** * Public interface for generator expressions, returned by registered * generator functions (e.g. Generator.Date.Now()). */ interface ChainableGenerator extends ResolvableExpression { /** * Transform the generated value through a pipeline of transformers. */ pipe(...steps: TransformerFunctionExpr[]): ChainableExpr; /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** * Test the generated value against a condition. */ match(condition: ConditionFunctionExpr): PredicateTestExpr; /** * Negate the next condition test. */ readonly not: ChainableNegation; } /** * Public interface for scoped reference builders (Item()). */ interface ChainableScopedRef extends ResolvableExpression { /** Uses the fallback only when the value is null or undefined. */ nullish(fallback: ResolvableValue | undefined): ChainableExpr; /** * Navigate to the parent scope in nested collections. */ readonly parent: ChainableScopedRef; /** * Get a sub-property of the collection item. * Supports dot notation: .path('user.address.city') */ path(key: string): ChainableRef; /** * Get the full value of the collection item. */ value(): ChainableRef; /** * Get the key when iterating over an object. * Only available when iterating over object entries (not arrays). */ key(): ChainableRef; } /** * Public interface for loop metadata references (Loop). */ interface ChainableLoopRef extends ResolvableExpression { /** * Navigate to the parent loop in nested collections. */ readonly Parent: ChainableLoopRef; /** * Get the current iteration position, 1-based. */ Index(): ChainableRef; /** * Get the current iteration index, 0-based. */ Index0(): ChainableRef; /** * Get the reverse iteration position, 1-based. */ RevIndex(): ChainableRef; /** * Get the reverse iteration index, 0-based. */ RevIndex0(): ChainableRef; /** * Check whether this is the first iteration. */ First(): ChainableRef; /** * Check whether this is the last iteration. */ Last(): ChainableRef; /** * Get the total number of items in the iteration. */ Length(): ChainableRef; } //#endregion //#region forge-core/src/authoring/builders/references.d.ts /** * References POST body data from form submission. */ declare function Post(key: string): ChainableRef; /** * References URL parameters (e.g., /users/:id). */ declare function Params(key: string): ChainableRef; /** * References query string parameters (e.g., ?search=test). */ declare function Query(key: string): ChainableRef; /** * References request metadata from the current request context. */ declare const Request: { Url(): ChainableRef; Path(): ChainableRef; Method(): ChainableRef; Headers(name: string): ChainableRef; Cookies(name: string): ChainableRef; State(key: string): ChainableRef; }; /** * References data defined for the step. */ declare function Data(key: string): ChainableRef; /** * References server-side session data from the current request context. */ declare function Session(key: string): ChainableRef; /** * References an answer using its target field or a string code. * * @example * Answer('email') // Reference by code string * Answer(emailField) // Reference by field definition * Answer('user.address.postcode') // Nested path */ declare function Answer(target: FieldBlockDefinition | ResolvableString): ChainableRef; /** * References the current collection item when inside a collection scope. * * @example * Item().path('name') // Access item.name * Item().value() // Access the whole item * Item().parent.path('groupId') // Access parent item's property */ declare function Item(): ChainableScopedRef; /** * References metadata for the current collection loop. * * @example * Loop.Index() // 1-based iteration position * Loop.Index0() // 0-based iteration index * Loop.Parent.Index() // Parent loop position in nested iterations */ declare const Loop: ChainableLoopRef; /** * References the block/field it's in scope of. * * @example * Self().match(Condition.IsRequired()) * Self().not.match(Condition.String.IsEmpty()) * Self().pipe(Transformer.String.Trim).match(Condition.IsRequired()) */ declare function Self(): ChainableRef; //#endregion //#region forge-core/src/authoring/types/structures.type.d.ts /** * View configuration for journeys and steps. * Forge combines journey configurations from root to leaf, then applies the * current step configuration before passing the effective view to the renderer. */ interface ViewConfig { /** Template identifier. The nearest journey or current step declaration wins. */ template?: string; /** Template locals merged by key from the root journey to the current step. */ locals?: Record; } /** * Represents a validation rule for a form field. * Includes the validation logic, error message, and execution context. */ interface ValidationExpr { type: ExpressionType.VALIDATION; /** A predicate that must be `true` for the field to be considered valid. */ condition: PredicateExpr; /** The error message shown when the condition fails. Can be a plain string, a reference expression, or a format expression. */ message: ResolvableString; /** When `true`, the rule only runs on form submission, not during navigation/traversal checks. Useful for expensive or time-sensitive validations. */ submissionOnly?: boolean; /** Validation groups this rule belongs to. Defaults to `['default']` when omitted or empty. */ groups?: string[]; /** Metadata passed to the error handler, e.g. `{ field: 'month' }` to highlight a specific part of a composite input like a date. */ details?: Record; } type ValidationProps = Omit; type ValidWhenInput = ValidationExpr | IterateExpr | ChainableIterable; /** * A prioritised rule that participates in tie-breaking during reachability, * backlink, and resume resolution. The first entry whose `when` evaluates * truthy (or which has no `when`) supplies the step's priority; the highest * priority among competing candidates wins, with journey declaration order * as the final tiebreaker. */ interface TieBreaker { type: ExpressionType.TIE_BREAKER; /** Priority value — higher beats lower. */ priority: number; /** Predicate that must hold for this priority to apply. Omit for a catch-all. */ when?: PredicateExpr; } type TieBreakerProps = Omit; /** * Where Forge redirects a request for an unreachable step: the journey's * default active entry point, or the current resume frontier. * * @see {@link JourneyReachability.unreachableRedirect} */ type UnreachableRedirectTarget = 'entry' | 'frontier'; /** * Custom key/value pairs attached to a journey or step, surfaced on the * route tree and render context. Values may be expressions, resolved per * request. * * @see {@link JourneyDefinition.metadata} * @see {@link StepDefinition.metadata} */ type RouteMetadata = Record; /** * Top-level journey definition representing a complete form flow. * Journeys contain steps and can have nested child journeys. */ interface JourneyDefinition { type: StructureType.JOURNEY; /** * URL segment this journey mounts under. * Nested journeys append their path to their parent's; the root journey * mounts under the base path the Forge instance was created with. * * @example * path: '/goals' * * @example * // Route parameters are declared with a colon * path: '/goals/:goalId' */ path: string; /** * Stable identifier for the journey, independent of its URL path. * The root journey's code identifies the whole registered package: it * scopes the engine's route keys and appears in compilation traces and * diagnostics, so it must be unique across registered packages. * * @example * code: 'prison-visit-booking' */ code: string; /** * Lifecycle hooks run on every request to this journey or any step or * child journey beneath it, before the step's own hooks. Use them for * access control and data loading. * * @example * onAccess: [access({ effects: [loadUserData()] })] * * @see {@link AccessHook} for hook evaluation order and outcomes */ onAccess?: AccessHook[]; /** * Steps belonging directly to this journey, routed under its path. * * @see {@link StepDefinition} */ steps?: StepDefinition[]; /** * Child journeys nested under this one, routed beneath this journey's * path. */ children?: JourneyDefinition[]; /** * Display title for the journey, surfaced on the route tree and as a * journey ancestor in the render context. The title may be an expression, * resolved per request. * * @example * title: 'Book a prison visit' * * @example * // Titles may be expressions * title: Format('Visit for %1', Data('prisonerName')) */ title: ResolvableString; /** * Optional display description, surfaced alongside {@link title} on the * route tree. The description may be an expression, resolved per request. */ description?: ResolvableString; /** * View configuration for rendering this journey's steps. Combined from * the root journey down to the current step: the nearest `template` wins * and `locals` merge by key. * * @see {@link ViewConfig} */ view?: ViewConfig; /** * Custom key/value pairs surfaced on the route tree and render context, * for concerns like navigation labels or template flags. * Values may be expressions, resolved per request. * * @example * metadata: { section: 'sentencing', navLabel: 'Goals' } * * @example * // Values may be expressions * metadata: { navLabel: Data('journeyTitle') } */ metadata?: RouteMetadata; /** * Static data merged into the request's data context, readable with * `Data()` references. Merges root-first, so a step's or child journey's * keys override this journey's. Plain values only; expressions are * rejected at registration. * * @example * data: { supportEmail: 'help@justice.gov.uk' } * // Read elsewhere with Data('supportEmail') */ data?: Record; /** * Controls resume behaviour and how unreachable-step requests are * redirected for this journey. * * @see {@link JourneyReachability} */ reachability?: JourneyReachability; } /** * Journey-level reachability configuration. Controls whether the resume * resolver is active — when it is, users are redirected to their furthest * incomplete step instead of being able to access any reachable step freely. */ interface JourneyReachability { /** * Controls when Forge's resume behaviour is active for this journey. * * - `true` — resume is always active: GET requests to a step other than the * resume frontier redirect to it, once progress and a frontier exist. * - A dynamic expression — resume only when the expression resolves to a * truthy value; a falsy result behaves the same as `false`. * - `false` — behaves the same as omitting it (resume is never active). * - Omitted — resume is never active; users access any reachable step freely. * * @example * reachability: { resumeWhen: true } * reachability: { resumeWhen: Query('resume').match(Condition.Equals('true')) } */ resumeWhen?: ResolvableBoolean; /** * Controls where Forge redirects when a requested step is not reachable. * * - `entry` — redirect to the default active entry point. * - `frontier` — redirect to the current frontier when one exists, otherwise * fall back to the default active entry point. * * @example * reachability: { unreachableRedirect: 'frontier' } */ unreachableRedirect?: UnreachableRedirectTarget; /** * Disables the reachability BFS walk for this journey. All steps are * treated as reachable without requiring entry points or forward edges. * * Child journeys inherit this setting but can override it with an * explicit `false` to re-enable reachability checks. * * @example * reachability: { disableReachabilityChecks: true } */ disableReachabilityChecks?: boolean; } /** * Reachability configuration for a step. Controls how the step participates * in the reachability walk that determines which steps a user can access. */ interface StepReachability { /** * Declares this step as an entry point for the reachability walk. * * - `true` — unconditional entry point (always seeded as reachable). * - A dynamic expression — conditional entry point, seeded only when the * expression resolves to a truthy value. An active conditional entry * whose path already has progress can anchor the resume frontier past * an earlier blocker. * - `false` — behaves the same as omitting it (not an entry point). * * @example * reachability: { entryWhen: true } * reachability: { entryWhen: Session('submitted').match(Condition.Equals(true)) } */ entryWhen?: ResolvableBoolean; /** * Prioritised tie-breaker rules consulted whenever this step is one of * several equally-valid candidates. Rules are evaluated top-to-bottom; * the first matching entry supplies the step's priority. * * @example * reachability: { * entryWhen: true, * tieBreakers: [tieBreaker({ priority: 100 })], * } */ tieBreakers?: TieBreaker[]; } interface StepEntryValidation { groups: string[]; /** * Controls when these groups are validated as the step is entered. * * - `true` — the groups are always validated on entry. * - A dynamic expression — the groups are validated only when the expression * resolves to a truthy value. * - `false` — behaves the same as omitting the entry (the rule never fires). */ when: ResolvableBoolean; } /** * Definition for a single step within a journey. * Steps contain blocks and define navigation/hook logic. */ interface StepDefinition { type: StructureType.STEP; /** * URL segment appended to the owning journey's path to form the step's * route. * * @example * path: '/overview' * * @example * // Route parameters are declared with a colon * path: '/record/:index' */ path: string; /** * Optional stable identifier for the step, independent of its URL path. * Surfaced in reachability projections and diagnostic traces so steps can * be recognised without relying on their (possibly parameterised) path. * * @example * code: 'check-answers' */ code?: string; /** * Content of the step, rendered in order. Blocks are built with registered * components: field blocks collect answers, basic blocks display content. * * @see {@link BlockDefinition} */ blocks?: BlockDefinition[]; /** * Lifecycle hooks run on every request to this step, after the hooks of * its ancestor journeys. Use them for access control and data loading. * * @example * onAccess: [access({ effects: [loadGoal()] })] * * @see {@link AccessHook} for hook evaluation order and outcomes */ onAccess?: AccessHook[]; /** * Hooks run when the step is submitted. The first hook whose `when` and * `guards` pass executes; the rest are skipped. * * @example * onSubmission: [ * submit({ * validate: true, * onValid: { * effects: [saveGoal()], * next: [redirect({ goto: '/overview' })], * }, * }), * ] * * @see {@link SubmitHook} for validation routing and outcomes */ onSubmission?: SubmitHook[]; /** * Surfaces existing validation failures when the step is loaded, without * a submission. Each entry names the validation groups to surface and a * `when` controlling whether they are. * * @example * // A check-answers step showing any outstanding failures on arrival * validateOnEntry: [{ groups: ['default'], when: true }] * * @see {@link StepEntryValidation} */ validateOnEntry?: StepEntryValidation[]; /** * Display title for the step, surfaced on the route tree and render * context. The title may be an expression, resolved per request. * * @example * title: 'Check your answers' * * @example * // Titles may be expressions * title: Format('Edit goal %1', Params('goalId')) */ title: ResolvableString; /** * Optional display description, surfaced alongside {@link title} on the * route tree. The description may be an expression, resolved per request. */ description?: ResolvableString; /** * View configuration for rendering this step. Applied on top of the * combined view of its ancestor journeys: the nearest `template` wins * and `locals` merge by key. * * @see {@link ViewConfig} */ view?: ViewConfig; /** * Controls how this step participates in the reachability walk: whether * it is an entry point, and how ties between candidates are broken. * * @see {@link StepReachability} */ reachability?: StepReachability; /** * Overrides the back link shown on this step. When omitted, Forge derives * it from the reachability walk (the previous reachable step). The value * is rendered as-is, so the browser resolves relative targets against the * step's URL. * * @example * backlink: 'tasks' * * @example * // Point at a hub step in the parent journey * backlink: '../tasks' */ backlink?: string; /** * Custom key/value pairs surfaced on the route tree and render context, * for concerns like navigation labels or template flags. * Values may be expressions, resolved per request. * * @example * metadata: { navLabel: 'Check answers', hideFromNav: true } * * @example * // Values may be expressions * metadata: { navLabel: Answer('nickname') } */ metadata?: RouteMetadata; /** * Static data merged into the request's data context, readable with * `Data()` references. Merges root-first, so this step's keys override * its ancestor journeys'. Plain values only; expressions are rejected * at registration. * * @example * data: { maxAttachments: 5 } * // Read elsewhere with Data('maxAttachments') */ data?: Record; /** * Validation rules for this step. Rules are checked in order. * * @example * validWhen: [ * validation({ * condition: Self().match(Condition.IsRequired()), * message: 'Select an option', * }), * ] */ validWhen?: ValidWhenInput[] | IterateExpr | ChainableIterable; /** * Regex patterns matched against answer keys when this step becomes * unreachable. Matching answers are cleared alongside the step's own field * answers. Use this for answers the step stores under dynamic keys that * its blocks don't declare. * * @example * // Clear every answer stored under the visitDetails prefix * cleardownFieldCodes: ['^visitDetails\\.'] */ cleardownFieldCodes?: string[]; } //#endregion //#region forge-core/src/authoring/types/functions.type.d.ts /** * The callable implementation of a registered function, with its dependencies * already applied. For conditions, transformers, and effects the first * argument is the injected value (or effect context) and the remaining * arguments are the authored ones; generators receive only the authored * arguments. */ type FunctionEvaluator = (...args: any[]) => T; /** * A runtime registry entry for one registered function, as consumed by the * engine. Usually produced by `build()` on a {@link BaseFunctionRegistry} * subclass rather than written by hand. */ interface FunctionRegistryEntry { /** Registry key the function is looked up by when expressions call it. */ name: string; /** The implementation to call. */ evaluate: FunctionEvaluator; /** * Validates the injected value before {@link evaluate} runs. A failing * value makes a condition evaluate to `false` (a wrongly-shaped field is * a normal "not valid yet" outcome); for any other kind a failure throws. */ inputSchema?: ZodType; /** * Validates the authored arguments (excluding the injected value) before * {@link evaluate} runs, and drives arity checking at compilation. A * failure always throws: bad arguments are an authoring mistake. */ argumentsSchema?: ZodType; /** * Validates the return value of {@link evaluate}. A failure throws. */ outputSchema?: ZodType; /** * Which kind of function this is. Decides whether a value is injected as * the first argument and how schema failures short-circuit. */ functionType?: FunctionType; } /** * Registry entries keyed by function name: the shape the engine resolves * function calls against, and what `build()` on a registry returns. */ type FunctionRegistryObject = Record; //#endregion //#region forge-core/src/authoring/utils/deprecated/defineFunction.type.d.ts /** @deprecated Use registry classes instead. */ type NoDeps = Record; /** @deprecated Use registry classes instead. */ type FunctionShapeMap = Record>; type PublicFunctionArguments = TFunction extends ((...args: infer TArgs) => unknown) ? TArgs : never; type FunctionGroup = { [K in keyof T]: (...args: PublicFunctionArguments) => TExpr; }; /** @deprecated Use ConditionRegistry instead. */ type ConditionFunctionGroup = FunctionGroup>; /** @deprecated Use TransformerRegistry instead. */ type TransformerFunctionGroup = FunctionGroup>; /** @deprecated Use EffectRegistry instead. */ type EffectFunctionGroup = FunctionGroup>; /** @deprecated Use GeneratorRegistry instead. */ type GeneratorFunctionGroup = FunctionGroup; /** @deprecated Use registry classes instead. */ type FunctionImplementations = { [K in keyof TShapes]: (deps: TDeps) => TShapes[K]; }; /** * A factory entry can be a plain factory function (backward-compatible) or an * object that also exposes a synchronous `prepare` hook. * * `prepare` runs at author-call time — when `conditions.Name(...)`, `generators.Name(...)` * etc. are invoked to build the expression — and receives the same args the * author passed. It does not see runtime dependencies or the injected `value` / * `context` first parameter. * * Use it to sanitise or reshape arguments before they enter the expression tree * (e.g. stripping `block` / `divider` properties from radio items), and/or to * throw when arguments are structurally invalid (bad template syntax, missing * required arg, etc.). * * Return the (possibly cleaned) arguments as an array. The returned array * replaces the original arguments in the built expression. * * @deprecated Use registry classes instead. */ type FunctionFactoryEntry, TDeps, TPublicArgs extends readonly unknown[]> = ((deps: TDeps) => TEvaluator) | { prepare?: (...args: TPublicArgs) => [...TPublicArgs]; factory: (deps: TDeps) => TEvaluator; }; type RuntimeContext$1 = { condition: [value: unknown]; transformer: [value: unknown]; effect: [context: EffectFunctionContext$1]; generator: []; }; type RuntimeReturn = { condition: boolean | Promise; transformer: ResolvableValue | Promise; effect: void | Promise; generator: ResolvableValue | Promise; }; /** @deprecated Use registry classes instead. */ type ImplementationShapes unknown>> = { [K in keyof TFunctions]: (...args: [...RuntimeContext$1[TKind], ...PublicFunctionArguments]) => RuntimeReturn[TKind]; }; /** @deprecated Use ConditionRegistry instead. */ type ConditionImplementations, TDeps = NoDeps> = { [K in keyof TConditions]: FunctionFactoryEntry[K], TDeps, PublicFunctionArguments>; }; /** @deprecated Use TransformerRegistry instead. */ type TransformerImplementations, TDeps = NoDeps> = { [K in keyof TTransformers]: FunctionFactoryEntry[K], TDeps, PublicFunctionArguments>; }; /** @deprecated Use EffectRegistry instead. */ type EffectImplementations, TDeps = NoDeps> = { [K in keyof TEffects]: FunctionFactoryEntry[K], TDeps, PublicFunctionArguments>; }; /** @deprecated Use GeneratorRegistry instead. */ type GeneratorImplementations, TDeps = NoDeps> = { [K in keyof TGenerators]: FunctionFactoryEntry[K], TDeps, PublicFunctionArguments>; }; type ReferenceArguments> = Parameters extends [unknown, ...infer TRest] ? TRest : []; type ValueArguments> = ReferenceArguments extends ResolvableValue[] ? ReferenceArguments : never; type GeneratorArguments> = Parameters extends ResolvableValue[] ? Parameters : never; /** @deprecated Use ConditionRegistry instead. */ type ConditionFunctions = { [K in keyof TShapes]: (...args: ValueArguments) => ConditionFunctionExpr>; }; /** @deprecated Use TransformerRegistry instead. */ type TransformerFunctions = { [K in keyof TShapes]: (...args: ValueArguments) => TransformerFunctionExpr>; }; /** @deprecated Use EffectRegistry instead. */ type EffectFunctions = { [K in keyof TShapes]: (...args: ValueArguments) => EffectFunctionExpr>; }; /** @deprecated Use GeneratorRegistry instead. */ type GeneratorFunctions = { [K in keyof TShapes]: (...args: GeneratorArguments) => ChainableGenerator; }; //#endregion //#region forge-core/src/authoring/registries/BaseFunctionRegistry.d.ts interface RegistrationOptions { inputSchema?: ZodType; argumentsSchema?: ZodType; outputSchema?: ZodType; prepare?: (...args: any[]) => any[]; } declare const REGISTRY_BRAND: unique symbol; declare abstract class BaseFunctionRegistry> { private readonly functionType; private readonly defaultOutputSchema?; readonly [REGISTRY_BRAND] = true; private readonly registrations; private anonymousCounter; constructor(functionType: FunctionType, defaultOutputSchema?: ZodType | undefined); protected nextAnonymousName(): string; protected parseArgs(first: string | RegistrationOptions | ((deps: TDeps) => (...args: any[]) => any), second?: RegistrationOptions | ((deps: TDeps) => (...args: any[]) => any), third?: (deps: TDeps) => (...args: any[]) => any): { name: string; options: RegistrationOptions; factory: (deps: TDeps) => (...args: any[]) => any; }; private requireEmbeddedFactory; protected store(name: string, options: RegistrationOptions, factory: (deps: TDeps) => (...args: any[]) => any): void; protected buildExpressionHandle(name: string, prepare?: (...args: any[]) => any[]): (...args: any[]) => any; build(deps?: TDeps): FunctionRegistryObject; private compileSchema; private compileOutputSchema; } //#endregion //#region forge-core/src/authoring/types/package.type.d.ts /** * A forge package bundles a journey definition with its custom registries. * * Use this to export journeys as self-contained packages that include their * effects, transformers, conditions, and components alongside the journey definition. * * @typeParam TDeps - Dependencies required to create the function registries * * @see {@link createForgePackage} for the recommended way to create forge packages */ interface ForgePackage> { /** * The root journey definition this package mounts, compiled at registration. * Accepts a JSON string, which {@link createForgePackage} parses. */ journey: string | JourneyDefinition; /** * Custom functions for this package, layered over the global function * registry and visible only to this package's journey. Accepts a function * registry, an array of registries, or the deprecated implementations-map * form. The dependencies passed to `registerPackage()` are given to each * registry's `build()`. * * @see {@link BaseFunctionRegistry} */ functions?: FunctionImplementations | BaseFunctionRegistry | BaseFunctionRegistry[]; /** * Custom components for this package, layered over the global component * registry and visible only to this package's journey. * * @see {@link ComponentRegistryEntry} */ components?: ComponentRegistryEntry[]; /** * Whether this package should be registered. Default: true * * When set to false, registerPackage() will skip registration entirely. * Useful for disabling journeys via configuration or feature flags. * * @example * ```typescript * createForgePackage({ * enabled: config.featureFlags.myFormEnabled, * journey: myJourney, * }) * ``` */ enabled?: boolean; } /** * A forge package that has been finalised by {@link createForgePackage}. * * The journey is guaranteed to be a parsed, builder-free definition, and the * `forgePackage` brand marks the package as safe for `Forge.registerPackage()`, * which rejects packages that have not passed through `createForgePackage()`. * * @typeParam TDeps - Dependencies required to create the function registries */ interface RegisteredForgePackage> extends Omit, 'journey'> { /** The parsed, finalised journey definition this package mounts. */ journey: JourneyDefinition; /** Brand stamped by {@link createForgePackage}; registration requires it. */ forgePackage: true; } //#endregion //#region forge-core/src/authoring/builders/structures.d.ts /** * Creates a presentational (non-field) block for a step. * Use for headings, paragraphs, inset text, and other non-interactive content. */ declare function block(definition: Omit): D; /** * Creates a field block that captures user input. * Fields have a `code` for storing answers and support `validWhen`, `dependentWhen`, * `defaultValue`, and `formatters`. */ declare function field(definition: Omit): D; /** * Creates a step (page) within a journey. * Steps contain blocks and define lifecycle hooks for access, submission, and actions. */ declare function step(definition: Omit): D; /** * Creates a journey definition - a complete form flow containing steps. */ declare function journey(definition: Omit): D; /** * Create a forge package that bundles a journey with its custom functions and components. * * This is the mandatory gate into Forge: it parses string journeys, finalises * any builders in the journey tree (stamping source locations for diagnostics), * and brands the result so `Forge.registerPackage()` accepts it. * * @param pkg - The forge package configuration * @returns The package with a finalised journey, branded for registration * * @example * ```typescript * // Package with custom functions (deps injected via registerPackage) * export default createForgePackage({ * journey: myJourney, * functions: { * ...myEffectsImplementations, * ...myTransformersImplementations, * }, * }) * * // Journey only (no custom functions) * export default createForgePackage({ * journey: simpleJourney, * }) * ``` */ declare function createForgePackage>(pkg: ForgePackage): RegisteredForgePackage; //#endregion //#region forge-core/src/authoring/builders/hooks.d.ts /** * Creates a submission hook for handling form submissions. * Use this in the onSubmission array of steps. */ declare function submit(definition: Omit): SubmitHook; /** * Creates an access hook for access control, data loading, and analytics. * Use this in the onAccess array of journeys or steps. */ declare function access(definition: Omit): AccessHook; /** * Creates a validation rule for a field or step. * Add to the `validWhen` array - rules are checked in order. */ declare function validation(definition: ValidationProps): ValidationExpr; /** * Creates a tie-breaker rule for a step. Add to `reachability.tieBreakers` — * entries are evaluated top-to-bottom and the first matching `when` (or an * entry with no `when`) supplies the step's priority. * * @example * tieBreaker({ priority: 100, when: Answer('income_started').match(true) }) */ declare function tieBreaker(definition: TieBreakerProps): TieBreaker; /** * Creates a redirect outcome for hooks. * When matched, halts hook processing and redirects to the specified path. * * @example * // Unconditional redirect * redirect({ goto: '/overview' }) * * @example * // Conditional redirect * redirect({ * when: Data('needsSetup').match(Condition.Equals(true)), * goto: '/setup', * }) */ declare function redirect(definition: Omit): RedirectOutcome; /** * Creates an error outcome for hooks. * When matched, halts hook processing and returns an error outcome. * * @example * // Not found error * throwError({ * when: Data('notFound').match(Condition.Equals(true)), * status: 404, * message: 'Item not found', * }) * * @example * // Dynamic error message * throwError({ * when: Data('saveError').match(Condition.IsRequired()), * status: 500, * message: Format('Failed to save: %1', Data('saveError')), * }) */ declare function throwError(definition: Omit): ThrowErrorOutcome; //#endregion //#region forge-core/src/authoring/builders/values.d.ts /** * Creates a string formatting expression with placeholder substitution. * Placeholders are %1, %2, etc. * * @example * Format('Hello %1!', Answer('name')) * Format('%1 %2', Answer('firstName'), Answer('lastName')) */ declare const Format: (template: ResolvableString, ...args: ResolvableString[]) => ChainableGenerator; /** * Wraps a static/literal value to make it chainable with .pipe() and .match(). * * Use this when you have static data that you want to transform or test * using the fluent expression API. * * @param value - Any static value (array, object, primitive) * @returns A chainable expression (only exposes .pipe(), .match(), .not) * * @example * // Static array with transformations * Literal(['apple', 'banana', 'cherry']).pipe(Transformer.Array.Filter(...)) * * // Static value with condition * Literal(42).match(Condition.Number.GreaterThan(0)) * * // Use with .each() for iteration * Literal([1, 2, 3]).each(Iterator.Map(Item().value())) */ declare function Literal(value: ResolvableValue): ChainableExpr; //#endregion //#region forge-core/src/authoring/builders/ConditionalExprBuilder.d.ts /** * Creates a conditional expression builder with the given predicate. * Use this for fluent chained conditional building. * * @param predicate - The condition to evaluate * @returns A chainable conditional for fluent then/else building * * @example * when(Answer('age').match(Condition.GreaterThan(18))) * .then('adult') * .else('child') */ declare const when: (predicate: PredicateExpr | PredicateTestExpr) => ChainableConditional; /** * Options for creating a conditional expression using object syntax. */ interface ConditionalOptions { /** The predicate condition to evaluate */ when: PredicateExpr | PredicateTestExpr; /** Value to return when predicate is true */ then: BranchValue; /** Value to return when predicate is false (optional, defaults to false) */ else?: BranchValue; } /** * Creates a conditional expression using object syntax. * Alternative to the fluent `when().then().else()` builder. * * @param options - Object with when, then, and optional else properties * @returns A chainable conditional that will be finalised during form processing * * @example * // Basic usage * Conditional({ * when: Answer('country').match(Condition.Equals('UK')), * then: 'Postcode', * else: 'ZIP Code', * }) * * // Without else (returns false when the predicate is false) * Conditional({ * when: Answer('isPremium').match(Condition.Equals(true)), * then: 'Premium Support', * }) * * // Nested conditionals * Conditional({ * when: Answer('tier').match(Condition.Equals('premium')), * then: 'Premium', * else: Conditional({ * when: Answer('tier').match(Condition.Equals('standard')), * then: 'Standard', * else: 'Basic', * }), * }) */ declare const Conditional: (options: ConditionalOptions) => ChainableConditional; //#endregion //#region forge-core/src/authoring/builders/MatchExprBuilder.d.ts /** * Creates a match expression builder for the given subject. * Use this to create switch-like conditional logic with multiple branches. * Each branch takes a single condition or a combinator tree built with * and()/or()/xor()/not(); the subject is applied to every condition leaf. * * @param subject - The value to match against * @returns A chainable match for fluent branch building * * @example * match(Item().path('status')) * .branch(Condition.Equals('NOT_STARTED'), 'Not started') * .branch(Condition.Equals('IN_PROGRESS'), 'In progress') * .branch(or(Condition.Equals('COMPLETED'), Condition.Equals('APPROVED')), 'Completed') * .otherwise('Unknown') */ declare const match: (subject: BranchValue) => ChainableMatch; //#endregion //#region forge-core/src/authoring/builders/combinators.d.ts /** * Creates an AND combination where all operands must be true. * Given predicates, returns an AND logic predicate. * Given bare conditions, or combinators over them, returns a subject-less AND * condition combinator, whose conditions take their subject from the surrounding match. * @param p - Two or more operands to combine, as one array or as separate arguments * @returns A logic predicate, or a condition combinator, that is true if all operands are true */ declare function and(p: PredicateExpr[]): PredicateAndExpr; declare function and(...p: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]): PredicateAndExpr; declare function and(c: ConditionBranchExpr[]): ConditionAndExpr; declare function and(...c: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]): ConditionAndExpr; /** * Creates an OR combination where at least one operand must be true. * Given predicates, returns an OR logic predicate. * Given bare conditions, or combinators over them, returns a subject-less OR * condition combinator, whose conditions take their subject from the surrounding match. * @param p - Two or more operands to combine, as one array or as separate arguments * @returns A logic predicate, or a condition combinator, that is true if any operand is true */ declare function or(p: PredicateExpr[]): PredicateOrExpr; declare function or(...p: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]): PredicateOrExpr; declare function or(c: ConditionBranchExpr[]): ConditionOrExpr; declare function or(...c: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]): ConditionOrExpr; /** * Creates an XOR combination where exactly one operand must be true. * Given predicates, returns an XOR logic predicate. * Given bare conditions, or combinators over them, returns a subject-less XOR * condition combinator, whose conditions take their subject from the surrounding match. * @param p - Two or more operands to combine, as one array or as separate arguments * @returns A logic predicate, or a condition combinator, that is true if exactly one operand is true */ declare function xor(p: PredicateExpr[]): PredicateXorExpr; declare function xor(...p: [PredicateExpr, PredicateExpr, ...PredicateExpr[]]): PredicateXorExpr; declare function xor(c: ConditionBranchExpr[]): ConditionXorExpr; declare function xor(...c: [ConditionBranchExpr, ConditionBranchExpr, ...ConditionBranchExpr[]]): ConditionXorExpr; /** * Creates a NOT combination that inverts the operand's result. * Given a predicate, returns a NOT logic predicate. * Given a bare condition, or a combinator over them, returns a subject-less NOT * condition combinator, whose conditions take their subject from the surrounding match. * @param p - The operand to negate * @returns A logic predicate, or a condition combinator, that is the opposite of the operand */ declare function not(p: PredicateExpr): PredicateNotExpr; declare function not(c: ConditionBranchExpr): ConditionNotExpr; //#endregion //#region forge-core/src/authoring/builders/iterators.d.ts /** * Iterator namespace containing factory functions for iterator configurations. * * Iterators are used with the .each() method to perform per-item operations on collections. * Unlike transformers which operate on the whole array, iterators enter per-item iteration * mode where Item() references are available. * * @example * // Map: Transform each item * Data('items').each(Iterator.Map( * { label: Item().path('name'), value: Item().path('id') } * )) * * @example * // Filter: Keep matching items * Data('items').each(Iterator.Filter( * Item().path('active').match(Condition.Equals(true)) * )) * * @example * // Chain filter and map * Data('items') * .each(Iterator.Filter(Item().path('active').match(Condition.Equals(true)))) * .each(Iterator.Map({ label: Item().path('name') })) */ declare const Iterator: { /** * Create a Map iterator that transforms each item to a new shape. * * @param yieldValue - The template for each transformed item * @returns MapIteratorConfig to use with .each() * * @example * // Transform items to label/value pairs * Iterator.Map({ label: Item().path('name'), value: Item().path('id') }) * * @example * // Extract a single property from each item * Iterator.Map(Item().path('name')) */ Map(yieldValue: unknown): MapIteratorConfig; /** * Create a Filter iterator that keeps items matching a predicate. * * @param predicate - Predicate expression using Item() references * @returns FilterIteratorConfig to use with .each() * * @example * // Keep only active items * Iterator.Filter(Item().path('active').match(Condition.Equals(true))) * * @example * // Exclude items matching a value * Iterator.Filter(Item().path('slug').not.match(Condition.Equals(Params('currentSlug')))) */ Filter(predicate: PredicateExpr): FilterIteratorConfig; /** * Create a Find iterator that returns the first item matching a predicate. * Returns undefined if no match is found. * * @param predicate - Predicate expression using Item() references * @returns FindIteratorConfig to use with .each() * * @example * // Find user by ID * Data('users').each(Iterator.Find( * Item().path('id').match(Condition.Equals(Params('userId'))) * )) * * @example * // Find first active item * Data('items').each(Iterator.Find( * Item().path('active').match(Condition.Equals(true)) * )) */ Find(predicate: PredicateExpr): FindIteratorConfig; /** Returns whether any item matches; empty collections return false. */ Some(predicate: PredicateExpr): SomeIteratorConfig; /** Returns whether every item matches; empty collections return true. */ Every(predicate: PredicateExpr): EveryIteratorConfig; /** Counts matching items; empty collections return zero. */ Count(predicate: PredicateExpr): CountIteratorConfig; }; //#endregion //#region forge-core/src/authoring/registries/ConditionRegistry.d.ts declare class ConditionRegistry> extends BaseFunctionRegistry { constructor(); register(name: string, options: RegistrationOptions & { factory: (deps: TDeps) => (value: any, ...args: TArgs) => boolean | PromiseLike; }): (...args: { [K in keyof TArgs]: Resolvable; }) => ConditionFunctionExpr; register(name: string, options: RegistrationOptions, factory: (deps: TDeps) => (value: any, ...args: TArgs) => boolean | PromiseLike): (...args: { [K in keyof TArgs]: Resolvable; }) => ConditionFunctionExpr; register(name: string, factory: (deps: TDeps) => (value: any, ...args: TArgs) => boolean | PromiseLike): (...args: { [K in keyof TArgs]: Resolvable; }) => ConditionFunctionExpr; register(options: RegistrationOptions, factory: (deps: TDeps) => (value: any, ...args: TArgs) => boolean | PromiseLike): (...args: { [K in keyof TArgs]: Resolvable; }) => ConditionFunctionExpr; register(factory: (deps: TDeps) => (value: any, ...args: TArgs) => boolean | PromiseLike): (...args: { [K in keyof TArgs]: Resolvable; }) => ConditionFunctionExpr; } //#endregion //#region forge-core/src/built-ins/functions/conditions/generalConditions.d.ts declare const GeneralConditions: { /** Checks if a value is not empty/null/undefined */ IsRequired(): ConditionFunctionExpr; /** Checks if a value is strictly equal to an expected value */ Equals(expected: unknown): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/stringConditions.d.ts declare const StringConditions: { /** Checks if a string matches a regular expression pattern */ MatchesRegex(pattern: Resolvable): ConditionFunctionExpr; /** Checks if a string has at least the minimum specified length */ HasMinLength(min: Resolvable): ConditionFunctionExpr; /** Checks if a string does not exceed the maximum specified length */ HasMaxLength(max: Resolvable): ConditionFunctionExpr; /** Checks if a string has exactly the specified length */ HasExactLength(len: Resolvable): ConditionFunctionExpr; /** Checks if a string contains at most the specified number of words */ HasMaxWords(maxWords: Resolvable): ConditionFunctionExpr; /** Contains only letters (A-Z, a-z) */ LettersOnly(): ConditionFunctionExpr; /** Contains only digits (0-9) */ DigitsOnly(): ConditionFunctionExpr; /** Contains only letters and common punctuation */ LettersWithCommonPunctuation(): ConditionFunctionExpr; /** Contains only letters, spaces, dashes, and apostrophes */ LettersWithSpaceDashApostrophe(): ConditionFunctionExpr; /** Contains only letters and digits (alphanumeric) */ LettersAndDigitsOnly(): ConditionFunctionExpr; /** Contains only alphanumeric characters and common punctuation */ AlphanumericWithCommonPunctuation(): ConditionFunctionExpr; /** Contains only alphanumeric characters and safe symbols */ AlphanumericWithAllSafeSymbols(): ConditionFunctionExpr; /** Checks if a string starts with the specified prefix */ StartsWith(prefix: Resolvable): ConditionFunctionExpr; /** Checks if a string ends with the specified suffix */ EndsWith(suffix: Resolvable): ConditionFunctionExpr; /** Checks if a string contains the specified substring */ Contains(substring: Resolvable): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/addressConditions.d.ts declare const AddressConditions: { /** Validates if a string is a valid UK postcode format */ IsValidPostcode(): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/emailConditions.d.ts declare const EmailConditions: { /** Validates if a string is a properly formatted email address */ IsValidEmail(): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/dateConditions.d.ts declare const DateConditions: { /** Checks if a value is a valid ISO-8601 date string (YYYY-MM-DD) */ IsValid(): ConditionFunctionExpr; /** Validates if an ISO date string has a valid year component (1000-9999) */ IsValidYear(): ConditionFunctionExpr; /** Validates if an ISO date string has a valid month component (1-12) */ IsValidMonth(): ConditionFunctionExpr; /** Validates if a date string has a valid day component for its specific month/year */ IsValidDay(): ConditionFunctionExpr; /** Checks if an ISO date string is before another ISO date string */ IsBefore(dateStr: Resolvable): ConditionFunctionExpr; /** Checks if an ISO date string is after another ISO date string */ IsAfter(dateStr: Resolvable): ConditionFunctionExpr; /** Checks if an ISO date string is in the future (after today) */ IsFutureDate(): ConditionFunctionExpr; /** Checks if an ISO date string is in the past (before today) */ IsPastDate(): ConditionFunctionExpr; /** Checks if an ISO date string is today */ IsToday(): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/numberConditions.d.ts declare const NumberConditions: { /** Checks if a value is a number (not NaN, not a string, not undefined) */ IsNumber(): ConditionFunctionExpr; /** Checks if a value is an integer (whole number) */ IsInteger(): ConditionFunctionExpr; /** Checks if a number is greater than a threshold value */ GreaterThan(threshold: Resolvable): ConditionFunctionExpr; /** Checks if a number is greater than or equal to a threshold value */ GreaterThanOrEqual(threshold: Resolvable): ConditionFunctionExpr; /** Checks if a number is less than a threshold value */ LessThan(threshold: Resolvable): ConditionFunctionExpr; /** Checks if a number is less than or equal to a threshold value */ LessThanOrEqual(threshold: Resolvable): ConditionFunctionExpr; /** Checks if a number is between two values (inclusive) */ Between(min: Resolvable, max: Resolvable): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/phoneConditions.d.ts declare const PhoneConditions: { /** Validates if a string is a valid phone number format (7-20 digits) */ IsValidPhoneNumber(): ConditionFunctionExpr; /** Validates if a string is a valid UK mobile phone number */ IsValidUKMobile(): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/arrayConditions.d.ts declare const ArrayConditions: { /** Checks if a value is an array */ IsArray(): ConditionFunctionExpr; /** Checks if a value exists within an array of options */ IsIn(expected: Resolvable): ConditionFunctionExpr; /** Checks if an array contains a specific value */ Contains(expected: unknown): ConditionFunctionExpr; /** Checks if an array contains any of the items from another array */ ContainsAny(expected: Resolvable): ConditionFunctionExpr; /** Checks if all items in the value array exist in the expected array */ ContainsAll(expected: Resolvable): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/objectConditions.d.ts declare const ObjectConditions: { /** Checks if a value is a plain object (not null, not array) */ IsObject(): ConditionFunctionExpr; /** Checks if an object has a property at the given path */ HasProperty(path: Resolvable): ConditionFunctionExpr; /** Checks if an object property at the given path is empty */ PropertyIsEmpty(path: Resolvable): ConditionFunctionExpr; /** Checks if an object property at the given path has a value (not empty) */ PropertyHasValue(path: Resolvable): ConditionFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/conditions/index.d.ts interface ConditionGroups { /** Conditions for handling strings */ String: typeof StringConditions; /** Conditions for handling emails */ Email: typeof EmailConditions; /** Conditions for handling phone/mobile numbers */ Phone: typeof PhoneConditions; /** Conditions for handling addresses */ Address: typeof AddressConditions; /** Conditions for handling dates */ Date: typeof DateConditions; /** Conditions for handling numbers */ Number: typeof NumberConditions; /** Conditions for handling arrays */ Array: typeof ArrayConditions; /** Conditions for handling objects */ Object: typeof ObjectConditions; } declare const Condition: typeof GeneralConditions & ConditionGroups; declare const ConditionsRegistry: { [x: string]: FunctionRegistryEntry; }; //#endregion //#region forge-core/src/authoring/registries/GeneratorRegistry.d.ts declare class GeneratorRegistry> extends BaseFunctionRegistry { constructor(); register(name: string, options: RegistrationOptions & { factory: (deps: TDeps) => (...args: TArgs) => any; }): (...args: { [K in keyof TArgs]: Resolvable; }) => ChainableGenerator; register(name: string, options: RegistrationOptions, factory: (deps: TDeps) => (...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => ChainableGenerator; register(name: string, factory: (deps: TDeps) => (...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => ChainableGenerator; register(options: RegistrationOptions, factory: (deps: TDeps) => (...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => ChainableGenerator; register(factory: (deps: TDeps) => (...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => ChainableGenerator; } //#endregion //#region forge-core/src/built-ins/functions/generators/dateGenerators.d.ts declare const DateGenerators: { /** Generates the current date and time */ Now(): ChainableGenerator; /** Generates today's date at midnight */ Today(): ChainableGenerator; }; //#endregion //#region forge-core/src/built-ins/functions/generators/formatGenerators.d.ts declare const FormatGenerators: { /** Generates a string from a template with %1-style positional placeholders */ FormatString(template: Resolvable, ...replacements: unknown[]): ChainableGenerator; }; //#endregion //#region forge-core/src/built-ins/functions/generators/index.d.ts interface GeneratorGroups { /** Generators for producing formatted string values */ FormatString: typeof FormatGenerators.FormatString; /** Generators for producing date values */ Date: typeof DateGenerators; } declare const Generator: GeneratorGroups; declare const GeneratorsRegistry: { [x: string]: FunctionRegistryEntry; }; //#endregion //#region forge-core/src/authoring/registries/TransformerRegistry.d.ts declare class TransformerRegistry> extends BaseFunctionRegistry { constructor(); register(name: string, options: RegistrationOptions & { factory: (deps: TDeps) => (value: any, ...args: TArgs) => any; }): (...args: { [K in keyof TArgs]: Resolvable; }) => TransformerFunctionExpr; register(name: string, options: RegistrationOptions, factory: (deps: TDeps) => (value: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => TransformerFunctionExpr; register(name: string, factory: (deps: TDeps) => (value: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => TransformerFunctionExpr; register(options: RegistrationOptions, factory: (deps: TDeps) => (value: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => TransformerFunctionExpr; register(factory: (deps: TDeps) => (value: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => TransformerFunctionExpr; } //#endregion //#region forge-core/src/built-ins/functions/transformers/arrayTransformers.d.ts declare const ArrayTransformers: { /** * Returns the length of the array * @example * // Length() applied to [1, 2, 3, 4] returns 4 */ Length(): TransformerFunctionExpr; /** * Returns the first element of the array * @example * // First() applied to [1, 2, 3] returns 1 */ First(): TransformerFunctionExpr; /** * Returns the last element of the array * @example * // Last() applied to [1, 2, 3] returns 3 */ Last(): TransformerFunctionExpr; /** * Reverses the array (returns a new array) * @example * // Reverse() applied to [1, 2, 3] returns [3, 2, 1] */ Reverse(): TransformerFunctionExpr; /** * Joins array elements into a string with specified separator * @param separator - Separator to place between elements (defaults to ',') * @example * // Join(", ") applied to [1, 2, 3] returns "1, 2, 3" */ Join(separator?: Resolvable): TransformerFunctionExpr; /** * Returns a slice of the array from start to end index * @param start - The zero-based index at which to begin extraction * @param end - The zero-based index before which to end extraction (optional) * @example * // Slice(1, 4) applied to [1, 2, 3, 4, 5] returns [2, 3, 4] */ Slice(start: Resolvable, end?: Resolvable): TransformerFunctionExpr; /** * Concatenates arrays together * @param arrays - Additional arrays to concatenate to the input * @example * // Concat([3, 4]) applied to [1, 2] returns [1, 2, 3, 4] */ Concat(...args: Resolvable[]): TransformerFunctionExpr; /** * Returns unique elements from the array (removes duplicates) * @example * // Unique() applied to [1, 2, 2, 3, 1] returns [1, 2, 3] */ Unique(): TransformerFunctionExpr; /** * Sorts the array in ascending order (returns a new array) * @example * // Sort() applied to [3, 1, 4, 2] returns [1, 2, 3, 4] */ Sort(): TransformerFunctionExpr; /** * Filters the array to only include elements that match the specified value * @param filterValue - The value each element is compared against * @example * // Filter(2) applied to [1, 2, 2, 3] returns [2, 2] */ Filter(filterValue: unknown): TransformerFunctionExpr; /** * Maps each array element by extracting a property (for objects) or applying an index (for arrays) * @param property - The property name (for objects) or index (for nested arrays) to extract * @example * // Map('name') applied to [{name: 'John'}, {name: 'Jane'}] returns ['John', 'Jane'] * // Map(0) applied to [[1, 2], [3, 4]] returns [1, 3] */ Map(property: Resolvable): TransformerFunctionExpr; /** * Flattens a nested array by one level * @example * // Flatten() applied to [[1, 2], [3, 4]] returns [1, 2, 3, 4] */ Flatten(): TransformerFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/transformers/dateTransformers.d.ts declare const DateTransformers: { /** * Formats a Date object into a string using the specified format * * Supported tokens: * - YYYY: 4-digit year (2024) * - YY: 2-digit year (24) * - MMMM: Full month name (January, February, March, etc.) * - MM: 2-digit month (01-12) * - M: Month (1-12) * - DD: 2-digit day (01-31) * - Do: Day of month (1st, 2nd, 3rd, etc.) * - D: Day (1-31) * - HH: 2-digit hours (00-23) * - H: Hours (0-23) * - mm: 2-digit minutes (00-59) * - m: Minutes (0-59) * - ss: 2-digit seconds (00-59) * - s: Seconds (0-59) * * @param format - Format string using the supported tokens * @example * // Format("DD/MM/YYYY") returns "15/03/2024" * // Format("YYYY-MM-DD") returns "2024-03-15" * // Format("D M YYYY") returns "15 3 2024" * // Format("HH:mm:ss") returns "14:30:45" */ Format(format: Resolvable): TransformerFunctionExpr; /** * Adds a number of days to a Date * @param days - Number of days to add (negative values subtract) * @example * // AddDays(7) adds one week * // AddDays(-1) subtracts one day */ AddDays(days: Resolvable): TransformerFunctionExpr; /** * Subtracts a number of days from a Date * @param days - Number of days to subtract * @example * // SubtractDays(7) subtracts one week */ SubtractDays(days: Resolvable): TransformerFunctionExpr; /** * Adds a number of months to a Date * @param months - Number of months to add (negative values subtract) * @example * // AddMonths(1) adds one month * // AddMonths(-6) subtracts 6 months */ AddMonths(months: Resolvable): TransformerFunctionExpr; /** * Adds a number of years to a Date * @param years - Number of years to add (negative values subtract) * @example * // AddYears(1) adds one year * // AddYears(-18) subtracts 18 years */ AddYears(years: Resolvable): TransformerFunctionExpr; /** * Returns the start of the day (midnight) for a Date * @example * // StartOfDay() returns 2024-03-15T00:00:00.000 */ StartOfDay(): TransformerFunctionExpr; /** * Returns the end of the day (23:59:59.999) for a Date * @example * // EndOfDay() returns 2024-03-15T23:59:59.999 */ EndOfDay(): TransformerFunctionExpr; /** * Converts a Date to ISO-8601 string format * @example * // ToISOString() returns "2024-03-15T14:30:45.123Z" */ ToISOString(): TransformerFunctionExpr; /** * Converts a Date to a locale-specific string * @param locale - Optional locale identifier (e.g. 'en-GB', 'en-US') * @example * // ToLocaleString() returns "15/03/2024, 14:30:45" (UK locale) * // ToLocaleString('en-US') returns "3/15/2024, 2:30:45 PM" */ ToLocaleString(locale?: Resolvable): TransformerFunctionExpr; /** * Converts a Date to UK long date format (e.g. "18 March 2026") * @example * // ToUKLongDate() returns "18 March 2026" */ ToUKLongDate(): TransformerFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/transformers/numberTransformers.d.ts declare const NumberTransformers: { /** * Adds a number to the input value * @param addend - The number to add * @example * // Add(3) applied to 5 returns 8 * // Add(Answer('tax')) applied to Answer('price') - dynamic addition */ Add(addend: Resolvable): TransformerFunctionExpr; /** * Subtracts a number from the input value * @param subtrahend - The number to subtract * @example * // Subtract(3) applied to 10 returns 7 */ Subtract(subtrahend: Resolvable): TransformerFunctionExpr; /** * Multiplies the input value by a number * @param multiplier - The number to multiply by * @example * // Multiply(3) applied to 4 returns 12 * // Multiply(Answer('quantity')) applied to Answer('price') - dynamic multiplication */ Multiply(multiplier: Resolvable): TransformerFunctionExpr; /** * Divides the input value by a number * @param divisor - The number to divide by * @example * // Divide(3) applied to 15 returns 5 */ Divide(divisor: Resolvable): TransformerFunctionExpr; /** * Returns the absolute value of the input * @example * // Abs() applied to -5 returns 5 */ Abs(): TransformerFunctionExpr; /** * Rounds the number to the nearest integer * @example * // Round() applied to 4.7 returns 5 */ Round(): TransformerFunctionExpr; /** * Rounds the number down to the nearest integer * @example * // Floor() applied to 4.7 returns 4 */ Floor(): TransformerFunctionExpr; /** * Rounds the number up to the nearest integer * @example * // Ceil() applied to 4.2 returns 5 */ Ceil(): TransformerFunctionExpr; /** * Rounds the number to a specified number of decimal places * @param decimals - The number of decimal places to round to * @example * // ToFixed(2) applied to 3.14159 returns 3.14 */ ToFixed(decimals: Resolvable): TransformerFunctionExpr; /** * Returns the maximum of the input value and a comparison value * @param comparison - The value to compare against * @example * // Max(10) applied to 5 returns 10 */ Max(comparison: Resolvable): TransformerFunctionExpr; /** * Returns the minimum of the input value and a comparison value * @param comparison - The value to compare against * @example * // Min(10) applied to 5 returns 5 */ Min(comparison: Resolvable): TransformerFunctionExpr; /** * Raises the input value to the power of the exponent * @param exponent - The exponent to raise the value to * @example * // Power(3) applied to 2 returns 8 */ Power(exponent: Resolvable): TransformerFunctionExpr; /** * Returns the square root of the input value * @example * // Sqrt() applied to 16 returns 4 */ Sqrt(): TransformerFunctionExpr; /** * Clamps the input value between a minimum and maximum range * @param min - The minimum value (inclusive) * @param max - The maximum value (inclusive) * @example * // Clamp(5, 10) applied to 15 returns 10 * // Clamp(5, 10) applied to 3 returns 5 * // Clamp(5, 10) applied to 7 returns 7 */ Clamp(min: Resolvable, max: Resolvable): TransformerFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/transformers/objectTransformers.d.ts interface DateParts { year?: string; month?: string; day?: string; } declare const ObjectTransformers: { /** * Converts an object with date parts to an ISO 8601 date string * Supports full dates (YYYY-MM-DD), partial dates (YYYY-MM, MM-DD), or single components * * @param paths - Object mapping date components to property paths * @example * // Full date: {day: "15", month: "3", year: "2024"} becomes "2024-03-15" * ToISO({year: 'year', month: 'month', day: 'day'}) * * @example * // Partial date: {month: "3", year: "2024"} becomes "2024-03" * ToISO({year: 'year', month: 'month'}) * * @example * // Nested paths: {date: {y: "2024", m: "3", d: "15"}} becomes "2024-03-15" * ToISO({year: 'date.y', month: 'date.m', day: 'date.d'}) */ ToISO(paths: Resolvable): TransformerFunctionExpr; /** * Converts an ISO 8601 date string back to an object with date parts. * The inverse of ToISO. Objects are passed through unchanged. * * @param paths - Object mapping date components to output property names * @example * // Full date: "2024-03-15" becomes {year: "2024", month: "03", day: "15"} * FromISO({year: 'year', month: 'month', day: 'day'}) * * @example * // Year-month: "2024-03" becomes {year: "2024", month: "03"} * FromISO({year: 'year', month: 'month'}) */ FromISO(paths: Resolvable): TransformerFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/transformers/stringTransformers.d.ts declare const StringTransformers: { /** * Removes whitespace from both ends of a string * @example * // Transforms " hello world " to "hello world" */ Trim(): TransformerFunctionExpr; /** * Converts string to uppercase * @example * // Transforms "Hello World" to "HELLO WORLD" */ ToUpperCase(): TransformerFunctionExpr; /** * Converts string to lowercase * @example * // Transforms "Hello World" to "hello world" */ ToLowerCase(): TransformerFunctionExpr; /** * Capitalizes the first letter of each word * @example * // Transforms "hello world" to "Hello World" */ ToTitleCase(): TransformerFunctionExpr; /** * Capitalizes the first letter of the string * @example * // Transforms "hello world" to "Hello world" */ Capitalize(): TransformerFunctionExpr; /** * Converts a name to its possessive form * Names ending in 's' get just an apostrophe, others get 's * @example * // Possessive("John") returns "John's" * // Possessive("James") returns "James'" * // Possessive("Chris") returns "Chris'" */ Possessive(): TransformerFunctionExpr; /** * Extracts a substring from start to end position * @param start - The zero-based index at which to begin extraction * @param end - The zero-based index before which to end extraction (optional) * @example * // Substring(1, 4) applied to "hello" returns "ell" */ Substring(start: Resolvable, end?: Resolvable): TransformerFunctionExpr; /** * Replaces all occurrences of a search string with a replacement string * @param searchValue - The string to search for * @param replaceValue - The string to replace matches with * @example * // Replace("world", "universe") applied to "hello world" returns "hello universe" */ Replace(searchValue: Resolvable, replaceValue: Resolvable): TransformerFunctionExpr; /** * Pads the string to a specified length with a given string on the left * @param targetLength - The length the string should be padded to * @param padString - The string to pad with (defaults to a single space) * @example * // PadStart(3) applied to "5" returns " 5" */ PadStart(targetLength: Resolvable, padString?: Resolvable): TransformerFunctionExpr; /** * Pads the string to a specified length with a given string on the right * @param targetLength - The length the string should be padded to * @param padString - The string to pad with (defaults to a single space) * @example * // PadEnd(3) applied to "5" returns "5 " */ PadEnd(targetLength: Resolvable, padString?: Resolvable): TransformerFunctionExpr; /** * Converts a string to an integer * Throws on invalid input so the pipeline errors and the original value is preserved. * @example * // ToInt() on "123" returns 123 * // ToInt() on "123.45" returns 123 (truncated) * // ToInt() on " 123 " returns 123 * // ToInt() on "" throws Error * // ToInt() on "abc" throws Error * // ToInt() on "123abc" throws Error (partial parse rejected) */ ToInt(): TransformerFunctionExpr; /** * Converts a string to a floating-point number * Throws on invalid input so the pipeline errors and the original value is preserved. * @example * // ToFloat() on "123.45" returns 123.45 * // ToFloat() on "3.14159" returns 3.14159 * // ToFloat() on " 123.45 " returns 123.45 * // ToFloat() on "" throws Error * // ToFloat() on "abc" throws Error * // ToFloat() on "123abc" throws Error (partial parse rejected) */ ToFloat(): TransformerFunctionExpr; /** * Splits a string into an array of characters or by a separator * @param separator - Optional separator string; if omitted, splits into individual characters * @example * // ToArray() on "hello" returns ["h", "e", "l", "l", "o"] * // ToArray(",") on "hello,world" returns ["hello", "world"] * // ToArray("-") on "a-b-c" returns ["a", "b", "c"] */ ToArray(separator?: Resolvable): TransformerFunctionExpr; /** * Converts a date string to a Date object (local time). * Supports both UK format (DD/MM/YYYY) and ISO-8601 format (YYYY-MM-DD or full ISO with time/timezone). * Throws on invalid input so the pipeline errors and the original value is preserved. * * @example * // ToDate() on "15/03/2024" returns 2024-03-15T00:00:00 local * // ToDate() on "15-03-2024" returns 2024-03-15T00:00:00 local * // ToDate() on "2024-03-15" returns 2024-03-15T00:00:00 local * // ToDate() on "2024-03-15T14:30:00Z" returns a Date object with time * // ToDate() on "" throws Error */ ToDate(): TransformerFunctionExpr; /** * Formats a date string using Intl.DateTimeFormat options. * Defaults to UK long date formatting when no options are supplied. * * @param options - Intl.DateTimeFormat options plus optional locale, which defaults to en-GB * @example * // FormatDate() on "2024-03-15" returns "15 March 2024" * // FormatDate({ dateStyle: 'short' }) on "2024-03-15" returns "15/03/2024" * // FormatDate({ locale: 'en-US', dateStyle: 'long' }) on "2024-03-15" returns "March 15, 2024" */ FormatDate(options?: Resolvable | undefined>): TransformerFunctionExpr; /** * Converts a UK-formatted date string (DD/MM/YYYY) to ISO-8601 format (YYYY-MM-DD). * Throws on invalid input so the pipeline errors and the original value is preserved. * * Use this with MOJ Date Picker which outputs UK format dates. * @example * // ToISODate() on "15/03/2024" returns "2024-03-15" * // ToISODate() on "5/3/2024" returns "2024-03-05" * // ToISODate() on "15-03-2024" returns "2024-03-15" * // ToISODate() on "" throws Error * // ToISODate() on "31/02/2024" throws Error (invalid date) */ ToISODate(): TransformerFunctionExpr; /** * Converts an epoch millisecond date string to a Date (local time). * Throws on invalid input so the pipeline errors and the original value is preserved. * * @example * // ToTimestampDate() on "1771429146000" returns 2026-02-18T15:39:06 local * // ToTimestampDate() on "" throws Error */ ToTimestampDate(): TransformerFunctionExpr; /** * Escapes HTML entities in a string to prevent XSS attacks. * Use this when piping untrusted data (user input, external API data) into HTML contexts. * * Converts: < > & " ' to their HTML entity equivalents. * * @example * // EscapeHtml() on '">' returns '"><img src=x onerror=alert(1)>' * // Usage: Data('goalTitle').pipe(Transformer.String.EscapeHtml()) */ EscapeHtml(): TransformerFunctionExpr; }; //#endregion //#region forge-core/src/built-ins/functions/transformers/index.d.ts interface TransformerGroups { /** Transformers for handling strings */ String: typeof StringTransformers; /** Transformers for handling numbers */ Number: typeof NumberTransformers; /** Transformers for handling arrays */ Array: typeof ArrayTransformers; /** Transformers for handling objects */ Object: typeof ObjectTransformers; /** Transformers for handling dates */ Date: typeof DateTransformers; } declare const Transformer: TransformerGroups; declare const TransformersRegistry: { [x: string]: FunctionRegistryEntry; }; //#endregion //#region forge-core/src/authoring/registries/EffectRegistry.d.ts declare class EffectRegistry> extends BaseFunctionRegistry { constructor(); register(name: string, options: RegistrationOptions & { factory: (deps: TDeps) => (context: any, ...args: TArgs) => any; }): (...args: { [K in keyof TArgs]: Resolvable; }) => EffectFunctionExpr; register(name: string, options: RegistrationOptions, factory: (deps: TDeps) => (context: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => EffectFunctionExpr; register(name: string, factory: (deps: TDeps) => (context: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => EffectFunctionExpr; register(options: RegistrationOptions, factory: (deps: TDeps) => (context: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => EffectFunctionExpr; register(factory: (deps: TDeps) => (context: any, ...args: TArgs) => any): (...args: { [K in keyof TArgs]: Resolvable; }) => EffectFunctionExpr; } //#endregion //#region forge-core/src/authoring/utils/deprecated/createFunctionsRegistry.d.ts /** * Resolves function factory entries into a registry of ready-to-call evaluators. * * Each entry can be a plain factory function (back-compat) or an object with * `{ factory, functionType?, prepare? }`. The registry decomposes each entry, * calls the factory with `deps` to produce an evaluator, and preserves its * `functionType` metadata for the engine to use at runtime. * * @deprecated Use BaseFunctionRegistry.build() instead. * * @param implementations - Object mapping function names to factory entries * @param deps - Dependencies to inject into each factory (omit if none needed) * * @returns A registry object mapping function names to `{ name, evaluate, functionType? }` */ declare function createFunctionsRegistry(implementations: FunctionImplementations): FunctionRegistryObject; declare function createFunctionsRegistry(implementations: FunctionImplementations, deps: TDeps): FunctionRegistryObject; //#endregion //#region forge-core/src/authoring/utils/deprecated/defineConditionFunctions.d.ts /** * Creates condition functions with dependency injection from factory functions. * * This separates builder creation from registry creation: * - `conditions`: Available immediately for use in form definitions (no deps needed) * - `implementations`: Passed to `createFunctionsRegistry` at runtime with real dependencies * * Each condition factory receives dependencies and returns an evaluator function. * The evaluator's first parameter (`value`) is injected by the engine at runtime - * the returned `conditions` builders only expose the remaining configuration arguments. * * @deprecated Use ConditionRegistry instead. * * @param factories - Condition factories keyed by function name * * @returns Object containing condition builders and implementations * * @example * const { conditions, implementations } = defineConditionFunctions({ * IsPositive: () => (value: unknown) => Number(value) > 0, * GreaterThan: () => (value: unknown, threshold: number) => Number(value) > threshold, * }) * * // Use in form definitions (no deps needed) * conditions.GreaterThan(10) // { type: 'condition', name: 'GreaterThan', arguments: [10] } * * // Create registry at runtime * const registry = createFunctionsRegistry(implementations) */ declare function defineConditionFunctions(factories: FunctionImplementations): { conditions: ConditionFunctions; implementations: FunctionImplementations; }; declare function defineConditionFunctions, TDeps = NoDeps>(factories: ConditionImplementations): { conditions: TConditions; implementations: FunctionImplementations, TDeps>; }; //#endregion //#region forge-core/src/authoring/utils/deprecated/defineEffectFunctions.d.ts /** * Creates effect functions with dependency injection from factory functions. * * This separates builder creation from registry creation: * - `effects`: Available immediately for use in form definitions (no deps needed) * - `implementations`: Passed to `createFunctionsRegistry` at runtime with real dependencies * * Each effect factory receives dependencies and returns an evaluator function. * The evaluator's first parameter (`context: EffectFunctionContext`) is injected * by the engine at runtime - the returned `effects` builders only expose the * remaining configuration arguments. * * @deprecated Use EffectRegistry instead. * * @param factories - Effect factories keyed by function name * * @returns Object containing effect builders and implementations * * @example * const { effects, implementations } = defineEffectFunctions< * { LogAction: (context: EffectFunctionContext, action: string) => void }, * { logger: Logger } * >({ * LogAction: (deps) => (context, action) => deps.logger.info(action), * }) * * // Use in form definitions * effects.LogAction('SUBMIT') // { type: 'effect', name: 'LogAction', arguments: ['SUBMIT'] } * * // Create registry at runtime * const registry = createFunctionsRegistry(implementations, { logger }) */ declare function defineEffectFunctions(factories: FunctionImplementations): { effects: EffectFunctions; implementations: FunctionImplementations; }; declare function defineEffectFunctions, TDeps = NoDeps>(factories: EffectImplementations): { effects: TEffects; implementations: FunctionImplementations, TDeps>; }; //#endregion //#region forge-core/src/authoring/utils/deprecated/defineGeneratorFunctions.d.ts /** * Creates generator functions with dependency injection from factory functions. * * This separates builder creation from registry creation: * - `generators`: Available immediately for use in form definitions (no deps needed) * - `implementations`: Passed to `createFunctionsRegistry` at runtime with real dependencies * * Unlike conditions, transformers, and effects, generators do not receive a runtime * `value` or `context` parameter - their evaluators are called directly with just * the configuration arguments. The returned builders create `GeneratorBuilder` instances * that support chaining via `.pipe()`. * * Each factory entry can be a plain factory function or `{ prepare?, factory }`. When * `prepare` is provided, it runs synchronously when the author calls the builder — * sanitising/reshaping arguments before they enter the expression tree, and/or * throwing to reject invalid arguments at module-load time rather than at render time. * * @deprecated Use GeneratorRegistry instead. * * @param factories - Generator factories keyed by function name * * @returns Object containing generator builders and implementations * * @example * const { generators, implementations } = defineGeneratorFunctions({ * Today: () => () => new Date().toISOString().split('T')[0], * PrefixedId: () => (prefix: string) => `${prefix}${crypto.randomUUID()}`, * }) * * // With author-time preparation: * const { generators } = defineGeneratorFunctions<{ Slug: (input: string) => string }>({ * Slug: { * prepare: (input) => { * if (!input) throw new Error('input required') * return [input] * }, * factory: () => (input) => input.toLowerCase().replace(/\s+/g, '-'), * }, * }) * * // Use in form definitions (returns GeneratorBuilder for chaining) * generators.PrefixedId('user-').pipe(transformers.ToUpperCase()) * * // Create registry at runtime * const registry = createFunctionsRegistry(implementations) */ declare function defineGeneratorFunctions(factories: FunctionImplementations): { generators: GeneratorFunctions; implementations: FunctionImplementations; }; declare function defineGeneratorFunctions, TDeps = NoDeps>(factories: GeneratorImplementations): { generators: TGenerators; implementations: FunctionImplementations, TDeps>; }; //#endregion //#region forge-core/src/authoring/utils/deprecated/defineTransformerFunctions.d.ts /** * Creates transformer functions with dependency injection from factory functions. * * This separates builder creation from registry creation: * - `transformers`: Available immediately for use in form definitions (no deps needed) * - `implementations`: Passed to `createFunctionsRegistry` at runtime with real dependencies * * Each transformer factory receives dependencies and returns an evaluator function. * The evaluator's first parameter (`value`) is injected by the engine at runtime - * the returned `transformers` builders only expose the remaining configuration arguments. * * @deprecated Use TransformerRegistry instead. * * @param factories - Transformer factories keyed by function name * * @returns Object containing transformer builders and implementations * * @example * const { transformers, implementations } = defineTransformerFunctions({ * AddPrefix: () => (value: unknown, prefix: string) => `${prefix}${String(value)}`, * }) * * // Use in form definitions * transformers.AddPrefix('Mr ') // { type: 'transformer', name: 'AddPrefix', arguments: ['Mr '] } * * // Create registry at runtime * const registry = createFunctionsRegistry(implementations) */ declare function defineTransformerFunctions(factories: FunctionImplementations): { transformers: TransformerFunctions; implementations: FunctionImplementations; }; declare function defineTransformerFunctions, TDeps = NoDeps>(factories: TransformerImplementations): { transformers: TTransformers; implementations: FunctionImplementations, TDeps>; }; //#endregion //#region forge-core/src/authoring/utils/deprecated/createFunctionScope.d.ts type ScopedConditionFactory = (deps: TDeps) => (value: TValue, ...args: TArgs) => boolean | Promise; type ScopedTransformerFactory = (deps: TDeps) => (value: TValue, ...args: TArgs) => unknown; type ScopedEffectFactory = (deps: TDeps) => (context: TContext, ...args: TArgs) => void | Promise; type ScopedGeneratorFactory = (deps: TDeps) => (...args: TArgs) => unknown; /** * Package-local collector for inline function definitions. * * Each method stores the dependency-injected factory in `implementations` and * returns the normal Forge expression used by journeys, steps, blocks, and hooks. * * @deprecated Use ConditionRegistry/TransformerRegistry/EffectRegistry/GeneratorRegistry inline instead. */ interface FunctionScope { readonly implementations: FunctionImplementations; condition(name: string, factory: ScopedConditionFactory, ...args: TArgs): ConditionFunctionExpr; transformer(name: string, factory: ScopedTransformerFactory, ...args: TArgs): TransformerFunctionExpr; effect(name: string, factory: ScopedEffectFactory, ...args: TArgs): EffectFunctionExpr; generator(name: string, factory: ScopedGeneratorFactory, ...args: TArgs): ChainableGenerator; } /** * Create a package-local function scope for one-off authoring functions. * * Pass `scope.implementations` into `createForgePackage({ functions })` so the * collected factories receive the same runtime dependencies as regular * `defineEffectFunctions` and `defineTransformerFunctions` implementations. * * @deprecated Use ConditionRegistry/TransformerRegistry/EffectRegistry/GeneratorRegistry inline instead. */ declare function createFunctionScope(): FunctionScope; //#endregion export { type AccessHook, Answer, BaseFunctionRegistry, BlockType, type BranchValue, type ChainableConditional, type ChainableExpr, type ChainableGenerator, type ChainableIterable, type ChainableLoopRef, type ChainableMatch, type ChainableNegation, type ChainableRef, type ChainableScopedRef, Condition, ConditionCombinatorType, type ConditionFunctionExpr, ConditionRegistry, Conditional, type ConditionalExpr, ConditionsRegistry, Data, EffectFunctionContext, type EffectFunctionExpr, EffectRegistry, ExpressionType, type ForgePackage, Format, type FunctionEvaluator, type FunctionExpr, type FunctionImplementations, type FunctionRegistryEntry, type FunctionRegistryObject, type FunctionScope, type FunctionShapeMap, FunctionType, Generator, type GeneratorFunctionExpr, GeneratorRegistry, GeneratorsRegistry, Item, type IterateExpr, Iterator, type JourneyDefinition, type JourneyReachability, Literal, Loop, type MatchExpr, Params, type PipelineExpr, Post, type PredicateExpr, Query, type RedirectOutcome, type ReferenceExpr, type RegisteredForgePackage, Request, type Resolvable, type ResolvableExpression, type ResolvableValue, Self, Session, type StepDefinition, type StepReachability, StructureType, type SubmitHook, type ThrowErrorOutcome, type TieBreaker, type TieBreakerProps, Transformer, type TransformerFunctionExpr, TransformerRegistry, TransformersRegistry, type UnreachableRedirectTarget, type ValidationExpr, type ValidationProps, type ViewConfig, access, and, block, createForgePackage, createFunctionScope, createFunctionsRegistry, defineConditionFunctions, defineEffectFunctions, defineGeneratorFunctions, defineTransformerFunctions, field, journey, match, not, or, redirect, step, submit, throwError, tieBreaker, validation, when, xor };