@fogpipe/forma-core 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-IRLYWN3R.js → chunk-VHKUCCAC.js} +13 -1
- package/dist/{chunk-IRLYWN3R.js.map → chunk-VHKUCCAC.js.map} +1 -1
- package/dist/engine/calculate.d.ts +64 -0
- package/dist/engine/calculate.d.ts.map +1 -0
- package/dist/engine/enabled.d.ts +40 -0
- package/dist/engine/enabled.d.ts.map +1 -0
- package/dist/engine/index.cjs +12 -0
- package/dist/engine/index.cjs.map +1 -1
- package/dist/engine/index.d.ts +12 -255
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +1 -1
- package/dist/engine/required.d.ts +45 -0
- package/dist/engine/required.d.ts.map +1 -0
- package/dist/engine/validate.d.ts +59 -0
- package/dist/engine/validate.d.ts.map +1 -0
- package/dist/engine/visibility.d.ts +52 -0
- package/dist/engine/visibility.d.ts.map +1 -0
- package/dist/feel/index.d.ts +12 -15
- package/dist/feel/index.d.ts.map +1 -0
- package/dist/index.cjs +12 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{types-Bs3CG9JZ.d.cts → types.d.ts} +31 -30
- package/dist/types.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/__tests__/validate.test.ts +278 -0
- package/src/engine/validate.ts +14 -0
- package/src/index.ts +36 -2
- package/src/types.ts +2 -0
- package/dist/engine/index.d.cts +0 -258
- package/dist/feel/index.d.cts +0 -105
- package/dist/index.d.cts +0 -3
- package/dist/types-Bs3CG9JZ.d.ts +0 -283
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/feel/index.ts","../src/engine/calculate.ts","../src/engine/visibility.ts","../src/engine/required.ts","../src/engine/enabled.ts","../src/engine/validate.ts"],"sourcesContent":["/**\n * @fogpipe/forma-core\n *\n * Core runtime for Forma dynamic forms.\n * Provides types, FEEL expression evaluation, and form state engines.\n */\n\n// Types\nexport * from \"./types.js\";\n\n// FEEL expression evaluation\nexport * from \"./feel/index.js\";\n\n// Form state engines\nexport * from \"./engine/index.js\";\n","/**\n * FEEL Expression Evaluator\n *\n * Wraps the feelin library to provide FEEL expression evaluation\n * with Forma context conventions.\n *\n * Context variable conventions:\n * - `fieldName` - Direct field value access\n * - `computed.name` - Computed value access\n * - `ref.path` - Reference data lookup (external lookup tables)\n * - `item.fieldName` - Array item field access (within array context)\n * - `itemIndex` - Current array item index (0-based)\n * - `value` - Current field value (in validation expressions)\n */\n\nimport { evaluate as feelinEvaluate } from \"feelin\";\nimport type { EvaluationContext, FEELExpression } from \"../types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EvaluateResult<T = unknown> {\n success: true;\n value: T;\n}\n\nexport interface EvaluateError {\n success: false;\n error: string;\n expression: string;\n}\n\nexport type EvaluationOutcome<T = unknown> = EvaluateResult<T> | EvaluateError;\n\n// ============================================================================\n// Context Building\n// ============================================================================\n\n/**\n * Build the FEEL evaluation context from our EvaluationContext\n *\n * Maps our context conventions to feelin context format:\n * - Form data fields are spread directly\n * - computed becomes an object (accessed as computed.fieldName)\n * - ref becomes an object for reference data (accessed as ref.path.to.data)\n * - item becomes an object for array context (accessed as item.fieldName)\n * - itemIndex is a number for array context\n * - value is the current field value\n */\nfunction buildFeelContext(ctx: EvaluationContext): Record<string, unknown> {\n const feelContext: Record<string, unknown> = {\n // Spread form data directly so fields are accessible by name\n ...ctx.data,\n };\n\n // Add computed values under 'computed' (accessed as computed.fieldName)\n if (ctx.computed) {\n feelContext[\"computed\"] = ctx.computed;\n }\n\n // Add reference data under 'ref' (accessed as ref.path.to.data)\n if (ctx.referenceData) {\n feelContext[\"ref\"] = ctx.referenceData;\n }\n\n // Add array item context (accessed as item.fieldName)\n if (ctx.item !== undefined) {\n feelContext[\"item\"] = ctx.item;\n }\n\n // Add array index\n if (ctx.itemIndex !== undefined) {\n feelContext[\"itemIndex\"] = ctx.itemIndex;\n }\n\n // Add current field value for validation expressions\n if (ctx.value !== undefined) {\n feelContext[\"value\"] = ctx.value;\n }\n\n return feelContext;\n}\n\n// ============================================================================\n// Expression Evaluation\n// ============================================================================\n\n/**\n * Evaluate a FEEL expression and return the result\n *\n * @param expression - FEEL expression string\n * @param context - Evaluation context with form data, computed values, etc.\n * @returns Evaluation outcome with success/value or error\n *\n * @example\n * // Simple field comparison\n * evaluate(\"age >= 18\", { data: { age: 21 } })\n * // => { success: true, value: true }\n *\n * @example\n * // Computed value reference\n * evaluate(\"computed.bmi > 30\", { data: {}, computed: { bmi: 32.5 } })\n * // => { success: true, value: true }\n *\n * @example\n * // Array item context\n * evaluate(\"item.frequency = \\\"daily\\\"\", { data: {}, item: { frequency: \"daily\" } })\n * // => { success: true, value: true }\n */\nexport function evaluate<T = unknown>(\n expression: FEELExpression,\n context: EvaluationContext\n): EvaluationOutcome<T> {\n try {\n const feelContext = buildFeelContext(context);\n const result = feelinEvaluate(expression, feelContext);\n return {\n success: true,\n value: result as T,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n expression,\n };\n }\n}\n\n/**\n * Evaluate a FEEL expression expecting a boolean result\n *\n * Used for visibility, required, and enabled conditions.\n * Returns false on error or non-boolean result for safety.\n *\n * @param expression - FEEL expression that should return boolean\n * @param context - Evaluation context\n * @returns Boolean result (false on error)\n */\nexport function evaluateBoolean(\n expression: FEELExpression,\n context: EvaluationContext\n): boolean {\n const result = evaluate<boolean>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return false;\n }\n\n // FEEL uses three-valued logic where comparisons with null return null.\n // For form visibility/required/enabled conditions, we treat null as false.\n if (result.value === null || result.value === undefined) {\n return false;\n }\n\n if (typeof result.value !== \"boolean\") {\n console.warn(\n `FEEL expression did not return boolean: ${expression}\\nGot: ${typeof result.value}`\n );\n return false;\n }\n\n return result.value;\n}\n\n/**\n * Evaluate a FEEL expression expecting a numeric result\n *\n * Used for computed values that return numbers.\n *\n * @param expression - FEEL expression that should return number\n * @param context - Evaluation context\n * @returns Numeric result or null on error\n */\nexport function evaluateNumber(\n expression: FEELExpression,\n context: EvaluationContext\n): number | null {\n const result = evaluate<number>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return null;\n }\n\n if (typeof result.value !== \"number\") {\n console.warn(\n `FEEL expression did not return number: ${expression}\\nGot: ${typeof result.value}`\n );\n return null;\n }\n\n return result.value;\n}\n\n/**\n * Evaluate a FEEL expression expecting a string result\n *\n * @param expression - FEEL expression that should return string\n * @param context - Evaluation context\n * @returns String result or null on error\n */\nexport function evaluateString(\n expression: FEELExpression,\n context: EvaluationContext\n): string | null {\n const result = evaluate<string>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return null;\n }\n\n if (typeof result.value !== \"string\") {\n console.warn(\n `FEEL expression did not return string: ${expression}\\nGot: ${typeof result.value}`\n );\n return null;\n }\n\n return result.value;\n}\n\n// ============================================================================\n// Batch Evaluation\n// ============================================================================\n\n/**\n * Evaluate multiple FEEL expressions at once\n *\n * Useful for evaluating all visibility conditions in a form.\n *\n * @param expressions - Map of field names to FEEL expressions\n * @param context - Evaluation context\n * @returns Map of field names to boolean results\n */\nexport function evaluateBooleanBatch(\n expressions: Record<string, FEELExpression>,\n context: EvaluationContext\n): Record<string, boolean> {\n const results: Record<string, boolean> = {};\n\n for (const [key, expression] of Object.entries(expressions)) {\n results[key] = evaluateBoolean(expression, context);\n }\n\n return results;\n}\n\n// ============================================================================\n// Expression Validation\n// ============================================================================\n\n/**\n * Check if a FEEL expression is syntactically valid\n *\n * @param expression - FEEL expression to validate\n * @returns True if the expression can be parsed\n */\nexport function isValidExpression(expression: FEELExpression): boolean {\n try {\n // Try to evaluate with empty context - we just want to check parsing\n feelinEvaluate(expression, {});\n return true;\n } catch {\n // Expression failed to parse or evaluate\n return false;\n }\n}\n\n/**\n * Validate a FEEL expression and return any parsing errors\n *\n * @param expression - FEEL expression to validate\n * @returns Null if valid, error message if invalid\n */\nexport function validateExpression(expression: FEELExpression): string | null {\n try {\n // Evaluate with minimal context to catch parse errors\n feelinEvaluate(expression, {});\n return null;\n } catch (error) {\n // Only return actual parsing errors, not runtime errors\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"parse\") || message.includes(\"syntax\")) {\n return message;\n }\n // Runtime errors (missing variables, etc.) are OK for validation\n return null;\n }\n}\n","/**\n * Calculation Engine\n *\n * Evaluates computed fields based on form data.\n * Computed values are derived from form data using FEEL expressions.\n */\n\nimport { evaluate } from \"../feel/index.js\";\nimport type {\n Forma,\n ComputedField,\n EvaluationContext,\n CalculationResult,\n CalculationError,\n} from \"../types.js\";\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Calculate all computed values from form data\n *\n * Evaluates each computed field's FEEL expression and returns the results.\n * Errors are collected rather than thrown, allowing partial results.\n *\n * @param data - Current form data\n * @param spec - Form specification with computed fields\n * @returns Computed values and any calculation errors\n *\n * @example\n * const spec = {\n * computed: {\n * bmi: {\n * expression: \"weight / (height / 100) ** 2\",\n * label: \"BMI\",\n * format: \"decimal(1)\"\n * },\n * isObese: {\n * expression: \"$computed.bmi >= 30\"\n * }\n * }\n * };\n *\n * const result = calculate({ weight: 85, height: 175 }, spec);\n * // => { values: { bmi: 27.76, isObese: false }, errors: [] }\n */\nexport function calculate(\n data: Record<string, unknown>,\n spec: Forma\n): Record<string, unknown> {\n const result = calculateWithErrors(data, spec);\n return result.values;\n}\n\n/**\n * Calculate computed values with error reporting\n *\n * Same as calculate() but also returns any errors that occurred.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Values and errors\n */\nexport function calculateWithErrors(\n data: Record<string, unknown>,\n spec: Forma\n): CalculationResult {\n if (!spec.computed) {\n return { values: {}, errors: [] };\n }\n\n const values: Record<string, unknown> = {};\n const errors: CalculationError[] = [];\n\n // Get computation order (handles dependencies)\n const orderedFields = getComputationOrder(spec.computed);\n\n // Evaluate each computed field in dependency order\n for (const fieldName of orderedFields) {\n const fieldDef = spec.computed[fieldName];\n if (!fieldDef) continue;\n\n const result = evaluateComputedField(\n fieldName,\n fieldDef,\n data,\n values, // Pass already-computed values for dependencies\n spec.referenceData // Pass reference data for lookups\n );\n\n if (result.success) {\n values[fieldName] = result.value;\n } else {\n errors.push({\n field: fieldName,\n message: result.error,\n expression: fieldDef.expression,\n });\n // Set to null so dependent fields can still evaluate\n values[fieldName] = null;\n }\n }\n\n return { values, errors };\n}\n\n// ============================================================================\n// Field Evaluation\n// ============================================================================\n\ninterface ComputeSuccess {\n success: true;\n value: unknown;\n}\n\ninterface ComputeFailure {\n success: false;\n error: string;\n}\n\ntype ComputeResult = ComputeSuccess | ComputeFailure;\n\n/**\n * Evaluate a single computed field\n */\nfunction evaluateComputedField(\n _name: string,\n fieldDef: ComputedField,\n data: Record<string, unknown>,\n computedSoFar: Record<string, unknown>,\n referenceData?: Record<string, unknown>\n): ComputeResult {\n // Check if any referenced computed field is null - propagate null to dependents\n // This prevents issues like: bmi is null, but bmiCategory still evaluates to \"obese\"\n // because `null < 18.5` is false in comparisons\n const referencedComputed = findComputedReferences(fieldDef.expression);\n for (const ref of referencedComputed) {\n if (computedSoFar[ref] === null) {\n return {\n success: true,\n value: null,\n };\n }\n }\n\n const context: EvaluationContext = {\n data,\n computed: computedSoFar,\n referenceData,\n };\n\n const result = evaluate(fieldDef.expression, context);\n\n if (!result.success) {\n return {\n success: false,\n error: result.error,\n };\n }\n\n // Treat NaN and Infinity as null - prevents unexpected behavior in conditional expressions\n // (e.g., NaN < 18.5 is false, causing fallthrough in if-else chains)\n if (typeof result.value === \"number\" && (!Number.isFinite(result.value))) {\n return {\n success: true,\n value: null,\n };\n }\n\n return {\n success: true,\n value: result.value,\n };\n}\n\n/**\n * Find computed field references in an expression (e.g., computed.bmi)\n */\nfunction findComputedReferences(expression: string): string[] {\n const refs: string[] = [];\n const regex = /computed\\.(\\w+)/g;\n let match;\n while ((match = regex.exec(expression)) !== null) {\n refs.push(match[1]);\n }\n return refs;\n}\n\n// ============================================================================\n// Dependency Resolution\n// ============================================================================\n\n/**\n * Determine the order to evaluate computed fields based on dependencies\n *\n * Computed fields can reference other computed fields via $computed.name.\n * This function performs topological sort to ensure dependencies are\n * evaluated first.\n */\nfunction getComputationOrder(\n computed: Record<string, ComputedField>\n): string[] {\n const fieldNames = Object.keys(computed);\n\n // Build dependency graph\n const deps = new Map<string, Set<string>>();\n for (const name of fieldNames) {\n deps.set(name, findComputedDependencies(computed[name].expression, fieldNames));\n }\n\n // Topological sort\n const sorted: string[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n function visit(name: string): void {\n if (visited.has(name)) return;\n if (visiting.has(name)) {\n // Circular dependency - just add it and let evaluation fail gracefully\n console.warn(`Circular dependency detected in computed field: ${name}`);\n sorted.push(name);\n visited.add(name);\n return;\n }\n\n visiting.add(name);\n\n const fieldDeps = deps.get(name) ?? new Set();\n for (const dep of fieldDeps) {\n visit(dep);\n }\n\n visiting.delete(name);\n visited.add(name);\n sorted.push(name);\n }\n\n for (const name of fieldNames) {\n visit(name);\n }\n\n return sorted;\n}\n\n/**\n * Find which computed fields are referenced in an expression\n */\nfunction findComputedDependencies(\n expression: string,\n availableFields: string[]\n): Set<string> {\n const deps = new Set<string>();\n\n // Look for computed.fieldName patterns (without $ prefix)\n const regex = /computed\\.(\\w+)/g;\n let match;\n while ((match = regex.exec(expression)) !== null) {\n const fieldName = match[1];\n if (availableFields.includes(fieldName)) {\n deps.add(fieldName);\n }\n }\n\n return deps;\n}\n\n// ============================================================================\n// Formatted Output\n// ============================================================================\n\n/**\n * Get a computed value formatted according to its format specification\n *\n * @param fieldName - Name of the computed field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Formatted string or null if not displayable\n */\nexport function getFormattedValue(\n fieldName: string,\n data: Record<string, unknown>,\n spec: Forma\n): string | null {\n if (!spec.computed?.[fieldName]) {\n return null;\n }\n\n const fieldDef = spec.computed[fieldName];\n const computed = calculate(data, spec);\n const value = computed[fieldName];\n\n if (value === null || value === undefined) {\n return null;\n }\n\n return formatValue(value, fieldDef.format);\n}\n\n/**\n * Format a value according to a format specification\n *\n * Supported formats:\n * - decimal(n) - Number with n decimal places\n * - currency - Number formatted as currency\n * - percent - Number formatted as percentage\n * - (none) - Default string conversion\n */\nfunction formatValue(value: unknown, format?: string): string {\n if (!format) {\n return String(value);\n }\n\n // Handle decimal(n) format\n const decimalMatch = format.match(/^decimal\\((\\d+)\\)$/);\n if (decimalMatch) {\n const decimals = parseInt(decimalMatch[1], 10);\n return typeof value === \"number\" ? value.toFixed(decimals) : String(value);\n }\n\n // Handle currency format\n if (format === \"currency\") {\n return typeof value === \"number\"\n ? new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(value)\n : String(value);\n }\n\n // Handle percent format\n if (format === \"percent\") {\n return typeof value === \"number\"\n ? new Intl.NumberFormat(\"en-US\", {\n style: \"percent\",\n minimumFractionDigits: 1,\n }).format(value)\n : String(value);\n }\n\n return String(value);\n}\n\n// ============================================================================\n// Single Field Calculation\n// ============================================================================\n\n/**\n * Calculate a single computed field\n *\n * @param fieldName - Name of the computed field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Computed value or null if calculation failed\n */\nexport function calculateField(\n fieldName: string,\n data: Record<string, unknown>,\n spec: Forma\n): unknown {\n const computed = calculate(data, spec);\n return computed[fieldName] ?? null;\n}\n","/**\n * Visibility Engine\n *\n * Determines which fields should be visible based on form data\n * and Forma visibility rules.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n VisibilityResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface VisibilityOptions {\n /** Pre-calculated computed values (avoids recalculation) */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine visibility for all fields in a form\n *\n * Returns a map of field paths to boolean visibility states.\n * Fields without visibleWhen expressions are always visible.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to visibility states\n *\n * @example\n * const visibility = getVisibility(\n * { age: 21, hasLicense: true },\n * forma\n * );\n * // => { age: true, hasLicense: true, vehicleType: true, ... }\n */\nexport function getVisibility(\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): VisibilityResult {\n // Calculate computed values if not provided\n const computed = options.computed ?? calculate(data, spec);\n\n // Build base evaluation context\n const baseContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: VisibilityResult = {};\n\n // Process all fields in field order\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n evaluateFieldVisibility(fieldPath, fieldDef, data, baseContext, result);\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Evaluation\n// ============================================================================\n\n/**\n * Evaluate visibility for a single field and its nested fields\n */\nfunction evaluateFieldVisibility(\n path: string,\n fieldDef: FieldDefinition,\n data: Record<string, unknown>,\n context: EvaluationContext,\n result: VisibilityResult\n): void {\n // Evaluate the field's own visibility\n if (fieldDef.visibleWhen) {\n result[path] = evaluateBoolean(fieldDef.visibleWhen, context);\n } else {\n result[path] = true; // No condition = always visible\n }\n\n // If not visible, children are implicitly not visible\n if (!result[path]) {\n return;\n }\n\n // Handle array fields with item visibility\n if (fieldDef.itemFields) {\n const arrayData = data[path];\n if (Array.isArray(arrayData)) {\n evaluateArrayItemVisibility(path, fieldDef, arrayData, context, result);\n }\n }\n}\n\n/**\n * Evaluate visibility for array item fields\n *\n * For each item in the array, evaluates the visibility of each\n * item field using the $item context.\n */\nfunction evaluateArrayItemVisibility(\n arrayPath: string,\n fieldDef: FieldDefinition,\n arrayData: unknown[],\n baseContext: EvaluationContext,\n result: VisibilityResult\n): void {\n if (!fieldDef.itemFields) return;\n\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n\n // Create item-specific context\n const itemContext: EvaluationContext = {\n ...baseContext,\n item,\n itemIndex: i,\n };\n\n // Evaluate each item field's visibility\n for (const [fieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${arrayPath}[${i}].${fieldName}`;\n\n if (itemFieldDef.visibleWhen) {\n result[itemFieldPath] = evaluateBoolean(itemFieldDef.visibleWhen, itemContext);\n } else {\n result[itemFieldPath] = true;\n }\n }\n }\n}\n\n// ============================================================================\n// Individual Field Visibility\n// ============================================================================\n\n/**\n * Check if a single field is visible\n *\n * Useful for checking visibility of one field without computing all.\n *\n * @param fieldPath - Field path to check\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns True if the field is visible\n */\nexport function isFieldVisible(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return true; // Unknown fields are visible by default\n }\n\n if (!fieldDef.visibleWhen) {\n return true; // No condition = always visible\n }\n\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return evaluateBoolean(fieldDef.visibleWhen, context);\n}\n\n// ============================================================================\n// Page Visibility\n// ============================================================================\n\n/**\n * Determine which pages are visible in a wizard form\n *\n * @param data - Current form data\n * @param spec - Form specification with pages\n * @param options - Optional pre-calculated computed values\n * @returns Map of page IDs to visibility states\n */\nexport function getPageVisibility(\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): Record<string, boolean> {\n if (!spec.pages) {\n return {};\n }\n\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: Record<string, boolean> = {};\n\n for (const page of spec.pages) {\n if (page.visibleWhen) {\n result[page.id] = evaluateBoolean(page.visibleWhen, context);\n } else {\n result[page.id] = true;\n }\n }\n\n return result;\n}\n","/**\n * Required Fields Engine\n *\n * Determines which fields are currently required based on\n * conditional requiredWhen expressions and schema required array.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n RequiredFieldsResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RequiredOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine which fields are currently required\n *\n * Returns a map of field paths to boolean required states.\n * Evaluates requiredWhen expressions for conditional requirements.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to required states\n *\n * @example\n * const required = getRequired(\n * { hasInsurance: true },\n * forma\n * );\n * // => { hasInsurance: true, insuranceProvider: true, policyNumber: true }\n */\nexport function getRequired(\n data: Record<string, unknown>,\n spec: Forma,\n options: RequiredOptions = {}\n): RequiredFieldsResult {\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: RequiredFieldsResult = {};\n\n // Evaluate each field's required status\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n result[fieldPath] = isFieldRequired(fieldPath, fieldDef, spec, context);\n }\n }\n\n // Also check array item fields\n for (const [fieldPath, fieldDef] of Object.entries(spec.fields)) {\n if (fieldDef.itemFields) {\n const arrayData = data[fieldPath];\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n const itemContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: i,\n };\n\n for (const [itemFieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${fieldPath}[${i}].${itemFieldName}`;\n result[itemFieldPath] = isFieldRequired(\n itemFieldPath,\n itemFieldDef,\n spec,\n itemContext\n );\n }\n }\n }\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Required Check\n// ============================================================================\n\n/**\n * Check if a single field is required based on requiredWhen or schema\n * @internal Exported for use by validate.ts\n */\nexport function isFieldRequired(\n fieldPath: string,\n fieldDef: FieldDefinition,\n spec: Forma,\n context: EvaluationContext\n): boolean {\n // If field has requiredWhen, evaluate it\n if (fieldDef.requiredWhen) {\n return evaluateBoolean(fieldDef.requiredWhen, context);\n }\n\n // Otherwise, check schema required array\n return spec.schema.required?.includes(fieldPath) ?? false;\n}\n\n/**\n * Check if a single field is currently required\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns True if the field is required\n */\nexport function isRequired(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return spec.schema.required?.includes(fieldPath) ?? false;\n }\n\n const computed = calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return isFieldRequired(fieldPath, fieldDef, spec, context);\n}\n","/**\n * Enabled Fields Engine\n *\n * Determines which fields are currently enabled (editable) based on\n * conditional enabledWhen expressions.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n EnabledResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EnabledOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine which fields are currently enabled (editable)\n *\n * Returns a map of field paths to boolean enabled states.\n * Fields without enabledWhen expressions are always enabled.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to enabled states\n *\n * @example\n * const enabled = getEnabled(\n * { isLocked: true },\n * forma\n * );\n * // => { isLocked: true, lockedField: false, ... }\n */\nexport function getEnabled(\n data: Record<string, unknown>,\n spec: Forma,\n options: EnabledOptions = {}\n): EnabledResult {\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: EnabledResult = {};\n\n // Evaluate each field's enabled status\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n result[fieldPath] = isFieldEnabled(fieldDef, context);\n }\n }\n\n // Also check array item fields\n for (const [fieldPath, fieldDef] of Object.entries(spec.fields)) {\n if (fieldDef.itemFields) {\n const arrayData = data[fieldPath];\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n const itemContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: i,\n };\n\n for (const [itemFieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${fieldPath}[${i}].${itemFieldName}`;\n result[itemFieldPath] = isFieldEnabled(itemFieldDef, itemContext);\n }\n }\n }\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Enabled Check\n// ============================================================================\n\n/**\n * Check if a field is enabled based on its definition\n */\nfunction isFieldEnabled(\n fieldDef: FieldDefinition,\n context: EvaluationContext\n): boolean {\n // If field has enabledWhen, evaluate it\n if (fieldDef.enabledWhen) {\n return evaluateBoolean(fieldDef.enabledWhen, context);\n }\n\n // No condition = always enabled\n return true;\n}\n\n/**\n * Check if a single field is currently enabled\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns True if the field is enabled\n */\nexport function isEnabled(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return true; // Unknown fields are enabled by default\n }\n\n if (!fieldDef.enabledWhen) {\n return true; // No condition = always enabled\n }\n\n const computed = calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return evaluateBoolean(fieldDef.enabledWhen, context);\n}\n","/**\n * Validation Engine\n *\n * Validates form data against Forma rules including:\n * - JSON Schema type validation\n * - Required field validation (with conditional requiredWhen)\n * - Custom FEEL validation rules\n * - Array item validation\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n ValidationRule,\n EvaluationContext,\n ValidationResult,\n FieldError,\n JSONSchemaProperty,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\nimport { getVisibility } from \"./visibility.js\";\nimport { isFieldRequired } from \"./required.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ValidateOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n /** Pre-calculated visibility */\n visibility?: Record<string, boolean>;\n /** Only validate visible fields (default: true) */\n onlyVisible?: boolean;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Validate form data against a Forma\n *\n * Performs comprehensive validation including:\n * - Required field checks (respecting conditional requiredWhen)\n * - JSON Schema type validation\n * - Custom FEEL validation rules\n * - Array min/max items validation\n * - Array item field validation\n *\n * By default, only visible fields are validated.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Validation options\n * @returns Validation result with valid flag and errors array\n *\n * @example\n * const result = validate(\n * { name: \"\", age: 15 },\n * forma\n * );\n * // => {\n * // valid: false,\n * // errors: [\n * // { field: \"name\", message: \"Name is required\", severity: \"error\" },\n * // { field: \"age\", message: \"Must be 18 or older\", severity: \"error\" }\n * // ]\n * // }\n */\nexport function validate(\n data: Record<string, unknown>,\n spec: Forma,\n options: ValidateOptions = {}\n): ValidationResult {\n const { onlyVisible = true } = options;\n\n // Calculate computed values\n const computed = options.computed ?? calculate(data, spec);\n\n // Calculate visibility\n const visibility = options.visibility ?? getVisibility(data, spec, { computed });\n\n // Collect errors\n const errors: FieldError[] = [];\n\n // Validate each field\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) continue;\n\n // Skip hidden fields if onlyVisible is true\n if (onlyVisible && visibility[fieldPath] === false) {\n continue;\n }\n\n // Get schema property for type validation\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Validate this field\n const fieldErrors = validateField(\n fieldPath,\n data[fieldPath],\n fieldDef,\n schemaProperty,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n\n errors.push(...fieldErrors);\n }\n\n return {\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\n errors,\n };\n}\n\n// ============================================================================\n// Field Validation\n// ============================================================================\n\n/**\n * Validate a single field and its nested fields\n */\nfunction validateField(\n path: string,\n value: unknown,\n fieldDef: FieldDefinition,\n schemaProperty: JSONSchemaProperty | undefined,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n value,\n };\n\n // 1. Required validation\n const required = isFieldRequired(path, fieldDef, spec, context);\n if (required && isEmpty(value)) {\n errors.push({\n field: path,\n message: fieldDef.label\n ? `${fieldDef.label} is required`\n : \"This field is required\",\n severity: \"error\",\n });\n }\n\n // 2. Type validation (only if value is present)\n if (!isEmpty(value) && schemaProperty) {\n const typeError = validateType(path, value, schemaProperty, fieldDef);\n if (typeError) {\n errors.push(typeError);\n }\n }\n\n // 3. Custom FEEL validation rules\n if (fieldDef.validations && !isEmpty(value)) {\n const customErrors = validateCustomRules(path, fieldDef.validations, context);\n errors.push(...customErrors);\n }\n\n // 4. Array validation\n if (Array.isArray(value) && fieldDef.itemFields) {\n const arrayErrors = validateArray(\n path,\n value,\n fieldDef,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n errors.push(...arrayErrors);\n }\n\n return errors;\n}\n\n/**\n * Check if a value is empty\n */\nfunction isEmpty(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n if (Array.isArray(value) && value.length === 0) return true;\n return false;\n}\n\n// ============================================================================\n// Type Validation\n// ============================================================================\n\n/**\n * Validate value against JSON Schema type\n */\nfunction validateType(\n path: string,\n value: unknown,\n schema: JSONSchemaProperty,\n fieldDef: FieldDefinition\n): FieldError | null {\n const label = fieldDef.label ?? path;\n\n switch (schema.type) {\n case \"string\": {\n if (typeof value !== \"string\") {\n return {\n field: path,\n message: `${label} must be a string`,\n severity: \"error\",\n };\n }\n\n // String-specific validations\n if (\"minLength\" in schema && schema.minLength !== undefined) {\n if (value.length < schema.minLength) {\n return {\n field: path,\n message: `${label} must be at least ${schema.minLength} characters`,\n severity: \"error\",\n };\n }\n }\n\n if (\"maxLength\" in schema && schema.maxLength !== undefined) {\n if (value.length > schema.maxLength) {\n return {\n field: path,\n message: `${label} must be no more than ${schema.maxLength} characters`,\n severity: \"error\",\n };\n }\n }\n\n if (\"pattern\" in schema && schema.pattern) {\n const regex = new RegExp(schema.pattern);\n if (!regex.test(value)) {\n return {\n field: path,\n message: `${label} format is invalid`,\n severity: \"error\",\n };\n }\n }\n\n if (\"enum\" in schema && schema.enum) {\n if (!schema.enum.includes(value)) {\n return {\n field: path,\n message: `${label} must be one of: ${schema.enum.join(\", \")}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"format\" in schema && schema.format) {\n const formatError = validateFormat(path, value, schema.format, label);\n if (formatError) return formatError;\n }\n\n return null;\n }\n\n case \"number\":\n case \"integer\": {\n if (typeof value !== \"number\") {\n return {\n field: path,\n message: `${label} must be a number`,\n severity: \"error\",\n };\n }\n\n if (schema.type === \"integer\" && !Number.isInteger(value)) {\n return {\n field: path,\n message: `${label} must be a whole number`,\n severity: \"error\",\n };\n }\n\n if (\"minimum\" in schema && schema.minimum !== undefined) {\n if (value < schema.minimum) {\n return {\n field: path,\n message: `${label} must be at least ${schema.minimum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"maximum\" in schema && schema.maximum !== undefined) {\n if (value > schema.maximum) {\n return {\n field: path,\n message: `${label} must be no more than ${schema.maximum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"exclusiveMinimum\" in schema && schema.exclusiveMinimum !== undefined) {\n if (value <= schema.exclusiveMinimum) {\n return {\n field: path,\n message: `${label} must be greater than ${schema.exclusiveMinimum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"exclusiveMaximum\" in schema && schema.exclusiveMaximum !== undefined) {\n if (value >= schema.exclusiveMaximum) {\n return {\n field: path,\n message: `${label} must be less than ${schema.exclusiveMaximum}`,\n severity: \"error\",\n };\n }\n }\n\n return null;\n }\n\n case \"boolean\": {\n if (typeof value !== \"boolean\") {\n return {\n field: path,\n message: `${label} must be true or false`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"array\": {\n if (!Array.isArray(value)) {\n return {\n field: path,\n message: `${label} must be a list`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"object\": {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return {\n field: path,\n message: `${label} must be an object`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Validate string format\n */\nfunction validateFormat(\n path: string,\n value: string,\n format: string,\n label: string\n): FieldError | null {\n switch (format) {\n case \"email\": {\n // Simple email regex\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid email address`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"date\": {\n // ISO date format YYYY-MM-DD\n const dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n if (!dateRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid date`,\n severity: \"error\",\n };\n }\n // Verify the date is actually valid (e.g., not Feb 30)\n const parsed = new Date(value + \"T00:00:00Z\");\n if (isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== value) {\n return {\n field: path,\n message: `${label} must be a valid date`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"date-time\": {\n if (isNaN(Date.parse(value))) {\n return {\n field: path,\n message: `${label} must be a valid date and time`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"uri\": {\n try {\n new URL(value);\n return null;\n } catch {\n return {\n field: path,\n message: `${label} must be a valid URL`,\n severity: \"error\",\n };\n }\n }\n\n case \"uuid\": {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n if (!uuidRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid UUID`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n default:\n return null;\n }\n}\n\n// ============================================================================\n// Custom Rule Validation\n// ============================================================================\n\n/**\n * Validate custom FEEL validation rules\n */\nfunction validateCustomRules(\n path: string,\n rules: ValidationRule[],\n context: EvaluationContext\n): FieldError[] {\n const errors: FieldError[] = [];\n\n for (const rule of rules) {\n const isValid = evaluateBoolean(rule.rule, context);\n\n if (!isValid) {\n errors.push({\n field: path,\n message: rule.message,\n severity: rule.severity ?? \"error\",\n });\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// Array Validation\n// ============================================================================\n\n/**\n * Validate array field including items\n */\nfunction validateArray(\n path: string,\n value: unknown[],\n fieldDef: FieldDefinition,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n const label = fieldDef.label ?? path;\n\n // Check min/max items\n if (fieldDef.minItems !== undefined && value.length < fieldDef.minItems) {\n errors.push({\n field: path,\n message: `${label} must have at least ${fieldDef.minItems} items`,\n severity: \"error\",\n });\n }\n\n if (fieldDef.maxItems !== undefined && value.length > fieldDef.maxItems) {\n errors.push({\n field: path,\n message: `${label} must have no more than ${fieldDef.maxItems} items`,\n severity: \"error\",\n });\n }\n\n // Validate each item's fields\n if (fieldDef.itemFields) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i] as Record<string, unknown>;\n const itemErrors = validateArrayItem(\n path,\n i,\n item,\n fieldDef.itemFields,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n errors.push(...itemErrors);\n }\n }\n\n return errors;\n}\n\n/**\n * Validate fields within a single array item\n */\nfunction validateArrayItem(\n arrayPath: string,\n index: number,\n item: Record<string, unknown>,\n itemFields: Record<string, FieldDefinition>,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n const itemFieldPath = `${arrayPath}[${index}].${fieldName}`;\n\n // Skip hidden fields\n if (onlyVisible && visibility[itemFieldPath] === false) {\n continue;\n }\n\n const value = item[fieldName];\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: index,\n value,\n };\n\n // Required check\n const isRequired = fieldDef.requiredWhen\n ? evaluateBoolean(fieldDef.requiredWhen, context)\n : false;\n\n if (isRequired && isEmpty(value)) {\n errors.push({\n field: itemFieldPath,\n message: fieldDef.label\n ? `${fieldDef.label} is required`\n : \"This field is required\",\n severity: \"error\",\n });\n }\n\n // Custom validations\n if (fieldDef.validations && !isEmpty(value)) {\n const customErrors = validateCustomRules(itemFieldPath, fieldDef.validations, context);\n errors.push(...customErrors);\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// Single Field Validation\n// ============================================================================\n\n/**\n * Validate a single field\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Array of errors for this field\n */\nexport function validateSingleField(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): FieldError[] {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return [];\n }\n\n const computed = calculate(data, spec);\n const visibility = getVisibility(data, spec, { computed });\n const schemaProperty = spec.schema.properties[fieldPath];\n\n return validateField(\n fieldPath,\n data[fieldPath],\n fieldDef,\n schemaProperty,\n spec,\n data,\n computed,\n visibility,\n true\n );\n}\n"],"mappings":"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","names":["feelinEvaluate","isRequired"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/feel/index.ts","../src/engine/calculate.ts","../src/engine/visibility.ts","../src/engine/required.ts","../src/engine/enabled.ts","../src/engine/validate.ts"],"sourcesContent":["/**\n * @fogpipe/forma-core\n *\n * Core runtime for Forma dynamic forms.\n * Provides types, FEEL expression evaluation, and form state engines.\n */\n\n// Types (explicit type-only exports)\nexport type {\n // FEEL\n FEELExpression,\n // JSON Schema\n JSONSchema,\n JSONSchemaProperty,\n JSONSchemaBase,\n JSONSchemaString,\n JSONSchemaNumber,\n JSONSchemaInteger,\n JSONSchemaBoolean,\n JSONSchemaArray,\n JSONSchemaObject,\n JSONSchemaEnum,\n // Field types\n FieldType,\n ValidationRule,\n SelectOption,\n FieldDefinition,\n ComputedField,\n PageDefinition,\n FormMeta,\n Forma,\n // Evaluation\n EvaluationContext,\n // Results\n VisibilityResult,\n RequiredResult,\n RequiredFieldsResult,\n EnabledResult,\n FieldError,\n ValidationResult,\n CalculationError,\n CalculationResult,\n} from \"./types.js\";\n\n// FEEL expression evaluation\nexport * from \"./feel/index.js\";\n\n// Form state engines\nexport * from \"./engine/index.js\";\n","/**\n * FEEL Expression Evaluator\n *\n * Wraps the feelin library to provide FEEL expression evaluation\n * with Forma context conventions.\n *\n * Context variable conventions:\n * - `fieldName` - Direct field value access\n * - `computed.name` - Computed value access\n * - `ref.path` - Reference data lookup (external lookup tables)\n * - `item.fieldName` - Array item field access (within array context)\n * - `itemIndex` - Current array item index (0-based)\n * - `value` - Current field value (in validation expressions)\n */\n\nimport { evaluate as feelinEvaluate } from \"feelin\";\nimport type { EvaluationContext, FEELExpression } from \"../types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EvaluateResult<T = unknown> {\n success: true;\n value: T;\n}\n\nexport interface EvaluateError {\n success: false;\n error: string;\n expression: string;\n}\n\nexport type EvaluationOutcome<T = unknown> = EvaluateResult<T> | EvaluateError;\n\n// ============================================================================\n// Context Building\n// ============================================================================\n\n/**\n * Build the FEEL evaluation context from our EvaluationContext\n *\n * Maps our context conventions to feelin context format:\n * - Form data fields are spread directly\n * - computed becomes an object (accessed as computed.fieldName)\n * - ref becomes an object for reference data (accessed as ref.path.to.data)\n * - item becomes an object for array context (accessed as item.fieldName)\n * - itemIndex is a number for array context\n * - value is the current field value\n */\nfunction buildFeelContext(ctx: EvaluationContext): Record<string, unknown> {\n const feelContext: Record<string, unknown> = {\n // Spread form data directly so fields are accessible by name\n ...ctx.data,\n };\n\n // Add computed values under 'computed' (accessed as computed.fieldName)\n if (ctx.computed) {\n feelContext[\"computed\"] = ctx.computed;\n }\n\n // Add reference data under 'ref' (accessed as ref.path.to.data)\n if (ctx.referenceData) {\n feelContext[\"ref\"] = ctx.referenceData;\n }\n\n // Add array item context (accessed as item.fieldName)\n if (ctx.item !== undefined) {\n feelContext[\"item\"] = ctx.item;\n }\n\n // Add array index\n if (ctx.itemIndex !== undefined) {\n feelContext[\"itemIndex\"] = ctx.itemIndex;\n }\n\n // Add current field value for validation expressions\n if (ctx.value !== undefined) {\n feelContext[\"value\"] = ctx.value;\n }\n\n return feelContext;\n}\n\n// ============================================================================\n// Expression Evaluation\n// ============================================================================\n\n/**\n * Evaluate a FEEL expression and return the result\n *\n * @param expression - FEEL expression string\n * @param context - Evaluation context with form data, computed values, etc.\n * @returns Evaluation outcome with success/value or error\n *\n * @example\n * // Simple field comparison\n * evaluate(\"age >= 18\", { data: { age: 21 } })\n * // => { success: true, value: true }\n *\n * @example\n * // Computed value reference\n * evaluate(\"computed.bmi > 30\", { data: {}, computed: { bmi: 32.5 } })\n * // => { success: true, value: true }\n *\n * @example\n * // Array item context\n * evaluate(\"item.frequency = \\\"daily\\\"\", { data: {}, item: { frequency: \"daily\" } })\n * // => { success: true, value: true }\n */\nexport function evaluate<T = unknown>(\n expression: FEELExpression,\n context: EvaluationContext\n): EvaluationOutcome<T> {\n try {\n const feelContext = buildFeelContext(context);\n const result = feelinEvaluate(expression, feelContext);\n return {\n success: true,\n value: result as T,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n expression,\n };\n }\n}\n\n/**\n * Evaluate a FEEL expression expecting a boolean result\n *\n * Used for visibility, required, and enabled conditions.\n * Returns false on error or non-boolean result for safety.\n *\n * @param expression - FEEL expression that should return boolean\n * @param context - Evaluation context\n * @returns Boolean result (false on error)\n */\nexport function evaluateBoolean(\n expression: FEELExpression,\n context: EvaluationContext\n): boolean {\n const result = evaluate<boolean>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return false;\n }\n\n // FEEL uses three-valued logic where comparisons with null return null.\n // For form visibility/required/enabled conditions, we treat null as false.\n if (result.value === null || result.value === undefined) {\n return false;\n }\n\n if (typeof result.value !== \"boolean\") {\n console.warn(\n `FEEL expression did not return boolean: ${expression}\\nGot: ${typeof result.value}`\n );\n return false;\n }\n\n return result.value;\n}\n\n/**\n * Evaluate a FEEL expression expecting a numeric result\n *\n * Used for computed values that return numbers.\n *\n * @param expression - FEEL expression that should return number\n * @param context - Evaluation context\n * @returns Numeric result or null on error\n */\nexport function evaluateNumber(\n expression: FEELExpression,\n context: EvaluationContext\n): number | null {\n const result = evaluate<number>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return null;\n }\n\n if (typeof result.value !== \"number\") {\n console.warn(\n `FEEL expression did not return number: ${expression}\\nGot: ${typeof result.value}`\n );\n return null;\n }\n\n return result.value;\n}\n\n/**\n * Evaluate a FEEL expression expecting a string result\n *\n * @param expression - FEEL expression that should return string\n * @param context - Evaluation context\n * @returns String result or null on error\n */\nexport function evaluateString(\n expression: FEELExpression,\n context: EvaluationContext\n): string | null {\n const result = evaluate<string>(expression, context);\n\n if (!result.success) {\n console.warn(\n `FEEL expression error: ${result.error}\\nExpression: ${result.expression}`\n );\n return null;\n }\n\n if (typeof result.value !== \"string\") {\n console.warn(\n `FEEL expression did not return string: ${expression}\\nGot: ${typeof result.value}`\n );\n return null;\n }\n\n return result.value;\n}\n\n// ============================================================================\n// Batch Evaluation\n// ============================================================================\n\n/**\n * Evaluate multiple FEEL expressions at once\n *\n * Useful for evaluating all visibility conditions in a form.\n *\n * @param expressions - Map of field names to FEEL expressions\n * @param context - Evaluation context\n * @returns Map of field names to boolean results\n */\nexport function evaluateBooleanBatch(\n expressions: Record<string, FEELExpression>,\n context: EvaluationContext\n): Record<string, boolean> {\n const results: Record<string, boolean> = {};\n\n for (const [key, expression] of Object.entries(expressions)) {\n results[key] = evaluateBoolean(expression, context);\n }\n\n return results;\n}\n\n// ============================================================================\n// Expression Validation\n// ============================================================================\n\n/**\n * Check if a FEEL expression is syntactically valid\n *\n * @param expression - FEEL expression to validate\n * @returns True if the expression can be parsed\n */\nexport function isValidExpression(expression: FEELExpression): boolean {\n try {\n // Try to evaluate with empty context - we just want to check parsing\n feelinEvaluate(expression, {});\n return true;\n } catch {\n // Expression failed to parse or evaluate\n return false;\n }\n}\n\n/**\n * Validate a FEEL expression and return any parsing errors\n *\n * @param expression - FEEL expression to validate\n * @returns Null if valid, error message if invalid\n */\nexport function validateExpression(expression: FEELExpression): string | null {\n try {\n // Evaluate with minimal context to catch parse errors\n feelinEvaluate(expression, {});\n return null;\n } catch (error) {\n // Only return actual parsing errors, not runtime errors\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"parse\") || message.includes(\"syntax\")) {\n return message;\n }\n // Runtime errors (missing variables, etc.) are OK for validation\n return null;\n }\n}\n","/**\n * Calculation Engine\n *\n * Evaluates computed fields based on form data.\n * Computed values are derived from form data using FEEL expressions.\n */\n\nimport { evaluate } from \"../feel/index.js\";\nimport type {\n Forma,\n ComputedField,\n EvaluationContext,\n CalculationResult,\n CalculationError,\n} from \"../types.js\";\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Calculate all computed values from form data\n *\n * Evaluates each computed field's FEEL expression and returns the results.\n * Errors are collected rather than thrown, allowing partial results.\n *\n * @param data - Current form data\n * @param spec - Form specification with computed fields\n * @returns Computed values and any calculation errors\n *\n * @example\n * const spec = {\n * computed: {\n * bmi: {\n * expression: \"weight / (height / 100) ** 2\",\n * label: \"BMI\",\n * format: \"decimal(1)\"\n * },\n * isObese: {\n * expression: \"$computed.bmi >= 30\"\n * }\n * }\n * };\n *\n * const result = calculate({ weight: 85, height: 175 }, spec);\n * // => { values: { bmi: 27.76, isObese: false }, errors: [] }\n */\nexport function calculate(\n data: Record<string, unknown>,\n spec: Forma\n): Record<string, unknown> {\n const result = calculateWithErrors(data, spec);\n return result.values;\n}\n\n/**\n * Calculate computed values with error reporting\n *\n * Same as calculate() but also returns any errors that occurred.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Values and errors\n */\nexport function calculateWithErrors(\n data: Record<string, unknown>,\n spec: Forma\n): CalculationResult {\n if (!spec.computed) {\n return { values: {}, errors: [] };\n }\n\n const values: Record<string, unknown> = {};\n const errors: CalculationError[] = [];\n\n // Get computation order (handles dependencies)\n const orderedFields = getComputationOrder(spec.computed);\n\n // Evaluate each computed field in dependency order\n for (const fieldName of orderedFields) {\n const fieldDef = spec.computed[fieldName];\n if (!fieldDef) continue;\n\n const result = evaluateComputedField(\n fieldName,\n fieldDef,\n data,\n values, // Pass already-computed values for dependencies\n spec.referenceData // Pass reference data for lookups\n );\n\n if (result.success) {\n values[fieldName] = result.value;\n } else {\n errors.push({\n field: fieldName,\n message: result.error,\n expression: fieldDef.expression,\n });\n // Set to null so dependent fields can still evaluate\n values[fieldName] = null;\n }\n }\n\n return { values, errors };\n}\n\n// ============================================================================\n// Field Evaluation\n// ============================================================================\n\ninterface ComputeSuccess {\n success: true;\n value: unknown;\n}\n\ninterface ComputeFailure {\n success: false;\n error: string;\n}\n\ntype ComputeResult = ComputeSuccess | ComputeFailure;\n\n/**\n * Evaluate a single computed field\n */\nfunction evaluateComputedField(\n _name: string,\n fieldDef: ComputedField,\n data: Record<string, unknown>,\n computedSoFar: Record<string, unknown>,\n referenceData?: Record<string, unknown>\n): ComputeResult {\n // Check if any referenced computed field is null - propagate null to dependents\n // This prevents issues like: bmi is null, but bmiCategory still evaluates to \"obese\"\n // because `null < 18.5` is false in comparisons\n const referencedComputed = findComputedReferences(fieldDef.expression);\n for (const ref of referencedComputed) {\n if (computedSoFar[ref] === null) {\n return {\n success: true,\n value: null,\n };\n }\n }\n\n const context: EvaluationContext = {\n data,\n computed: computedSoFar,\n referenceData,\n };\n\n const result = evaluate(fieldDef.expression, context);\n\n if (!result.success) {\n return {\n success: false,\n error: result.error,\n };\n }\n\n // Treat NaN and Infinity as null - prevents unexpected behavior in conditional expressions\n // (e.g., NaN < 18.5 is false, causing fallthrough in if-else chains)\n if (typeof result.value === \"number\" && (!Number.isFinite(result.value))) {\n return {\n success: true,\n value: null,\n };\n }\n\n return {\n success: true,\n value: result.value,\n };\n}\n\n/**\n * Find computed field references in an expression (e.g., computed.bmi)\n */\nfunction findComputedReferences(expression: string): string[] {\n const refs: string[] = [];\n const regex = /computed\\.(\\w+)/g;\n let match;\n while ((match = regex.exec(expression)) !== null) {\n refs.push(match[1]);\n }\n return refs;\n}\n\n// ============================================================================\n// Dependency Resolution\n// ============================================================================\n\n/**\n * Determine the order to evaluate computed fields based on dependencies\n *\n * Computed fields can reference other computed fields via $computed.name.\n * This function performs topological sort to ensure dependencies are\n * evaluated first.\n */\nfunction getComputationOrder(\n computed: Record<string, ComputedField>\n): string[] {\n const fieldNames = Object.keys(computed);\n\n // Build dependency graph\n const deps = new Map<string, Set<string>>();\n for (const name of fieldNames) {\n deps.set(name, findComputedDependencies(computed[name].expression, fieldNames));\n }\n\n // Topological sort\n const sorted: string[] = [];\n const visited = new Set<string>();\n const visiting = new Set<string>();\n\n function visit(name: string): void {\n if (visited.has(name)) return;\n if (visiting.has(name)) {\n // Circular dependency - just add it and let evaluation fail gracefully\n console.warn(`Circular dependency detected in computed field: ${name}`);\n sorted.push(name);\n visited.add(name);\n return;\n }\n\n visiting.add(name);\n\n const fieldDeps = deps.get(name) ?? new Set();\n for (const dep of fieldDeps) {\n visit(dep);\n }\n\n visiting.delete(name);\n visited.add(name);\n sorted.push(name);\n }\n\n for (const name of fieldNames) {\n visit(name);\n }\n\n return sorted;\n}\n\n/**\n * Find which computed fields are referenced in an expression\n */\nfunction findComputedDependencies(\n expression: string,\n availableFields: string[]\n): Set<string> {\n const deps = new Set<string>();\n\n // Look for computed.fieldName patterns (without $ prefix)\n const regex = /computed\\.(\\w+)/g;\n let match;\n while ((match = regex.exec(expression)) !== null) {\n const fieldName = match[1];\n if (availableFields.includes(fieldName)) {\n deps.add(fieldName);\n }\n }\n\n return deps;\n}\n\n// ============================================================================\n// Formatted Output\n// ============================================================================\n\n/**\n * Get a computed value formatted according to its format specification\n *\n * @param fieldName - Name of the computed field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Formatted string or null if not displayable\n */\nexport function getFormattedValue(\n fieldName: string,\n data: Record<string, unknown>,\n spec: Forma\n): string | null {\n if (!spec.computed?.[fieldName]) {\n return null;\n }\n\n const fieldDef = spec.computed[fieldName];\n const computed = calculate(data, spec);\n const value = computed[fieldName];\n\n if (value === null || value === undefined) {\n return null;\n }\n\n return formatValue(value, fieldDef.format);\n}\n\n/**\n * Format a value according to a format specification\n *\n * Supported formats:\n * - decimal(n) - Number with n decimal places\n * - currency - Number formatted as currency\n * - percent - Number formatted as percentage\n * - (none) - Default string conversion\n */\nfunction formatValue(value: unknown, format?: string): string {\n if (!format) {\n return String(value);\n }\n\n // Handle decimal(n) format\n const decimalMatch = format.match(/^decimal\\((\\d+)\\)$/);\n if (decimalMatch) {\n const decimals = parseInt(decimalMatch[1], 10);\n return typeof value === \"number\" ? value.toFixed(decimals) : String(value);\n }\n\n // Handle currency format\n if (format === \"currency\") {\n return typeof value === \"number\"\n ? new Intl.NumberFormat(\"en-US\", {\n style: \"currency\",\n currency: \"USD\",\n }).format(value)\n : String(value);\n }\n\n // Handle percent format\n if (format === \"percent\") {\n return typeof value === \"number\"\n ? new Intl.NumberFormat(\"en-US\", {\n style: \"percent\",\n minimumFractionDigits: 1,\n }).format(value)\n : String(value);\n }\n\n return String(value);\n}\n\n// ============================================================================\n// Single Field Calculation\n// ============================================================================\n\n/**\n * Calculate a single computed field\n *\n * @param fieldName - Name of the computed field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Computed value or null if calculation failed\n */\nexport function calculateField(\n fieldName: string,\n data: Record<string, unknown>,\n spec: Forma\n): unknown {\n const computed = calculate(data, spec);\n return computed[fieldName] ?? null;\n}\n","/**\n * Visibility Engine\n *\n * Determines which fields should be visible based on form data\n * and Forma visibility rules.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n VisibilityResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface VisibilityOptions {\n /** Pre-calculated computed values (avoids recalculation) */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine visibility for all fields in a form\n *\n * Returns a map of field paths to boolean visibility states.\n * Fields without visibleWhen expressions are always visible.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to visibility states\n *\n * @example\n * const visibility = getVisibility(\n * { age: 21, hasLicense: true },\n * forma\n * );\n * // => { age: true, hasLicense: true, vehicleType: true, ... }\n */\nexport function getVisibility(\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): VisibilityResult {\n // Calculate computed values if not provided\n const computed = options.computed ?? calculate(data, spec);\n\n // Build base evaluation context\n const baseContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: VisibilityResult = {};\n\n // Process all fields in field order\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n evaluateFieldVisibility(fieldPath, fieldDef, data, baseContext, result);\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Evaluation\n// ============================================================================\n\n/**\n * Evaluate visibility for a single field and its nested fields\n */\nfunction evaluateFieldVisibility(\n path: string,\n fieldDef: FieldDefinition,\n data: Record<string, unknown>,\n context: EvaluationContext,\n result: VisibilityResult\n): void {\n // Evaluate the field's own visibility\n if (fieldDef.visibleWhen) {\n result[path] = evaluateBoolean(fieldDef.visibleWhen, context);\n } else {\n result[path] = true; // No condition = always visible\n }\n\n // If not visible, children are implicitly not visible\n if (!result[path]) {\n return;\n }\n\n // Handle array fields with item visibility\n if (fieldDef.itemFields) {\n const arrayData = data[path];\n if (Array.isArray(arrayData)) {\n evaluateArrayItemVisibility(path, fieldDef, arrayData, context, result);\n }\n }\n}\n\n/**\n * Evaluate visibility for array item fields\n *\n * For each item in the array, evaluates the visibility of each\n * item field using the $item context.\n */\nfunction evaluateArrayItemVisibility(\n arrayPath: string,\n fieldDef: FieldDefinition,\n arrayData: unknown[],\n baseContext: EvaluationContext,\n result: VisibilityResult\n): void {\n if (!fieldDef.itemFields) return;\n\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n\n // Create item-specific context\n const itemContext: EvaluationContext = {\n ...baseContext,\n item,\n itemIndex: i,\n };\n\n // Evaluate each item field's visibility\n for (const [fieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${arrayPath}[${i}].${fieldName}`;\n\n if (itemFieldDef.visibleWhen) {\n result[itemFieldPath] = evaluateBoolean(itemFieldDef.visibleWhen, itemContext);\n } else {\n result[itemFieldPath] = true;\n }\n }\n }\n}\n\n// ============================================================================\n// Individual Field Visibility\n// ============================================================================\n\n/**\n * Check if a single field is visible\n *\n * Useful for checking visibility of one field without computing all.\n *\n * @param fieldPath - Field path to check\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns True if the field is visible\n */\nexport function isFieldVisible(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return true; // Unknown fields are visible by default\n }\n\n if (!fieldDef.visibleWhen) {\n return true; // No condition = always visible\n }\n\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return evaluateBoolean(fieldDef.visibleWhen, context);\n}\n\n// ============================================================================\n// Page Visibility\n// ============================================================================\n\n/**\n * Determine which pages are visible in a wizard form\n *\n * @param data - Current form data\n * @param spec - Form specification with pages\n * @param options - Optional pre-calculated computed values\n * @returns Map of page IDs to visibility states\n */\nexport function getPageVisibility(\n data: Record<string, unknown>,\n spec: Forma,\n options: VisibilityOptions = {}\n): Record<string, boolean> {\n if (!spec.pages) {\n return {};\n }\n\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: Record<string, boolean> = {};\n\n for (const page of spec.pages) {\n if (page.visibleWhen) {\n result[page.id] = evaluateBoolean(page.visibleWhen, context);\n } else {\n result[page.id] = true;\n }\n }\n\n return result;\n}\n","/**\n * Required Fields Engine\n *\n * Determines which fields are currently required based on\n * conditional requiredWhen expressions and schema required array.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n RequiredFieldsResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RequiredOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine which fields are currently required\n *\n * Returns a map of field paths to boolean required states.\n * Evaluates requiredWhen expressions for conditional requirements.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to required states\n *\n * @example\n * const required = getRequired(\n * { hasInsurance: true },\n * forma\n * );\n * // => { hasInsurance: true, insuranceProvider: true, policyNumber: true }\n */\nexport function getRequired(\n data: Record<string, unknown>,\n spec: Forma,\n options: RequiredOptions = {}\n): RequiredFieldsResult {\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: RequiredFieldsResult = {};\n\n // Evaluate each field's required status\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n result[fieldPath] = isFieldRequired(fieldPath, fieldDef, spec, context);\n }\n }\n\n // Also check array item fields\n for (const [fieldPath, fieldDef] of Object.entries(spec.fields)) {\n if (fieldDef.itemFields) {\n const arrayData = data[fieldPath];\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n const itemContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: i,\n };\n\n for (const [itemFieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${fieldPath}[${i}].${itemFieldName}`;\n result[itemFieldPath] = isFieldRequired(\n itemFieldPath,\n itemFieldDef,\n spec,\n itemContext\n );\n }\n }\n }\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Required Check\n// ============================================================================\n\n/**\n * Check if a single field is required based on requiredWhen or schema\n * @internal Exported for use by validate.ts\n */\nexport function isFieldRequired(\n fieldPath: string,\n fieldDef: FieldDefinition,\n spec: Forma,\n context: EvaluationContext\n): boolean {\n // If field has requiredWhen, evaluate it\n if (fieldDef.requiredWhen) {\n return evaluateBoolean(fieldDef.requiredWhen, context);\n }\n\n // Otherwise, check schema required array\n return spec.schema.required?.includes(fieldPath) ?? false;\n}\n\n/**\n * Check if a single field is currently required\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns True if the field is required\n */\nexport function isRequired(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return spec.schema.required?.includes(fieldPath) ?? false;\n }\n\n const computed = calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return isFieldRequired(fieldPath, fieldDef, spec, context);\n}\n","/**\n * Enabled Fields Engine\n *\n * Determines which fields are currently enabled (editable) based on\n * conditional enabledWhen expressions.\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n EvaluationContext,\n EnabledResult,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface EnabledOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Determine which fields are currently enabled (editable)\n *\n * Returns a map of field paths to boolean enabled states.\n * Fields without enabledWhen expressions are always enabled.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Optional pre-calculated computed values\n * @returns Map of field paths to enabled states\n *\n * @example\n * const enabled = getEnabled(\n * { isLocked: true },\n * forma\n * );\n * // => { isLocked: true, lockedField: false, ... }\n */\nexport function getEnabled(\n data: Record<string, unknown>,\n spec: Forma,\n options: EnabledOptions = {}\n): EnabledResult {\n const computed = options.computed ?? calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n const result: EnabledResult = {};\n\n // Evaluate each field's enabled status\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (fieldDef) {\n result[fieldPath] = isFieldEnabled(fieldDef, context);\n }\n }\n\n // Also check array item fields\n for (const [fieldPath, fieldDef] of Object.entries(spec.fields)) {\n if (fieldDef.itemFields) {\n const arrayData = data[fieldPath];\n if (Array.isArray(arrayData)) {\n for (let i = 0; i < arrayData.length; i++) {\n const item = arrayData[i] as Record<string, unknown>;\n const itemContext: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: i,\n };\n\n for (const [itemFieldName, itemFieldDef] of Object.entries(fieldDef.itemFields)) {\n const itemFieldPath = `${fieldPath}[${i}].${itemFieldName}`;\n result[itemFieldPath] = isFieldEnabled(itemFieldDef, itemContext);\n }\n }\n }\n }\n }\n\n return result;\n}\n\n// ============================================================================\n// Field Enabled Check\n// ============================================================================\n\n/**\n * Check if a field is enabled based on its definition\n */\nfunction isFieldEnabled(\n fieldDef: FieldDefinition,\n context: EvaluationContext\n): boolean {\n // If field has enabledWhen, evaluate it\n if (fieldDef.enabledWhen) {\n return evaluateBoolean(fieldDef.enabledWhen, context);\n }\n\n // No condition = always enabled\n return true;\n}\n\n/**\n * Check if a single field is currently enabled\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns True if the field is enabled\n */\nexport function isEnabled(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): boolean {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return true; // Unknown fields are enabled by default\n }\n\n if (!fieldDef.enabledWhen) {\n return true; // No condition = always enabled\n }\n\n const computed = calculate(data, spec);\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n };\n\n return evaluateBoolean(fieldDef.enabledWhen, context);\n}\n","/**\n * Validation Engine\n *\n * Validates form data against Forma rules including:\n * - JSON Schema type validation\n * - Required field validation (with conditional requiredWhen)\n * - Custom FEEL validation rules\n * - Array item validation\n */\n\nimport { evaluateBoolean } from \"../feel/index.js\";\nimport type {\n Forma,\n FieldDefinition,\n ValidationRule,\n EvaluationContext,\n ValidationResult,\n FieldError,\n JSONSchemaProperty,\n} from \"../types.js\";\nimport { calculate } from \"./calculate.js\";\nimport { getVisibility } from \"./visibility.js\";\nimport { isFieldRequired } from \"./required.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ValidateOptions {\n /** Pre-calculated computed values */\n computed?: Record<string, unknown>;\n /** Pre-calculated visibility */\n visibility?: Record<string, boolean>;\n /** Only validate visible fields (default: true) */\n onlyVisible?: boolean;\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Validate form data against a Forma\n *\n * Performs comprehensive validation including:\n * - Required field checks (respecting conditional requiredWhen)\n * - JSON Schema type validation\n * - Custom FEEL validation rules\n * - Array min/max items validation\n * - Array item field validation\n *\n * By default, only visible fields are validated.\n *\n * @param data - Current form data\n * @param spec - Form specification\n * @param options - Validation options\n * @returns Validation result with valid flag and errors array\n *\n * @example\n * const result = validate(\n * { name: \"\", age: 15 },\n * forma\n * );\n * // => {\n * // valid: false,\n * // errors: [\n * // { field: \"name\", message: \"Name is required\", severity: \"error\" },\n * // { field: \"age\", message: \"Must be 18 or older\", severity: \"error\" }\n * // ]\n * // }\n */\nexport function validate(\n data: Record<string, unknown>,\n spec: Forma,\n options: ValidateOptions = {}\n): ValidationResult {\n const { onlyVisible = true } = options;\n\n // Calculate computed values\n const computed = options.computed ?? calculate(data, spec);\n\n // Calculate visibility\n const visibility = options.visibility ?? getVisibility(data, spec, { computed });\n\n // Collect errors\n const errors: FieldError[] = [];\n\n // Validate each field\n for (const fieldPath of spec.fieldOrder) {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) continue;\n\n // Skip hidden fields if onlyVisible is true\n if (onlyVisible && visibility[fieldPath] === false) {\n continue;\n }\n\n // Get schema property for type validation\n const schemaProperty = spec.schema.properties[fieldPath];\n\n // Validate this field\n const fieldErrors = validateField(\n fieldPath,\n data[fieldPath],\n fieldDef,\n schemaProperty,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n\n errors.push(...fieldErrors);\n }\n\n return {\n valid: errors.filter((e) => e.severity === \"error\").length === 0,\n errors,\n };\n}\n\n// ============================================================================\n// Field Validation\n// ============================================================================\n\n/**\n * Validate a single field and its nested fields\n */\nfunction validateField(\n path: string,\n value: unknown,\n fieldDef: FieldDefinition,\n schemaProperty: JSONSchemaProperty | undefined,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n value,\n };\n\n // 1. Required validation\n const required = isFieldRequired(path, fieldDef, spec, context);\n if (required && isEmpty(value)) {\n errors.push({\n field: path,\n message: fieldDef.label\n ? `${fieldDef.label} is required`\n : \"This field is required\",\n severity: \"error\",\n });\n }\n\n // 2. Type validation (only if value is present)\n if (!isEmpty(value) && schemaProperty) {\n const typeError = validateType(path, value, schemaProperty, fieldDef);\n if (typeError) {\n errors.push(typeError);\n }\n }\n\n // 3. Custom FEEL validation rules\n if (fieldDef.validations && !isEmpty(value)) {\n const customErrors = validateCustomRules(path, fieldDef.validations, context);\n errors.push(...customErrors);\n }\n\n // 4. Array validation\n if (Array.isArray(value) && fieldDef.itemFields) {\n const arrayErrors = validateArray(\n path,\n value,\n fieldDef,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n errors.push(...arrayErrors);\n }\n\n return errors;\n}\n\n/**\n * Check if a value is empty\n */\nfunction isEmpty(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n if (Array.isArray(value) && value.length === 0) return true;\n return false;\n}\n\n// ============================================================================\n// Type Validation\n// ============================================================================\n\n/**\n * Validate value against JSON Schema type\n */\nfunction validateType(\n path: string,\n value: unknown,\n schema: JSONSchemaProperty,\n fieldDef: FieldDefinition\n): FieldError | null {\n const label = fieldDef.label ?? path;\n\n switch (schema.type) {\n case \"string\": {\n if (typeof value !== \"string\") {\n return {\n field: path,\n message: `${label} must be a string`,\n severity: \"error\",\n };\n }\n\n // String-specific validations\n if (\"minLength\" in schema && schema.minLength !== undefined) {\n if (value.length < schema.minLength) {\n return {\n field: path,\n message: `${label} must be at least ${schema.minLength} characters`,\n severity: \"error\",\n };\n }\n }\n\n if (\"maxLength\" in schema && schema.maxLength !== undefined) {\n if (value.length > schema.maxLength) {\n return {\n field: path,\n message: `${label} must be no more than ${schema.maxLength} characters`,\n severity: \"error\",\n };\n }\n }\n\n if (\"pattern\" in schema && schema.pattern) {\n const regex = new RegExp(schema.pattern);\n if (!regex.test(value)) {\n return {\n field: path,\n message: `${label} format is invalid`,\n severity: \"error\",\n };\n }\n }\n\n if (\"enum\" in schema && schema.enum) {\n if (!schema.enum.includes(value)) {\n return {\n field: path,\n message: `${label} must be one of: ${schema.enum.join(\", \")}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"format\" in schema && schema.format) {\n const formatError = validateFormat(path, value, schema.format, label);\n if (formatError) return formatError;\n }\n\n return null;\n }\n\n case \"number\":\n case \"integer\": {\n if (typeof value !== \"number\") {\n return {\n field: path,\n message: `${label} must be a number`,\n severity: \"error\",\n };\n }\n\n if (schema.type === \"integer\" && !Number.isInteger(value)) {\n return {\n field: path,\n message: `${label} must be a whole number`,\n severity: \"error\",\n };\n }\n\n if (\"minimum\" in schema && schema.minimum !== undefined) {\n if (value < schema.minimum) {\n return {\n field: path,\n message: `${label} must be at least ${schema.minimum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"maximum\" in schema && schema.maximum !== undefined) {\n if (value > schema.maximum) {\n return {\n field: path,\n message: `${label} must be no more than ${schema.maximum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"exclusiveMinimum\" in schema && schema.exclusiveMinimum !== undefined) {\n if (value <= schema.exclusiveMinimum) {\n return {\n field: path,\n message: `${label} must be greater than ${schema.exclusiveMinimum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"exclusiveMaximum\" in schema && schema.exclusiveMaximum !== undefined) {\n if (value >= schema.exclusiveMaximum) {\n return {\n field: path,\n message: `${label} must be less than ${schema.exclusiveMaximum}`,\n severity: \"error\",\n };\n }\n }\n\n if (\"multipleOf\" in schema && schema.multipleOf !== undefined) {\n const multipleOf = schema.multipleOf;\n // Use epsilon comparison to handle floating point precision issues\n const remainder = Math.abs(value % multipleOf);\n const isValid = remainder < 1e-10 || Math.abs(remainder - multipleOf) < 1e-10;\n if (!isValid) {\n return {\n field: path,\n message: `${label} must be a multiple of ${multipleOf}`,\n severity: \"error\",\n };\n }\n }\n\n return null;\n }\n\n case \"boolean\": {\n if (typeof value !== \"boolean\") {\n return {\n field: path,\n message: `${label} must be true or false`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"array\": {\n if (!Array.isArray(value)) {\n return {\n field: path,\n message: `${label} must be a list`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"object\": {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return {\n field: path,\n message: `${label} must be an object`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Validate string format\n */\nfunction validateFormat(\n path: string,\n value: string,\n format: string,\n label: string\n): FieldError | null {\n switch (format) {\n case \"email\": {\n // Simple email regex\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid email address`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"date\": {\n // ISO date format YYYY-MM-DD\n const dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n if (!dateRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid date`,\n severity: \"error\",\n };\n }\n // Verify the date is actually valid (e.g., not Feb 30)\n const parsed = new Date(value + \"T00:00:00Z\");\n if (isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== value) {\n return {\n field: path,\n message: `${label} must be a valid date`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"date-time\": {\n if (isNaN(Date.parse(value))) {\n return {\n field: path,\n message: `${label} must be a valid date and time`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n case \"uri\": {\n try {\n new URL(value);\n return null;\n } catch {\n return {\n field: path,\n message: `${label} must be a valid URL`,\n severity: \"error\",\n };\n }\n }\n\n case \"uuid\": {\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n if (!uuidRegex.test(value)) {\n return {\n field: path,\n message: `${label} must be a valid UUID`,\n severity: \"error\",\n };\n }\n return null;\n }\n\n default:\n return null;\n }\n}\n\n// ============================================================================\n// Custom Rule Validation\n// ============================================================================\n\n/**\n * Validate custom FEEL validation rules\n */\nfunction validateCustomRules(\n path: string,\n rules: ValidationRule[],\n context: EvaluationContext\n): FieldError[] {\n const errors: FieldError[] = [];\n\n for (const rule of rules) {\n const isValid = evaluateBoolean(rule.rule, context);\n\n if (!isValid) {\n errors.push({\n field: path,\n message: rule.message,\n severity: rule.severity ?? \"error\",\n });\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// Array Validation\n// ============================================================================\n\n/**\n * Validate array field including items\n */\nfunction validateArray(\n path: string,\n value: unknown[],\n fieldDef: FieldDefinition,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n const label = fieldDef.label ?? path;\n\n // Check min/max items\n if (fieldDef.minItems !== undefined && value.length < fieldDef.minItems) {\n errors.push({\n field: path,\n message: `${label} must have at least ${fieldDef.minItems} items`,\n severity: \"error\",\n });\n }\n\n if (fieldDef.maxItems !== undefined && value.length > fieldDef.maxItems) {\n errors.push({\n field: path,\n message: `${label} must have no more than ${fieldDef.maxItems} items`,\n severity: \"error\",\n });\n }\n\n // Validate each item's fields\n if (fieldDef.itemFields) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i] as Record<string, unknown>;\n const itemErrors = validateArrayItem(\n path,\n i,\n item,\n fieldDef.itemFields,\n spec,\n data,\n computed,\n visibility,\n onlyVisible\n );\n errors.push(...itemErrors);\n }\n }\n\n return errors;\n}\n\n/**\n * Validate fields within a single array item\n */\nfunction validateArrayItem(\n arrayPath: string,\n index: number,\n item: Record<string, unknown>,\n itemFields: Record<string, FieldDefinition>,\n spec: Forma,\n data: Record<string, unknown>,\n computed: Record<string, unknown>,\n visibility: Record<string, boolean>,\n onlyVisible: boolean\n): FieldError[] {\n const errors: FieldError[] = [];\n\n for (const [fieldName, fieldDef] of Object.entries(itemFields)) {\n const itemFieldPath = `${arrayPath}[${index}].${fieldName}`;\n\n // Skip hidden fields\n if (onlyVisible && visibility[itemFieldPath] === false) {\n continue;\n }\n\n const value = item[fieldName];\n const context: EvaluationContext = {\n data,\n computed,\n referenceData: spec.referenceData,\n item,\n itemIndex: index,\n value,\n };\n\n // Required check\n const isRequired = fieldDef.requiredWhen\n ? evaluateBoolean(fieldDef.requiredWhen, context)\n : false;\n\n if (isRequired && isEmpty(value)) {\n errors.push({\n field: itemFieldPath,\n message: fieldDef.label\n ? `${fieldDef.label} is required`\n : \"This field is required\",\n severity: \"error\",\n });\n }\n\n // Custom validations\n if (fieldDef.validations && !isEmpty(value)) {\n const customErrors = validateCustomRules(itemFieldPath, fieldDef.validations, context);\n errors.push(...customErrors);\n }\n }\n\n return errors;\n}\n\n// ============================================================================\n// Single Field Validation\n// ============================================================================\n\n/**\n * Validate a single field\n *\n * @param fieldPath - Path to the field\n * @param data - Current form data\n * @param spec - Form specification\n * @returns Array of errors for this field\n */\nexport function validateSingleField(\n fieldPath: string,\n data: Record<string, unknown>,\n spec: Forma\n): FieldError[] {\n const fieldDef = spec.fields[fieldPath];\n if (!fieldDef) {\n return [];\n }\n\n const computed = calculate(data, spec);\n const visibility = getVisibility(data, spec, { computed });\n const schemaProperty = spec.schema.properties[fieldPath];\n\n return validateField(\n fieldPath,\n data[fieldPath],\n fieldDef,\n schemaProperty,\n spec,\n data,\n computed,\n visibility,\n true\n );\n}\n"],"mappings":"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","names":["feelinEvaluate","isRequired"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fogpipe/forma-core
|
|
3
|
+
*
|
|
4
|
+
* Core runtime for Forma dynamic forms.
|
|
5
|
+
* Provides types, FEEL expression evaluation, and form state engines.
|
|
6
|
+
*/
|
|
7
|
+
export type { FEELExpression, JSONSchema, JSONSchemaProperty, JSONSchemaBase, JSONSchemaString, JSONSchemaNumber, JSONSchemaInteger, JSONSchemaBoolean, JSONSchemaArray, JSONSchemaObject, JSONSchemaEnum, FieldType, ValidationRule, SelectOption, FieldDefinition, ComputedField, PageDefinition, FormMeta, Forma, EvaluationContext, VisibilityResult, RequiredResult, RequiredFieldsResult, EnabledResult, FieldError, ValidationResult, CalculationError, CalculationResult, } from "./types.js";
|
|
8
|
+
export * from "./feel/index.js";
|
|
9
|
+
export * from "./engine/index.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EAEV,cAAc,EAEd,UAAU,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,cAAc,EAEd,SAAS,EACT,cAAc,EACd,YAAY,EACZ,eAAe,EACf,aAAa,EACb,cAAc,EACd,QAAQ,EACR,KAAK,EAEL,iBAAiB,EAEjB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,cAAc,iBAAiB,CAAC;AAGhC,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -21,22 +21,22 @@
|
|
|
21
21
|
* "computed.bmi > 30"
|
|
22
22
|
* "item.frequency = \"daily\""
|
|
23
23
|
*/
|
|
24
|
-
type FEELExpression = string;
|
|
24
|
+
export type FEELExpression = string;
|
|
25
25
|
/**
|
|
26
26
|
* Standard JSON Schema (subset we support)
|
|
27
27
|
*/
|
|
28
|
-
interface JSONSchema {
|
|
28
|
+
export interface JSONSchema {
|
|
29
29
|
type: "object";
|
|
30
30
|
properties: Record<string, JSONSchemaProperty>;
|
|
31
31
|
required?: string[];
|
|
32
32
|
$defs?: Record<string, JSONSchemaProperty>;
|
|
33
33
|
}
|
|
34
|
-
type JSONSchemaProperty = JSONSchemaString | JSONSchemaNumber | JSONSchemaInteger | JSONSchemaBoolean | JSONSchemaArray | JSONSchemaObject | JSONSchemaEnum;
|
|
35
|
-
interface JSONSchemaBase {
|
|
34
|
+
export type JSONSchemaProperty = JSONSchemaString | JSONSchemaNumber | JSONSchemaInteger | JSONSchemaBoolean | JSONSchemaArray | JSONSchemaObject | JSONSchemaEnum;
|
|
35
|
+
export interface JSONSchemaBase {
|
|
36
36
|
description?: string;
|
|
37
37
|
title?: string;
|
|
38
38
|
}
|
|
39
|
-
interface JSONSchemaString extends JSONSchemaBase {
|
|
39
|
+
export interface JSONSchemaString extends JSONSchemaBase {
|
|
40
40
|
type: "string";
|
|
41
41
|
minLength?: number;
|
|
42
42
|
maxLength?: number;
|
|
@@ -44,44 +44,46 @@ interface JSONSchemaString extends JSONSchemaBase {
|
|
|
44
44
|
format?: "date" | "date-time" | "email" | "uri" | "uuid";
|
|
45
45
|
enum?: string[];
|
|
46
46
|
}
|
|
47
|
-
interface JSONSchemaNumber extends JSONSchemaBase {
|
|
47
|
+
export interface JSONSchemaNumber extends JSONSchemaBase {
|
|
48
48
|
type: "number";
|
|
49
49
|
minimum?: number;
|
|
50
50
|
maximum?: number;
|
|
51
51
|
exclusiveMinimum?: number;
|
|
52
52
|
exclusiveMaximum?: number;
|
|
53
|
+
multipleOf?: number;
|
|
53
54
|
}
|
|
54
|
-
interface JSONSchemaInteger extends JSONSchemaBase {
|
|
55
|
+
export interface JSONSchemaInteger extends JSONSchemaBase {
|
|
55
56
|
type: "integer";
|
|
56
57
|
minimum?: number;
|
|
57
58
|
maximum?: number;
|
|
59
|
+
multipleOf?: number;
|
|
58
60
|
}
|
|
59
|
-
interface JSONSchemaBoolean extends JSONSchemaBase {
|
|
61
|
+
export interface JSONSchemaBoolean extends JSONSchemaBase {
|
|
60
62
|
type: "boolean";
|
|
61
63
|
}
|
|
62
|
-
interface JSONSchemaArray extends JSONSchemaBase {
|
|
64
|
+
export interface JSONSchemaArray extends JSONSchemaBase {
|
|
63
65
|
type: "array";
|
|
64
66
|
items: JSONSchemaProperty;
|
|
65
67
|
minItems?: number;
|
|
66
68
|
maxItems?: number;
|
|
67
69
|
}
|
|
68
|
-
interface JSONSchemaObject extends JSONSchemaBase {
|
|
70
|
+
export interface JSONSchemaObject extends JSONSchemaBase {
|
|
69
71
|
type: "object";
|
|
70
72
|
properties: Record<string, JSONSchemaProperty>;
|
|
71
73
|
required?: string[];
|
|
72
74
|
}
|
|
73
|
-
interface JSONSchemaEnum extends JSONSchemaBase {
|
|
75
|
+
export interface JSONSchemaEnum extends JSONSchemaBase {
|
|
74
76
|
type: "string";
|
|
75
77
|
enum: string[];
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
78
80
|
* Field type enumeration - maps to UI component types
|
|
79
81
|
*/
|
|
80
|
-
type FieldType = "text" | "password" | "number" | "integer" | "boolean" | "select" | "multiselect" | "date" | "datetime" | "email" | "url" | "textarea" | "array" | "object" | "computed";
|
|
82
|
+
export type FieldType = "text" | "password" | "number" | "integer" | "boolean" | "select" | "multiselect" | "date" | "datetime" | "email" | "url" | "textarea" | "array" | "object" | "computed";
|
|
81
83
|
/**
|
|
82
84
|
* Validation rule with FEEL expression
|
|
83
85
|
*/
|
|
84
|
-
interface ValidationRule {
|
|
86
|
+
export interface ValidationRule {
|
|
85
87
|
/** FEEL expression that should evaluate to true for valid data */
|
|
86
88
|
rule: FEELExpression;
|
|
87
89
|
/** Error message shown when validation fails */
|
|
@@ -92,7 +94,7 @@ interface ValidationRule {
|
|
|
92
94
|
/**
|
|
93
95
|
* Option for select/multiselect fields
|
|
94
96
|
*/
|
|
95
|
-
interface SelectOption {
|
|
97
|
+
export interface SelectOption {
|
|
96
98
|
/** Option value - can be string or number to match schema types */
|
|
97
99
|
value: string | number;
|
|
98
100
|
label: string;
|
|
@@ -102,7 +104,7 @@ interface SelectOption {
|
|
|
102
104
|
/**
|
|
103
105
|
* Field definition with all conditional logic
|
|
104
106
|
*/
|
|
105
|
-
interface FieldDefinition {
|
|
107
|
+
export interface FieldDefinition {
|
|
106
108
|
/** Display label for the field */
|
|
107
109
|
label?: string;
|
|
108
110
|
/** Help text or description */
|
|
@@ -131,7 +133,7 @@ interface FieldDefinition {
|
|
|
131
133
|
/**
|
|
132
134
|
* Computed field definition - derived values from form data
|
|
133
135
|
*/
|
|
134
|
-
interface ComputedField {
|
|
136
|
+
export interface ComputedField {
|
|
135
137
|
/** FEEL expression to calculate the value */
|
|
136
138
|
expression: FEELExpression;
|
|
137
139
|
/** Display label */
|
|
@@ -144,7 +146,7 @@ interface ComputedField {
|
|
|
144
146
|
/**
|
|
145
147
|
* Page definition for multi-step wizard forms
|
|
146
148
|
*/
|
|
147
|
-
interface PageDefinition {
|
|
149
|
+
export interface PageDefinition {
|
|
148
150
|
/** Unique page identifier */
|
|
149
151
|
id: string;
|
|
150
152
|
/** Page title */
|
|
@@ -159,7 +161,7 @@ interface PageDefinition {
|
|
|
159
161
|
/**
|
|
160
162
|
* Form metadata
|
|
161
163
|
*/
|
|
162
|
-
interface FormMeta {
|
|
164
|
+
export interface FormMeta {
|
|
163
165
|
/** Unique form identifier */
|
|
164
166
|
id: string;
|
|
165
167
|
/** Form title */
|
|
@@ -180,7 +182,7 @@ interface FormMeta {
|
|
|
180
182
|
* - Field ordering
|
|
181
183
|
* - Optional wizard/page structure
|
|
182
184
|
*/
|
|
183
|
-
interface Forma {
|
|
185
|
+
export interface Forma {
|
|
184
186
|
/** Schema version identifier */
|
|
185
187
|
$schema?: string;
|
|
186
188
|
/** Spec version */
|
|
@@ -203,7 +205,7 @@ interface Forma {
|
|
|
203
205
|
/**
|
|
204
206
|
* Context provided when evaluating FEEL expressions
|
|
205
207
|
*/
|
|
206
|
-
interface EvaluationContext {
|
|
208
|
+
export interface EvaluationContext {
|
|
207
209
|
/** Current form data */
|
|
208
210
|
data: Record<string, unknown>;
|
|
209
211
|
/** Computed values (calculated before field evaluation) */
|
|
@@ -220,29 +222,29 @@ interface EvaluationContext {
|
|
|
220
222
|
/**
|
|
221
223
|
* Field visibility result - map of field path to visibility state
|
|
222
224
|
*/
|
|
223
|
-
interface VisibilityResult {
|
|
225
|
+
export interface VisibilityResult {
|
|
224
226
|
[fieldPath: string]: boolean;
|
|
225
227
|
}
|
|
226
228
|
/**
|
|
227
229
|
* Required fields result - map of field path to required state
|
|
228
230
|
*/
|
|
229
|
-
interface RequiredResult {
|
|
231
|
+
export interface RequiredResult {
|
|
230
232
|
[fieldPath: string]: boolean;
|
|
231
233
|
}
|
|
232
234
|
/**
|
|
233
235
|
* Alias for RequiredResult (backwards compatibility)
|
|
234
236
|
*/
|
|
235
|
-
type RequiredFieldsResult = RequiredResult;
|
|
237
|
+
export type RequiredFieldsResult = RequiredResult;
|
|
236
238
|
/**
|
|
237
239
|
* Enabled fields result - map of field path to enabled state
|
|
238
240
|
*/
|
|
239
|
-
interface EnabledResult {
|
|
241
|
+
export interface EnabledResult {
|
|
240
242
|
[fieldPath: string]: boolean;
|
|
241
243
|
}
|
|
242
244
|
/**
|
|
243
245
|
* Field validation error
|
|
244
246
|
*/
|
|
245
|
-
interface FieldError {
|
|
247
|
+
export interface FieldError {
|
|
246
248
|
/** Field path that has the error */
|
|
247
249
|
field: string;
|
|
248
250
|
/** Error message */
|
|
@@ -253,7 +255,7 @@ interface FieldError {
|
|
|
253
255
|
/**
|
|
254
256
|
* Validation result
|
|
255
257
|
*/
|
|
256
|
-
interface ValidationResult {
|
|
258
|
+
export interface ValidationResult {
|
|
257
259
|
/** Whether the form data is valid */
|
|
258
260
|
valid: boolean;
|
|
259
261
|
/** List of validation errors */
|
|
@@ -262,7 +264,7 @@ interface ValidationResult {
|
|
|
262
264
|
/**
|
|
263
265
|
* Calculation error
|
|
264
266
|
*/
|
|
265
|
-
interface CalculationError {
|
|
267
|
+
export interface CalculationError {
|
|
266
268
|
/** Computed field name */
|
|
267
269
|
field: string;
|
|
268
270
|
/** Error message */
|
|
@@ -273,11 +275,10 @@ interface CalculationError {
|
|
|
273
275
|
/**
|
|
274
276
|
* Calculation result with potential errors
|
|
275
277
|
*/
|
|
276
|
-
interface CalculationResult {
|
|
278
|
+
export interface CalculationResult {
|
|
277
279
|
/** Computed values */
|
|
278
280
|
values: Record<string, unknown>;
|
|
279
281
|
/** Errors encountered during calculation */
|
|
280
282
|
errors: CalculationError[];
|
|
281
283
|
}
|
|
282
|
-
|
|
283
|
-
export type { ComputedField as C, EvaluationContext as E, FEELExpression as F, JSONSchema as J, PageDefinition as P, RequiredResult as R, SelectOption as S, ValidationRule as V, JSONSchemaProperty as a, JSONSchemaBase as b, JSONSchemaString as c, JSONSchemaNumber as d, JSONSchemaInteger as e, JSONSchemaBoolean as f, JSONSchemaArray as g, JSONSchemaObject as h, JSONSchemaEnum as i, FieldType as j, FieldDefinition as k, FormMeta as l, Forma as m, VisibilityResult as n, RequiredFieldsResult as o, EnabledResult as p, FieldError as q, ValidationResult as r, CalculationError as s, CalculationResult as t };
|
|
284
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fogpipe/forma-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Forma core runtime: Types and evaluation engines for dynamic forms with FEEL expressions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,10 +42,11 @@
|
|
|
42
42
|
"src"
|
|
43
43
|
],
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "tsup",
|
|
45
|
+
"build": "tsup && tsc --emitDeclarationOnly --declaration --declarationDir dist",
|
|
46
46
|
"dev": "tsup --watch",
|
|
47
47
|
"lint": "eslint .",
|
|
48
48
|
"check-types": "tsc --noEmit",
|
|
49
|
+
"check-types:test": "tsc --project tsconfig.test.json --noEmit",
|
|
49
50
|
"test": "vitest run",
|
|
50
51
|
"test:watch": "vitest"
|
|
51
52
|
},
|