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