@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.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
- definition: fieldDef,
114
- visible: isVisible(fieldDef.visibleWhen, data, externalVars),
115
- dependenciesMet: areDependenciesMet(fieldDef.dependsOn, data, externalVars)
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({ id: rule.customValidatorId, message: rule.message });
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 { id, message } of refineRules) {
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
  }