@waypointjs/core 0.1.5 → 0.1.6

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.ts CHANGED
@@ -36,6 +36,11 @@ interface ValidationRule {
36
36
  message: string;
37
37
  /** For "custom" type: identifier of the validator function registered at runtime */
38
38
  customValidatorId?: string;
39
+ /**
40
+ * Cross-field reference — "stepId.fieldId" path.
41
+ * When set, the comparison target is resolved from journey data instead of using `value`.
42
+ */
43
+ refField?: string;
39
44
  }
40
45
  type BuiltinFieldType = "text" | "number" | "email" | "password" | "tel" | "url" | "textarea" | "select" | "multiselect" | "checkbox" | "radio" | "date" | "file";
41
46
  /** Field type — either a builtin or a custom type id registered at runtime */
@@ -44,12 +49,25 @@ interface SelectOption {
44
49
  label: string;
45
50
  value: string | number;
46
51
  }
52
+ /**
53
+ * A dynamic default rule: if the condition matches, use the given value
54
+ * as the field's default. First matching rule wins.
55
+ */
56
+ interface DynamicDefaultRule {
57
+ when: ConditionGroup;
58
+ value: unknown;
59
+ }
47
60
  interface FieldDefinition {
48
61
  id: string;
49
62
  type: FieldType;
50
63
  label: string;
51
64
  placeholder?: string;
52
65
  defaultValue?: unknown;
66
+ /**
67
+ * Conditional defaults — evaluated in order, first match wins.
68
+ * Falls back to `defaultValue` if no rule matches.
69
+ */
70
+ dynamicDefault?: DynamicDefaultRule[];
53
71
  /** Options for select/multiselect/radio fields (hardcoded) */
54
72
  options?: SelectOption[];
55
73
  /** Reference to an external enum — options resolved at runtime from app-provided enums */
@@ -70,6 +88,8 @@ interface StepDefinition$1 {
70
88
  visibleWhen?: ConditionGroup;
71
89
  /** Whether this step can be used as a resume point */
72
90
  enableResumeFromHere?: boolean;
91
+ /** Whether the user can skip this step without filling required fields */
92
+ skippable?: boolean;
73
93
  }
74
94
  interface ExternalVariable {
75
95
  id: string;
@@ -140,20 +160,21 @@ type JourneyData = Record<string, Record<string, unknown>>;
140
160
  type ExternalVars = Record<string, unknown>;
141
161
  /**
142
162
  * Resolves a field path to its value from the data context.
143
- * - "stepId.fieldId" → journey data
144
- * - "$ext.varId" → external variable
163
+ * - "stepId.fieldId" → journey data
164
+ * - "$ext.varId" → external variable
165
+ * - "$step.stepId.skipped" → whether the step was skipped (boolean)
145
166
  */
146
- declare function resolveFieldValue(path: string, data: JourneyData, externalVars: ExternalVars): unknown;
167
+ declare function resolveFieldValue(path: string, data: JourneyData, externalVars: ExternalVars, skippedSteps?: string[]): unknown;
147
168
  /**
148
169
  * Evaluates a condition group against the current data context.
149
170
  * Returns true if the group's conditions are satisfied.
150
171
  */
151
- declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
172
+ declare function evaluateConditionGroup(group: ConditionGroup, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[], skippedSteps?: string[]): boolean;
152
173
  /**
153
174
  * Convenience: returns true if no condition is defined (always visible),
154
175
  * or if the condition group evaluates to true.
155
176
  */
156
- declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): boolean;
177
+ declare function isVisible(visibleWhen: ConditionGroup | undefined, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[], skippedSteps?: string[]): boolean;
157
178
 
158
179
  /** A field after condition evaluation */
159
180
  interface ResolvedField {
@@ -168,6 +189,11 @@ interface ResolvedField {
168
189
  * Use `field.resolvedOptions ?? field.definition.options` when rendering.
169
190
  */
170
191
  resolvedOptions?: SelectOption[];
192
+ /**
193
+ * Resolved dynamic default value (first matching `dynamicDefault` rule).
194
+ * Use `field.resolvedDefaultValue ?? field.definition.defaultValue` for initial form values.
195
+ */
196
+ resolvedDefaultValue?: unknown;
171
197
  }
172
198
  /** A step after condition evaluation */
173
199
  interface ResolvedStep {
@@ -195,7 +221,7 @@ interface ResolvedTree {
195
221
  *
196
222
  * This function is pure: same inputs always produce same outputs.
197
223
  */
198
- declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[]): ResolvedTree;
224
+ declare function resolveTree(schema: WaypointSchema, data: JourneyData, externalVars: ExternalVars, externalEnums?: ExternalEnum[], skippedSteps?: string[]): ResolvedTree;
199
225
  /**
200
226
  * Returns the index of the step with the given id in the resolved (visible) tree.
201
227
  * Returns -1 if not found.
@@ -230,6 +256,8 @@ interface WaypointRuntimeState {
230
256
  currentStepId: string | null;
231
257
  /** Step IDs visited in order */
232
258
  history: string[];
259
+ /** Step IDs that have been skipped by the user */
260
+ skippedSteps: string[];
233
261
  isSubmitting: boolean;
234
262
  /** True once onComplete has been called (all steps validated) */
235
263
  completed: boolean;
@@ -256,6 +284,10 @@ interface WaypointRuntimeActions {
256
284
  setCurrentStep(stepId: string): void;
257
285
  setIsSubmitting(b: boolean): void;
258
286
  setCompleted(b: boolean): void;
287
+ /** Marks a step as skipped (user chose to bypass it) */
288
+ skipStep(stepId: string): void;
289
+ /** Removes a step from the skipped list (e.g. when user goes back and fills it) */
290
+ unskipStep(stepId: string): void;
259
291
  /**
260
292
  * Truncates history to include only steps up to and including stepId.
261
293
  * Called before navigating forward so stale steps from a previous path are removed.
@@ -306,7 +338,7 @@ declare function registerCustomValidator(id: string, fn: (value: unknown) => boo
306
338
  * - Fields without a `required` validation rule are wrapped in `.optional()`.
307
339
  * - Numeric fields use `z.coerce.number()` so string inputs are coerced.
308
340
  */
309
- declare function buildZodSchema(fields: ResolvedField[], externalEnums?: ExternalEnum[]): z.ZodObject<z.ZodRawShape>;
341
+ declare function buildZodSchema(fields: ResolvedField[], externalEnums?: ExternalEnum[], data?: JourneyData): z.ZodObject<z.ZodRawShape>;
310
342
 
311
343
  /**
312
344
  * Runtime validation for WaypointSchema JSON.
@@ -400,4 +432,4 @@ declare function extractURLParamsFromTree(pathname: string, allSteps: StepDefini
400
432
  declare function extractOnlyMissingParams(pathname: string, allSteps: StepDefinition[], missingParamNames: string[]): WaypointParams;
401
433
  declare function mergeContextParams(userParams: WaypointParams | undefined, pathname: string, allSteps: StepDefinition[], targetURL?: string): WaypointParams;
402
434
 
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 };
435
+ export { type BuiltinFieldType, type ConditionGroup, type ConditionOperator, type ConditionRule, type CreateRuntimeStoreOptions, type CustomTypeDefinition, type DynamicDefaultRule, 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
@@ -3,11 +3,15 @@ import { persist, createJSONStorage } from 'zustand/middleware';
3
3
  import { z } from 'zod';
4
4
 
5
5
  // src/conditions.ts
6
- function resolveFieldValue(path, data, externalVars) {
6
+ function resolveFieldValue(path, data, externalVars, skippedSteps) {
7
7
  if (path.startsWith("$ext.")) {
8
8
  const varId = path.slice(5);
9
9
  return externalVars[varId];
10
10
  }
11
+ if (path.startsWith("$step.") && path.endsWith(".skipped")) {
12
+ const stepId2 = path.slice(6, -8);
13
+ return skippedSteps?.includes(stepId2) ?? false;
14
+ }
11
15
  const dotIndex = path.indexOf(".");
12
16
  if (dotIndex === -1) return void 0;
13
17
  const stepId = path.slice(0, dotIndex);
@@ -63,8 +67,8 @@ function evaluateOperator(operator, actual, expected) {
63
67
  return false;
64
68
  }
65
69
  }
66
- function evaluateRule(rule, data, externalVars, externalEnums) {
67
- const actual = resolveFieldValue(rule.field, data, externalVars);
70
+ function evaluateRule(rule, data, externalVars, externalEnums, skippedSteps) {
71
+ const actual = resolveFieldValue(rule.field, data, externalVars, skippedSteps);
68
72
  if ((rule.operator === "inEnum" || rule.operator === "notInEnum") && externalEnums) {
69
73
  const enumDef = externalEnums.find((e) => e.id === String(rule.value));
70
74
  const values = enumDef?.values.map((v) => String(v.value)) ?? [];
@@ -72,20 +76,20 @@ function evaluateRule(rule, data, externalVars, externalEnums) {
72
76
  }
73
77
  return evaluateOperator(rule.operator, actual, rule.value);
74
78
  }
75
- function evaluateConditionGroup(group, data, externalVars, externalEnums) {
79
+ function evaluateConditionGroup(group, data, externalVars, externalEnums, skippedSteps) {
76
80
  const ruleResults = group.rules.map(
77
- (rule) => evaluateRule(rule, data, externalVars, externalEnums)
81
+ (rule) => evaluateRule(rule, data, externalVars, externalEnums, skippedSteps)
78
82
  );
79
83
  const groupResults = (group.groups ?? []).map(
80
- (subGroup) => evaluateConditionGroup(subGroup, data, externalVars, externalEnums)
84
+ (subGroup) => evaluateConditionGroup(subGroup, data, externalVars, externalEnums, skippedSteps)
81
85
  );
82
86
  const allResults = [...ruleResults, ...groupResults];
83
87
  if (allResults.length === 0) return true;
84
88
  return group.combinator === "and" ? allResults.every(Boolean) : allResults.some(Boolean);
85
89
  }
86
- function isVisible(visibleWhen, data, externalVars, externalEnums) {
90
+ function isVisible(visibleWhen, data, externalVars, externalEnums, skippedSteps) {
87
91
  if (!visibleWhen) return true;
88
- return evaluateConditionGroup(visibleWhen, data, externalVars, externalEnums);
92
+ return evaluateConditionGroup(visibleWhen, data, externalVars, externalEnums, skippedSteps);
89
93
  }
90
94
 
91
95
  // src/tree-resolver.ts
@@ -109,22 +113,32 @@ function findMissingBlockingVars(externalVariables, externalVars, visibleSteps)
109
113
  return value === void 0 || value === null;
110
114
  }).map((extVar) => extVar.id);
111
115
  }
112
- function resolveTree(schema, data, externalVars, externalEnums) {
116
+ function resolveTree(schema, data, externalVars, externalEnums, skippedSteps) {
113
117
  const visibleSteps = [];
114
118
  const hiddenSteps = [];
115
119
  for (const stepDef of schema.steps) {
116
- const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars, externalEnums);
120
+ const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars, externalEnums, skippedSteps);
117
121
  const resolvedFields = stepDef.fields.map((fieldDef) => {
118
122
  let resolvedOptions;
119
123
  if (fieldDef.externalEnumId && externalEnums) {
120
124
  const enumDef = externalEnums.find((e) => e.id === fieldDef.externalEnumId);
121
125
  resolvedOptions = enumDef?.values;
122
126
  }
127
+ let resolvedDefaultValue;
128
+ if (fieldDef.dynamicDefault && fieldDef.dynamicDefault.length > 0) {
129
+ for (const rule of fieldDef.dynamicDefault) {
130
+ if (evaluateConditionGroup(rule.when, data, externalVars, externalEnums, skippedSteps)) {
131
+ resolvedDefaultValue = rule.value;
132
+ break;
133
+ }
134
+ }
135
+ }
123
136
  return {
124
137
  definition: fieldDef,
125
- visible: isVisible(fieldDef.visibleWhen, data, externalVars, externalEnums),
138
+ visible: isVisible(fieldDef.visibleWhen, data, externalVars, externalEnums, skippedSteps),
126
139
  dependenciesMet: areDependenciesMet(fieldDef.dependsOn, data, externalVars),
127
- resolvedOptions
140
+ resolvedOptions,
141
+ resolvedDefaultValue
128
142
  };
129
143
  });
130
144
  const resolvedStep = {
@@ -191,7 +205,7 @@ function getResolvedTree(state) {
191
205
  if (!state.schema) {
192
206
  return { steps: [], hiddenSteps: [], missingExternalVars: [] };
193
207
  }
194
- return resolveTree(state.schema, state.data, state.externalVars);
208
+ return resolveTree(state.schema, state.data, state.externalVars, void 0, state.skippedSteps);
195
209
  }
196
210
  function getCurrentStep(state) {
197
211
  if (!state.currentStepId) return void 0;
@@ -223,6 +237,7 @@ var initialState = {
223
237
  externalVars: {},
224
238
  currentStepId: null,
225
239
  history: [],
240
+ skippedSteps: [],
226
241
  isSubmitting: false,
227
242
  completed: false
228
243
  };
@@ -238,6 +253,7 @@ function buildStateCreator() {
238
253
  externalVars,
239
254
  currentStepId: firstStepId,
240
255
  history: firstStepId ? [firstStepId] : [],
256
+ skippedSteps: [],
241
257
  isSubmitting: false,
242
258
  completed: false
243
259
  });
@@ -279,6 +295,16 @@ function buildStateCreator() {
279
295
  setCompleted(b) {
280
296
  set({ completed: b });
281
297
  },
298
+ skipStep(stepId) {
299
+ set((state) => ({
300
+ skippedSteps: state.skippedSteps.includes(stepId) ? state.skippedSteps : [...state.skippedSteps, stepId]
301
+ }));
302
+ },
303
+ unskipStep(stepId) {
304
+ set((state) => ({
305
+ skippedSteps: state.skippedSteps.filter((id) => id !== stepId)
306
+ }));
307
+ },
282
308
  truncateHistoryAt(stepId) {
283
309
  set((state) => {
284
310
  const idx = state.history.indexOf(stepId);
@@ -317,6 +343,7 @@ function createRuntimeStore(options = {}) {
317
343
  data: state.data,
318
344
  currentStepId: state.currentStepId,
319
345
  history: state.history,
346
+ skippedSteps: state.skippedSteps,
320
347
  completed: state.completed
321
348
  })
322
349
  })
@@ -333,7 +360,13 @@ var customValidatorRegistry = {};
333
360
  function registerCustomValidator(id, fn) {
334
361
  customValidatorRegistry[id] = fn;
335
362
  }
336
- function buildFieldSchema(field, externalEnums) {
363
+ function resolveRuleValue(rule, data) {
364
+ if (rule.refField && data) {
365
+ return resolveFieldValue(rule.refField, data, {});
366
+ }
367
+ return rule.value;
368
+ }
369
+ function buildFieldSchema(field, externalEnums, data) {
337
370
  const rules = field.validation ?? [];
338
371
  const isRequired = rules.some((r) => r.type === "required");
339
372
  const isNumeric = field.type === "number";
@@ -351,28 +384,47 @@ function buildFieldSchema(field, externalEnums) {
351
384
  let numSchema = z.coerce.number({
352
385
  invalid_type_error: "Must be a number"
353
386
  });
387
+ const numRefineRules = [];
354
388
  for (const rule of rules) {
389
+ const rv = resolveRuleValue(rule, data);
390
+ const isRef = !!rule.refField;
355
391
  if (rule.type === "min" || rule.type === "greaterThanOrEqual") {
356
- const n = Number(rule.value);
357
- if (!isNaN(n)) numSchema = numSchema.gte(n, rule.message);
392
+ const n = Number(rv);
393
+ if (!isNaN(n)) {
394
+ if (isRef) numRefineRules.push({ fn: (v) => v >= n, message: rule.message });
395
+ else numSchema = numSchema.gte(n, rule.message);
396
+ }
358
397
  } else if (rule.type === "max" || rule.type === "lessThanOrEqual") {
359
- const n = Number(rule.value);
360
- if (!isNaN(n)) numSchema = numSchema.lte(n, rule.message);
398
+ const n = Number(rv);
399
+ if (!isNaN(n)) {
400
+ if (isRef) numRefineRules.push({ fn: (v) => v <= n, message: rule.message });
401
+ else numSchema = numSchema.lte(n, rule.message);
402
+ }
361
403
  } else if (rule.type === "greaterThan") {
362
- const n = Number(rule.value);
363
- if (!isNaN(n)) numSchema = numSchema.gt(n, rule.message);
404
+ const n = Number(rv);
405
+ if (!isNaN(n)) {
406
+ if (isRef) numRefineRules.push({ fn: (v) => v > n, message: rule.message });
407
+ else numSchema = numSchema.gt(n, rule.message);
408
+ }
364
409
  } else if (rule.type === "lessThan") {
365
- const n = Number(rule.value);
366
- if (!isNaN(n)) numSchema = numSchema.lt(n, rule.message);
410
+ const n = Number(rv);
411
+ if (!isNaN(n)) {
412
+ if (isRef) numRefineRules.push({ fn: (v) => v < n, message: rule.message });
413
+ else numSchema = numSchema.lt(n, rule.message);
414
+ }
367
415
  } else if (rule.type === "equals") {
368
- const n = Number(rule.value);
369
- if (!isNaN(n)) numSchema = numSchema.refine((v) => v === n, rule.message);
416
+ const n = Number(rv);
417
+ if (!isNaN(n)) numRefineRules.push({ fn: (v) => v === n, message: rule.message });
370
418
  } else if (rule.type === "notEquals") {
371
- const n = Number(rule.value);
372
- if (!isNaN(n)) numSchema = numSchema.refine((v) => v !== n, rule.message);
419
+ const n = Number(rv);
420
+ if (!isNaN(n)) numRefineRules.push({ fn: (v) => v !== n, message: rule.message });
373
421
  }
374
422
  }
375
- return isRequired ? numSchema : numSchema.optional();
423
+ let numFinal = isRequired ? numSchema : numSchema.optional();
424
+ for (const { fn, message } of numRefineRules) {
425
+ numFinal = numFinal.refine((v) => v == null || fn(v), message);
426
+ }
427
+ return numFinal;
376
428
  }
377
429
  let strSchema = z.string();
378
430
  const refineRules = [];
@@ -402,54 +454,70 @@ function buildFieldSchema(field, externalEnums) {
402
454
  strSchema = strSchema.regex(new RegExp(String(rule.value)), rule.message);
403
455
  }
404
456
  break;
405
- case "equals":
406
- if (rule.value !== void 0) {
407
- const eq = String(rule.value);
457
+ case "equals": {
458
+ const rv = resolveRuleValue(rule, data);
459
+ if (rv !== void 0) {
460
+ const eq = String(rv);
408
461
  refineRules.push({ fn: (v) => String(v) === eq, message: rule.message });
409
462
  }
410
463
  break;
411
- case "notEquals":
412
- if (rule.value !== void 0) {
413
- const neq = String(rule.value);
464
+ }
465
+ case "notEquals": {
466
+ const rv = resolveRuleValue(rule, data);
467
+ if (rv !== void 0) {
468
+ const neq = String(rv);
414
469
  refineRules.push({ fn: (v) => String(v) !== neq, message: rule.message });
415
470
  }
416
471
  break;
417
- case "greaterThan":
418
- if (rule.value !== void 0) {
419
- const gt = Number(rule.value);
472
+ }
473
+ case "greaterThan": {
474
+ const rv = resolveRuleValue(rule, data);
475
+ if (rv !== void 0) {
476
+ const gt = Number(rv);
420
477
  refineRules.push({ fn: (v) => Number(v) > gt, message: rule.message });
421
478
  }
422
479
  break;
423
- case "greaterThanOrEqual":
424
- if (rule.value !== void 0) {
425
- const gte = Number(rule.value);
480
+ }
481
+ case "greaterThanOrEqual": {
482
+ const rv = resolveRuleValue(rule, data);
483
+ if (rv !== void 0) {
484
+ const gte = Number(rv);
426
485
  refineRules.push({ fn: (v) => Number(v) >= gte, message: rule.message });
427
486
  }
428
487
  break;
429
- case "lessThan":
430
- if (rule.value !== void 0) {
431
- const lt = Number(rule.value);
488
+ }
489
+ case "lessThan": {
490
+ const rv = resolveRuleValue(rule, data);
491
+ if (rv !== void 0) {
492
+ const lt = Number(rv);
432
493
  refineRules.push({ fn: (v) => Number(v) < lt, message: rule.message });
433
494
  }
434
495
  break;
435
- case "lessThanOrEqual":
436
- if (rule.value !== void 0) {
437
- const lte = Number(rule.value);
496
+ }
497
+ case "lessThanOrEqual": {
498
+ const rv = resolveRuleValue(rule, data);
499
+ if (rv !== void 0) {
500
+ const lte = Number(rv);
438
501
  refineRules.push({ fn: (v) => Number(v) <= lte, message: rule.message });
439
502
  }
440
503
  break;
441
- case "contains":
442
- if (rule.value !== void 0) {
443
- const sub = String(rule.value);
504
+ }
505
+ case "contains": {
506
+ const rv = resolveRuleValue(rule, data);
507
+ if (rv !== void 0) {
508
+ const sub = String(rv);
444
509
  refineRules.push({ fn: (v) => String(v).includes(sub), message: rule.message });
445
510
  }
446
511
  break;
447
- case "notContains":
448
- if (rule.value !== void 0) {
449
- const nsub = String(rule.value);
512
+ }
513
+ case "notContains": {
514
+ const rv = resolveRuleValue(rule, data);
515
+ if (rv !== void 0) {
516
+ const nsub = String(rv);
450
517
  refineRules.push({ fn: (v) => !String(v).includes(nsub), message: rule.message });
451
518
  }
452
519
  break;
520
+ }
453
521
  case "matches":
454
522
  if (rule.value !== void 0 && rule.value !== null) {
455
523
  const rx = new RegExp(String(rule.value));
@@ -487,11 +555,11 @@ function buildFieldSchema(field, externalEnums) {
487
555
  }
488
556
  return finalSchema;
489
557
  }
490
- function buildZodSchema(fields, externalEnums) {
558
+ function buildZodSchema(fields, externalEnums, data) {
491
559
  const shape = {};
492
560
  for (const resolvedField of fields) {
493
561
  if (!resolvedField.visible) continue;
494
- shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition, externalEnums);
562
+ shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition, externalEnums, data);
495
563
  }
496
564
  return z.object(shape);
497
565
  }