@waypointjs/core 0.1.2 → 0.1.5
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/index.cjs +118 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -8
- package/dist/index.d.ts +26 -8
- package/dist/index.js +118 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
|
|
7
7
|
* Auto-sufficient tree definition generated by @waypointjs/builder.
|
|
8
8
|
* Versioned to allow non-breaking evolution.
|
|
9
9
|
*/
|
|
10
|
-
type ConditionOperator = "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "in" | "notIn" | "exists" | "notExists" | "matches";
|
|
10
|
+
type ConditionOperator = "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "in" | "notIn" | "exists" | "notExists" | "matches" | "inEnum" | "notInEnum";
|
|
11
11
|
/**
|
|
12
12
|
* A single condition rule.
|
|
13
13
|
* `field` is a dot-path: "stepId.fieldId" for journey data, or "$ext.varId" for external variables.
|
|
@@ -27,7 +27,7 @@ interface ConditionGroup {
|
|
|
27
27
|
rules: ConditionRule[];
|
|
28
28
|
groups?: ConditionGroup[];
|
|
29
29
|
}
|
|
30
|
-
type ValidationRuleType = "required" | "min" | "max" | "minLength" | "maxLength" | "email" | "url" | "regex" | "custom";
|
|
30
|
+
type ValidationRuleType = "required" | "min" | "max" | "minLength" | "maxLength" | "email" | "url" | "regex" | "custom" | "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "matches" | "inEnum" | "notInEnum";
|
|
31
31
|
interface ValidationRule {
|
|
32
32
|
type: ValidationRuleType;
|
|
33
33
|
/** Value for min/max/minLength/maxLength/regex rules */
|
|
@@ -50,8 +50,10 @@ interface FieldDefinition {
|
|
|
50
50
|
label: string;
|
|
51
51
|
placeholder?: string;
|
|
52
52
|
defaultValue?: unknown;
|
|
53
|
-
/** Options for select/multiselect/radio fields */
|
|
53
|
+
/** Options for select/multiselect/radio fields (hardcoded) */
|
|
54
54
|
options?: SelectOption[];
|
|
55
|
+
/** Reference to an external enum — options resolved at runtime from app-provided enums */
|
|
56
|
+
externalEnumId?: string;
|
|
55
57
|
validation?: ValidationRule[];
|
|
56
58
|
/** Controls visibility of this field within its step */
|
|
57
59
|
visibleWhen?: ConditionGroup;
|
|
@@ -82,6 +84,16 @@ interface ExternalVariable {
|
|
|
82
84
|
fieldId?: string;
|
|
83
85
|
}>;
|
|
84
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* An externally-provided list of options for select/multiselect/radio fields.
|
|
89
|
+
* The actual values are injected at runtime (builder prop / runner prop) so
|
|
90
|
+
* the schema only stores a reference (`externalEnumId`).
|
|
91
|
+
*/
|
|
92
|
+
interface ExternalEnum {
|
|
93
|
+
id: string;
|
|
94
|
+
label: string;
|
|
95
|
+
values: SelectOption[];
|
|
96
|
+
}
|
|
85
97
|
/**
|
|
86
98
|
* A custom field type registered in the builder.
|
|
87
99
|
* `metadata` is passed through as-is so the backend can enrich it.
|
|
@@ -136,12 +148,12 @@ declare function resolveFieldValue(path: string, data: JourneyData, externalVars
|
|
|
136
148
|
* Evaluates a condition group against the current data context.
|
|
137
149
|
* Returns true if the group's conditions are satisfied.
|
|
138
150
|
*/
|
|
139
|
-
declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars): boolean;
|
|
151
|
+
declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
|
|
140
152
|
/**
|
|
141
153
|
* Convenience: returns true if no condition is defined (always visible),
|
|
142
154
|
* or if the condition group evaluates to true.
|
|
143
155
|
*/
|
|
144
|
-
declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars): boolean;
|
|
156
|
+
declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
|
|
145
157
|
|
|
146
158
|
/** A field after condition evaluation */
|
|
147
159
|
interface ResolvedField {
|
|
@@ -150,6 +162,12 @@ interface ResolvedField {
|
|
|
150
162
|
visible: boolean;
|
|
151
163
|
/** Whether all dependsOn paths have a non-empty value */
|
|
152
164
|
dependenciesMet: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Resolved options from an external enum.
|
|
167
|
+
* Set when `definition.externalEnumId` matches an enum in the provided `externalEnums`.
|
|
168
|
+
* Use `field.resolvedOptions ?? field.definition.options` when rendering.
|
|
169
|
+
*/
|
|
170
|
+
resolvedOptions?: SelectOption[];
|
|
153
171
|
}
|
|
154
172
|
/** A step after condition evaluation */
|
|
155
173
|
interface ResolvedStep {
|
|
@@ -177,7 +195,7 @@ interface ResolvedTree {
|
|
|
177
195
|
*
|
|
178
196
|
* This function is pure: same inputs always produce same outputs.
|
|
179
197
|
*/
|
|
180
|
-
declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars): ResolvedTree;
|
|
198
|
+
declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): ResolvedTree;
|
|
181
199
|
/**
|
|
182
200
|
* Returns the index of the step with the given id in the resolved (visible) tree.
|
|
183
201
|
* Returns -1 if not found.
|
|
@@ -288,7 +306,7 @@ declare function registerCustomValidator(id: string, fn: (value: unknown) => boo
|
|
|
288
306
|
* - Fields without a `required` validation rule are wrapped in `.optional()`.
|
|
289
307
|
* - Numeric fields use `z.coerce.number()` so string inputs are coerced.
|
|
290
308
|
*/
|
|
291
|
-
declare function buildZodSchema(fields: ResolvedField[]): z.ZodObject<z.ZodRawShape>;
|
|
309
|
+
declare function buildZodSchema(fields: ResolvedField[], externalEnums?: ExternalEnum[]): z.ZodObject<z.ZodRawShape>;
|
|
292
310
|
|
|
293
311
|
/**
|
|
294
312
|
* Runtime validation for WaypointSchema JSON.
|
|
@@ -382,4 +400,4 @@ declare function extractURLParamsFromTree(pathname: string, allSteps: StepDefini
|
|
|
382
400
|
declare function extractOnlyMissingParams(pathname: string, allSteps: StepDefinition[], missingParamNames: string[]): WaypointParams;
|
|
383
401
|
declare function mergeContextParams(userParams: WaypointParams | undefined, pathname: string, allSteps: StepDefinition[], targetURL?: string): WaypointParams;
|
|
384
402
|
|
|
385
|
-
export { type BuiltinFieldType, type ConditionGroup, type ConditionOperator, type ConditionRule, type CreateRuntimeStoreOptions, type CustomTypeDefinition, type ExternalVariable, type ExternalVars, type FieldDefinition, type FieldType, type JourneyData, type JourneyState, type JourneyTreeStep, type JourneyTreeType, type PersistenceMode, type ResolvedField, type ResolvedStep, type ResolvedTree, type RuntimeStore, type SchemaValidationResult, type SelectOption, type StepDefinition$1 as StepDefinition, URLTemplateEngine, type ValidationRule, type ValidationRuleType, type WaypointParams, type WaypointRuntimeActions, type WaypointRuntimeState, type WaypointRuntimeStore, type WaypointSchema, assertSchema, buildZodSchema, calculateProgress, calculateProgressFromState, createRuntimeStore, evaluateConditionGroup, extractOnlyMissingParams, extractURLParamsFromTree, findLastValidStep, findMatchingStep, findStepIndex, getCurrentStep, getMissingBlockingVars, getNextStep, getNextStepFromState, getPreviousStep, getPreviousStepFromState, getResolvedTree, hasPersistedState, isVisible, mergeContextParams, registerCustomValidator, resolveFieldValue, resolveTree, validateSchema };
|
|
403
|
+
export { type BuiltinFieldType, type ConditionGroup, type ConditionOperator, type ConditionRule, type CreateRuntimeStoreOptions, type CustomTypeDefinition, type ExternalEnum, type ExternalVariable, type ExternalVars, type FieldDefinition, type FieldType, type JourneyData, type JourneyState, type JourneyTreeStep, type JourneyTreeType, type PersistenceMode, type ResolvedField, type ResolvedStep, type ResolvedTree, type RuntimeStore, type SchemaValidationResult, type SelectOption, type StepDefinition$1 as StepDefinition, URLTemplateEngine, type ValidationRule, type ValidationRuleType, type WaypointParams, type WaypointRuntimeActions, type WaypointRuntimeState, type WaypointRuntimeStore, type WaypointSchema, assertSchema, buildZodSchema, calculateProgress, calculateProgressFromState, createRuntimeStore, evaluateConditionGroup, extractOnlyMissingParams, extractURLParamsFromTree, findLastValidStep, findMatchingStep, findStepIndex, getCurrentStep, getMissingBlockingVars, getNextStep, getNextStepFromState, getPreviousStep, getPreviousStepFromState, getResolvedTree, hasPersistedState, isVisible, mergeContextParams, registerCustomValidator, resolveFieldValue, resolveTree, validateSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
|
|
7
7
|
* Auto-sufficient tree definition generated by @waypointjs/builder.
|
|
8
8
|
* Versioned to allow non-breaking evolution.
|
|
9
9
|
*/
|
|
10
|
-
type ConditionOperator = "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "in" | "notIn" | "exists" | "notExists" | "matches";
|
|
10
|
+
type ConditionOperator = "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "in" | "notIn" | "exists" | "notExists" | "matches" | "inEnum" | "notInEnum";
|
|
11
11
|
/**
|
|
12
12
|
* A single condition rule.
|
|
13
13
|
* `field` is a dot-path: "stepId.fieldId" for journey data, or "$ext.varId" for external variables.
|
|
@@ -27,7 +27,7 @@ interface ConditionGroup {
|
|
|
27
27
|
rules: ConditionRule[];
|
|
28
28
|
groups?: ConditionGroup[];
|
|
29
29
|
}
|
|
30
|
-
type ValidationRuleType = "required" | "min" | "max" | "minLength" | "maxLength" | "email" | "url" | "regex" | "custom";
|
|
30
|
+
type ValidationRuleType = "required" | "min" | "max" | "minLength" | "maxLength" | "email" | "url" | "regex" | "custom" | "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "contains" | "notContains" | "matches" | "inEnum" | "notInEnum";
|
|
31
31
|
interface ValidationRule {
|
|
32
32
|
type: ValidationRuleType;
|
|
33
33
|
/** Value for min/max/minLength/maxLength/regex rules */
|
|
@@ -50,8 +50,10 @@ interface FieldDefinition {
|
|
|
50
50
|
label: string;
|
|
51
51
|
placeholder?: string;
|
|
52
52
|
defaultValue?: unknown;
|
|
53
|
-
/** Options for select/multiselect/radio fields */
|
|
53
|
+
/** Options for select/multiselect/radio fields (hardcoded) */
|
|
54
54
|
options?: SelectOption[];
|
|
55
|
+
/** Reference to an external enum — options resolved at runtime from app-provided enums */
|
|
56
|
+
externalEnumId?: string;
|
|
55
57
|
validation?: ValidationRule[];
|
|
56
58
|
/** Controls visibility of this field within its step */
|
|
57
59
|
visibleWhen?: ConditionGroup;
|
|
@@ -82,6 +84,16 @@ interface ExternalVariable {
|
|
|
82
84
|
fieldId?: string;
|
|
83
85
|
}>;
|
|
84
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* An externally-provided list of options for select/multiselect/radio fields.
|
|
89
|
+
* The actual values are injected at runtime (builder prop / runner prop) so
|
|
90
|
+
* the schema only stores a reference (`externalEnumId`).
|
|
91
|
+
*/
|
|
92
|
+
interface ExternalEnum {
|
|
93
|
+
id: string;
|
|
94
|
+
label: string;
|
|
95
|
+
values: SelectOption[];
|
|
96
|
+
}
|
|
85
97
|
/**
|
|
86
98
|
* A custom field type registered in the builder.
|
|
87
99
|
* `metadata` is passed through as-is so the backend can enrich it.
|
|
@@ -136,12 +148,12 @@ declare function resolveFieldValue(path: string, data: JourneyData, externalVars
|
|
|
136
148
|
* Evaluates a condition group against the current data context.
|
|
137
149
|
* Returns true if the group's conditions are satisfied.
|
|
138
150
|
*/
|
|
139
|
-
declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars): boolean;
|
|
151
|
+
declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
|
|
140
152
|
/**
|
|
141
153
|
* Convenience: returns true if no condition is defined (always visible),
|
|
142
154
|
* or if the condition group evaluates to true.
|
|
143
155
|
*/
|
|
144
|
-
declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars): boolean;
|
|
156
|
+
declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
|
|
145
157
|
|
|
146
158
|
/** A field after condition evaluation */
|
|
147
159
|
interface ResolvedField {
|
|
@@ -150,6 +162,12 @@ interface ResolvedField {
|
|
|
150
162
|
visible: boolean;
|
|
151
163
|
/** Whether all dependsOn paths have a non-empty value */
|
|
152
164
|
dependenciesMet: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Resolved options from an external enum.
|
|
167
|
+
* Set when `definition.externalEnumId` matches an enum in the provided `externalEnums`.
|
|
168
|
+
* Use `field.resolvedOptions ?? field.definition.options` when rendering.
|
|
169
|
+
*/
|
|
170
|
+
resolvedOptions?: SelectOption[];
|
|
153
171
|
}
|
|
154
172
|
/** A step after condition evaluation */
|
|
155
173
|
interface ResolvedStep {
|
|
@@ -177,7 +195,7 @@ interface ResolvedTree {
|
|
|
177
195
|
*
|
|
178
196
|
* This function is pure: same inputs always produce same outputs.
|
|
179
197
|
*/
|
|
180
|
-
declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars): ResolvedTree;
|
|
198
|
+
declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): ResolvedTree;
|
|
181
199
|
/**
|
|
182
200
|
* Returns the index of the step with the given id in the resolved (visible) tree.
|
|
183
201
|
* Returns -1 if not found.
|
|
@@ -288,7 +306,7 @@ declare function registerCustomValidator(id: string, fn: (value: unknown) => boo
|
|
|
288
306
|
* - Fields without a `required` validation rule are wrapped in `.optional()`.
|
|
289
307
|
* - Numeric fields use `z.coerce.number()` so string inputs are coerced.
|
|
290
308
|
*/
|
|
291
|
-
declare function buildZodSchema(fields: ResolvedField[]): z.ZodObject<z.ZodRawShape>;
|
|
309
|
+
declare function buildZodSchema(fields: ResolvedField[], externalEnums?: ExternalEnum[]): z.ZodObject<z.ZodRawShape>;
|
|
292
310
|
|
|
293
311
|
/**
|
|
294
312
|
* Runtime validation for WaypointSchema JSON.
|
|
@@ -382,4 +400,4 @@ declare function extractURLParamsFromTree(pathname: string, allSteps: StepDefini
|
|
|
382
400
|
declare function extractOnlyMissingParams(pathname: string, allSteps: StepDefinition[], missingParamNames: string[]): WaypointParams;
|
|
383
401
|
declare function mergeContextParams(userParams: WaypointParams | undefined, pathname: string, allSteps: StepDefinition[], targetURL?: string): WaypointParams;
|
|
384
402
|
|
|
385
|
-
export { type BuiltinFieldType, type ConditionGroup, type ConditionOperator, type ConditionRule, type CreateRuntimeStoreOptions, type CustomTypeDefinition, type ExternalVariable, type ExternalVars, type FieldDefinition, type FieldType, type JourneyData, type JourneyState, type JourneyTreeStep, type JourneyTreeType, type PersistenceMode, type ResolvedField, type ResolvedStep, type ResolvedTree, type RuntimeStore, type SchemaValidationResult, type SelectOption, type StepDefinition$1 as StepDefinition, URLTemplateEngine, type ValidationRule, type ValidationRuleType, type WaypointParams, type WaypointRuntimeActions, type WaypointRuntimeState, type WaypointRuntimeStore, type WaypointSchema, assertSchema, buildZodSchema, calculateProgress, calculateProgressFromState, createRuntimeStore, evaluateConditionGroup, extractOnlyMissingParams, extractURLParamsFromTree, findLastValidStep, findMatchingStep, findStepIndex, getCurrentStep, getMissingBlockingVars, getNextStep, getNextStepFromState, getPreviousStep, getPreviousStepFromState, getResolvedTree, hasPersistedState, isVisible, mergeContextParams, registerCustomValidator, resolveFieldValue, resolveTree, validateSchema };
|
|
403
|
+
export { type BuiltinFieldType, type ConditionGroup, type ConditionOperator, type ConditionRule, type CreateRuntimeStoreOptions, type CustomTypeDefinition, type ExternalEnum, type ExternalVariable, type ExternalVars, type FieldDefinition, type FieldType, type JourneyData, type JourneyState, type JourneyTreeStep, type JourneyTreeType, type PersistenceMode, type ResolvedField, type ResolvedStep, type ResolvedTree, type RuntimeStore, type SchemaValidationResult, type SelectOption, type StepDefinition$1 as StepDefinition, URLTemplateEngine, type ValidationRule, type ValidationRuleType, type WaypointParams, type WaypointRuntimeActions, type WaypointRuntimeState, type WaypointRuntimeStore, type WaypointSchema, assertSchema, buildZodSchema, calculateProgress, calculateProgressFromState, createRuntimeStore, evaluateConditionGroup, extractOnlyMissingParams, extractURLParamsFromTree, findLastValidStep, findMatchingStep, findStepIndex, getCurrentStep, getMissingBlockingVars, getNextStep, getNextStepFromState, getPreviousStep, getPreviousStepFromState, getResolvedTree, hasPersistedState, isVisible, mergeContextParams, registerCustomValidator, resolveFieldValue, resolveTree, validateSchema };
|
package/dist/index.js
CHANGED
|
@@ -63,24 +63,29 @@ function evaluateOperator(operator, actual, expected) {
|
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
function evaluateRule(rule, data, externalVars) {
|
|
66
|
+
function evaluateRule(rule, data, externalVars, externalEnums) {
|
|
67
67
|
const actual = resolveFieldValue(rule.field, data, externalVars);
|
|
68
|
+
if ((rule.operator === "inEnum" || rule.operator === "notInEnum") && externalEnums) {
|
|
69
|
+
const enumDef = externalEnums.find((e) => e.id === String(rule.value));
|
|
70
|
+
const values = enumDef?.values.map((v) => String(v.value)) ?? [];
|
|
71
|
+
return rule.operator === "inEnum" ? values.includes(String(actual)) : !values.includes(String(actual));
|
|
72
|
+
}
|
|
68
73
|
return evaluateOperator(rule.operator, actual, rule.value);
|
|
69
74
|
}
|
|
70
|
-
function evaluateConditionGroup(group, data, externalVars) {
|
|
75
|
+
function evaluateConditionGroup(group, data, externalVars, externalEnums) {
|
|
71
76
|
const ruleResults = group.rules.map(
|
|
72
|
-
(rule) => evaluateRule(rule, data, externalVars)
|
|
77
|
+
(rule) => evaluateRule(rule, data, externalVars, externalEnums)
|
|
73
78
|
);
|
|
74
79
|
const groupResults = (group.groups ?? []).map(
|
|
75
|
-
(subGroup) => evaluateConditionGroup(subGroup, data, externalVars)
|
|
80
|
+
(subGroup) => evaluateConditionGroup(subGroup, data, externalVars, externalEnums)
|
|
76
81
|
);
|
|
77
82
|
const allResults = [...ruleResults, ...groupResults];
|
|
78
83
|
if (allResults.length === 0) return true;
|
|
79
84
|
return group.combinator === "and" ? allResults.every(Boolean) : allResults.some(Boolean);
|
|
80
85
|
}
|
|
81
|
-
function isVisible(visibleWhen, data, externalVars) {
|
|
86
|
+
function isVisible(visibleWhen, data, externalVars, externalEnums) {
|
|
82
87
|
if (!visibleWhen) return true;
|
|
83
|
-
return evaluateConditionGroup(visibleWhen, data, externalVars);
|
|
88
|
+
return evaluateConditionGroup(visibleWhen, data, externalVars, externalEnums);
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
// src/tree-resolver.ts
|
|
@@ -104,16 +109,24 @@ function findMissingBlockingVars(externalVariables, externalVars, visibleSteps)
|
|
|
104
109
|
return value === void 0 || value === null;
|
|
105
110
|
}).map((extVar) => extVar.id);
|
|
106
111
|
}
|
|
107
|
-
function resolveTree(schema, data, externalVars) {
|
|
112
|
+
function resolveTree(schema, data, externalVars, externalEnums) {
|
|
108
113
|
const visibleSteps = [];
|
|
109
114
|
const hiddenSteps = [];
|
|
110
115
|
for (const stepDef of schema.steps) {
|
|
111
|
-
const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars);
|
|
112
|
-
const resolvedFields = stepDef.fields.map((fieldDef) =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars, externalEnums);
|
|
117
|
+
const resolvedFields = stepDef.fields.map((fieldDef) => {
|
|
118
|
+
let resolvedOptions;
|
|
119
|
+
if (fieldDef.externalEnumId && externalEnums) {
|
|
120
|
+
const enumDef = externalEnums.find((e) => e.id === fieldDef.externalEnumId);
|
|
121
|
+
resolvedOptions = enumDef?.values;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
definition: fieldDef,
|
|
125
|
+
visible: isVisible(fieldDef.visibleWhen, data, externalVars, externalEnums),
|
|
126
|
+
dependenciesMet: areDependenciesMet(fieldDef.dependsOn, data, externalVars),
|
|
127
|
+
resolvedOptions
|
|
128
|
+
};
|
|
129
|
+
});
|
|
117
130
|
const resolvedStep = {
|
|
118
131
|
definition: stepDef,
|
|
119
132
|
visible: stepVisible,
|
|
@@ -320,7 +333,7 @@ var customValidatorRegistry = {};
|
|
|
320
333
|
function registerCustomValidator(id, fn) {
|
|
321
334
|
customValidatorRegistry[id] = fn;
|
|
322
335
|
}
|
|
323
|
-
function buildFieldSchema(field) {
|
|
336
|
+
function buildFieldSchema(field, externalEnums) {
|
|
324
337
|
const rules = field.validation ?? [];
|
|
325
338
|
const isRequired = rules.some((r) => r.type === "required");
|
|
326
339
|
const isNumeric = field.type === "number";
|
|
@@ -339,12 +352,24 @@ function buildFieldSchema(field) {
|
|
|
339
352
|
invalid_type_error: "Must be a number"
|
|
340
353
|
});
|
|
341
354
|
for (const rule of rules) {
|
|
342
|
-
if (rule.type === "min") {
|
|
355
|
+
if (rule.type === "min" || rule.type === "greaterThanOrEqual") {
|
|
343
356
|
const n = Number(rule.value);
|
|
344
357
|
if (!isNaN(n)) numSchema = numSchema.gte(n, rule.message);
|
|
345
|
-
} else if (rule.type === "max") {
|
|
358
|
+
} else if (rule.type === "max" || rule.type === "lessThanOrEqual") {
|
|
346
359
|
const n = Number(rule.value);
|
|
347
360
|
if (!isNaN(n)) numSchema = numSchema.lte(n, rule.message);
|
|
361
|
+
} else if (rule.type === "greaterThan") {
|
|
362
|
+
const n = Number(rule.value);
|
|
363
|
+
if (!isNaN(n)) numSchema = numSchema.gt(n, rule.message);
|
|
364
|
+
} else if (rule.type === "lessThan") {
|
|
365
|
+
const n = Number(rule.value);
|
|
366
|
+
if (!isNaN(n)) numSchema = numSchema.lt(n, rule.message);
|
|
367
|
+
} else if (rule.type === "equals") {
|
|
368
|
+
const n = Number(rule.value);
|
|
369
|
+
if (!isNaN(n)) numSchema = numSchema.refine((v) => v === n, rule.message);
|
|
370
|
+
} else if (rule.type === "notEquals") {
|
|
371
|
+
const n = Number(rule.value);
|
|
372
|
+
if (!isNaN(n)) numSchema = numSchema.refine((v) => v !== n, rule.message);
|
|
348
373
|
}
|
|
349
374
|
}
|
|
350
375
|
return isRequired ? numSchema : numSchema.optional();
|
|
@@ -377,27 +402,96 @@ function buildFieldSchema(field) {
|
|
|
377
402
|
strSchema = strSchema.regex(new RegExp(String(rule.value)), rule.message);
|
|
378
403
|
}
|
|
379
404
|
break;
|
|
405
|
+
case "equals":
|
|
406
|
+
if (rule.value !== void 0) {
|
|
407
|
+
const eq = String(rule.value);
|
|
408
|
+
refineRules.push({ fn: (v) => String(v) === eq, message: rule.message });
|
|
409
|
+
}
|
|
410
|
+
break;
|
|
411
|
+
case "notEquals":
|
|
412
|
+
if (rule.value !== void 0) {
|
|
413
|
+
const neq = String(rule.value);
|
|
414
|
+
refineRules.push({ fn: (v) => String(v) !== neq, message: rule.message });
|
|
415
|
+
}
|
|
416
|
+
break;
|
|
417
|
+
case "greaterThan":
|
|
418
|
+
if (rule.value !== void 0) {
|
|
419
|
+
const gt = Number(rule.value);
|
|
420
|
+
refineRules.push({ fn: (v) => Number(v) > gt, message: rule.message });
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
case "greaterThanOrEqual":
|
|
424
|
+
if (rule.value !== void 0) {
|
|
425
|
+
const gte = Number(rule.value);
|
|
426
|
+
refineRules.push({ fn: (v) => Number(v) >= gte, message: rule.message });
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
case "lessThan":
|
|
430
|
+
if (rule.value !== void 0) {
|
|
431
|
+
const lt = Number(rule.value);
|
|
432
|
+
refineRules.push({ fn: (v) => Number(v) < lt, message: rule.message });
|
|
433
|
+
}
|
|
434
|
+
break;
|
|
435
|
+
case "lessThanOrEqual":
|
|
436
|
+
if (rule.value !== void 0) {
|
|
437
|
+
const lte = Number(rule.value);
|
|
438
|
+
refineRules.push({ fn: (v) => Number(v) <= lte, message: rule.message });
|
|
439
|
+
}
|
|
440
|
+
break;
|
|
441
|
+
case "contains":
|
|
442
|
+
if (rule.value !== void 0) {
|
|
443
|
+
const sub = String(rule.value);
|
|
444
|
+
refineRules.push({ fn: (v) => String(v).includes(sub), message: rule.message });
|
|
445
|
+
}
|
|
446
|
+
break;
|
|
447
|
+
case "notContains":
|
|
448
|
+
if (rule.value !== void 0) {
|
|
449
|
+
const nsub = String(rule.value);
|
|
450
|
+
refineRules.push({ fn: (v) => !String(v).includes(nsub), message: rule.message });
|
|
451
|
+
}
|
|
452
|
+
break;
|
|
453
|
+
case "matches":
|
|
454
|
+
if (rule.value !== void 0 && rule.value !== null) {
|
|
455
|
+
const rx = new RegExp(String(rule.value));
|
|
456
|
+
refineRules.push({ fn: (v) => rx.test(String(v)), message: rule.message });
|
|
457
|
+
}
|
|
458
|
+
break;
|
|
459
|
+
case "inEnum":
|
|
460
|
+
if (rule.value && externalEnums) {
|
|
461
|
+
const enumDef = externalEnums.find((e) => e.id === String(rule.value));
|
|
462
|
+
if (enumDef) {
|
|
463
|
+
const values = enumDef.values.map((v) => String(v.value));
|
|
464
|
+
refineRules.push({ fn: (v) => values.includes(String(v)), message: rule.message });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
break;
|
|
468
|
+
case "notInEnum":
|
|
469
|
+
if (rule.value && externalEnums) {
|
|
470
|
+
const enumDef = externalEnums.find((e) => e.id === String(rule.value));
|
|
471
|
+
if (enumDef) {
|
|
472
|
+
const values = enumDef.values.map((v) => String(v.value));
|
|
473
|
+
refineRules.push({ fn: (v) => !values.includes(String(v)), message: rule.message });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
380
477
|
case "custom":
|
|
381
478
|
if (rule.customValidatorId && customValidatorRegistry[rule.customValidatorId]) {
|
|
382
|
-
refineRules.push({
|
|
479
|
+
refineRules.push({ fn: (v) => Boolean(customValidatorRegistry[rule.customValidatorId]?.(v)), message: rule.message });
|
|
383
480
|
}
|
|
384
481
|
break;
|
|
385
482
|
}
|
|
386
483
|
}
|
|
387
484
|
let finalSchema = isRequired ? strSchema : strSchema.optional();
|
|
388
|
-
for (const {
|
|
389
|
-
finalSchema = finalSchema.refine(
|
|
390
|
-
(val) => Boolean(customValidatorRegistry[id]?.(val)),
|
|
391
|
-
message
|
|
392
|
-
);
|
|
485
|
+
for (const { fn, message } of refineRules) {
|
|
486
|
+
finalSchema = finalSchema.refine(fn, message);
|
|
393
487
|
}
|
|
394
488
|
return finalSchema;
|
|
395
489
|
}
|
|
396
|
-
function buildZodSchema(fields) {
|
|
490
|
+
function buildZodSchema(fields, externalEnums) {
|
|
397
491
|
const shape = {};
|
|
398
492
|
for (const resolvedField of fields) {
|
|
399
493
|
if (!resolvedField.visible) continue;
|
|
400
|
-
shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition);
|
|
494
|
+
shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition, externalEnums);
|
|
401
495
|
}
|
|
402
496
|
return z.object(shape);
|
|
403
497
|
}
|