@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.cjs CHANGED
@@ -5,11 +5,15 @@ var middleware = require('zustand/middleware');
5
5
  var zod = require('zod');
6
6
 
7
7
  // src/conditions.ts
8
- function resolveFieldValue(path, data, externalVars) {
8
+ function resolveFieldValue(path, data, externalVars, skippedSteps) {
9
9
  if (path.startsWith("$ext.")) {
10
10
  const varId = path.slice(5);
11
11
  return externalVars[varId];
12
12
  }
13
+ if (path.startsWith("$step.") && path.endsWith(".skipped")) {
14
+ const stepId2 = path.slice(6, -8);
15
+ return skippedSteps?.includes(stepId2) ?? false;
16
+ }
13
17
  const dotIndex = path.indexOf(".");
14
18
  if (dotIndex === -1) return void 0;
15
19
  const stepId = path.slice(0, dotIndex);
@@ -65,8 +69,8 @@ function evaluateOperator(operator, actual, expected) {
65
69
  return false;
66
70
  }
67
71
  }
68
- function evaluateRule(rule, data, externalVars, externalEnums) {
69
- const actual = resolveFieldValue(rule.field, data, externalVars);
72
+ function evaluateRule(rule, data, externalVars, externalEnums, skippedSteps) {
73
+ const actual = resolveFieldValue(rule.field, data, externalVars, skippedSteps);
70
74
  if ((rule.operator === "inEnum" || rule.operator === "notInEnum") && externalEnums) {
71
75
  const enumDef = externalEnums.find((e) => e.id === String(rule.value));
72
76
  const values = enumDef?.values.map((v) => String(v.value)) ?? [];
@@ -74,20 +78,20 @@ function evaluateRule(rule, data, externalVars, externalEnums) {
74
78
  }
75
79
  return evaluateOperator(rule.operator, actual, rule.value);
76
80
  }
77
- function evaluateConditionGroup(group, data, externalVars, externalEnums) {
81
+ function evaluateConditionGroup(group, data, externalVars, externalEnums, skippedSteps) {
78
82
  const ruleResults = group.rules.map(
79
- (rule) => evaluateRule(rule, data, externalVars, externalEnums)
83
+ (rule) => evaluateRule(rule, data, externalVars, externalEnums, skippedSteps)
80
84
  );
81
85
  const groupResults = (group.groups ?? []).map(
82
- (subGroup) => evaluateConditionGroup(subGroup, data, externalVars, externalEnums)
86
+ (subGroup) => evaluateConditionGroup(subGroup, data, externalVars, externalEnums, skippedSteps)
83
87
  );
84
88
  const allResults = [...ruleResults, ...groupResults];
85
89
  if (allResults.length === 0) return true;
86
90
  return group.combinator === "and" ? allResults.every(Boolean) : allResults.some(Boolean);
87
91
  }
88
- function isVisible(visibleWhen, data, externalVars, externalEnums) {
92
+ function isVisible(visibleWhen, data, externalVars, externalEnums, skippedSteps) {
89
93
  if (!visibleWhen) return true;
90
- return evaluateConditionGroup(visibleWhen, data, externalVars, externalEnums);
94
+ return evaluateConditionGroup(visibleWhen, data, externalVars, externalEnums, skippedSteps);
91
95
  }
92
96
 
93
97
  // src/tree-resolver.ts
@@ -111,22 +115,32 @@ function findMissingBlockingVars(externalVariables, externalVars, visibleSteps)
111
115
  return value === void 0 || value === null;
112
116
  }).map((extVar) => extVar.id);
113
117
  }
114
- function resolveTree(schema, data, externalVars, externalEnums) {
118
+ function resolveTree(schema, data, externalVars, externalEnums, skippedSteps) {
115
119
  const visibleSteps = [];
116
120
  const hiddenSteps = [];
117
121
  for (const stepDef of schema.steps) {
118
- const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars, externalEnums);
122
+ const stepVisible = isVisible(stepDef.visibleWhen, data, externalVars, externalEnums, skippedSteps);
119
123
  const resolvedFields = stepDef.fields.map((fieldDef) => {
120
124
  let resolvedOptions;
121
125
  if (fieldDef.externalEnumId && externalEnums) {
122
126
  const enumDef = externalEnums.find((e) => e.id === fieldDef.externalEnumId);
123
127
  resolvedOptions = enumDef?.values;
124
128
  }
129
+ let resolvedDefaultValue;
130
+ if (fieldDef.dynamicDefault && fieldDef.dynamicDefault.length > 0) {
131
+ for (const rule of fieldDef.dynamicDefault) {
132
+ if (evaluateConditionGroup(rule.when, data, externalVars, externalEnums, skippedSteps)) {
133
+ resolvedDefaultValue = rule.value;
134
+ break;
135
+ }
136
+ }
137
+ }
125
138
  return {
126
139
  definition: fieldDef,
127
- visible: isVisible(fieldDef.visibleWhen, data, externalVars, externalEnums),
140
+ visible: isVisible(fieldDef.visibleWhen, data, externalVars, externalEnums, skippedSteps),
128
141
  dependenciesMet: areDependenciesMet(fieldDef.dependsOn, data, externalVars),
129
- resolvedOptions
142
+ resolvedOptions,
143
+ resolvedDefaultValue
130
144
  };
131
145
  });
132
146
  const resolvedStep = {
@@ -193,7 +207,7 @@ function getResolvedTree(state) {
193
207
  if (!state.schema) {
194
208
  return { steps: [], hiddenSteps: [], missingExternalVars: [] };
195
209
  }
196
- return resolveTree(state.schema, state.data, state.externalVars);
210
+ return resolveTree(state.schema, state.data, state.externalVars, void 0, state.skippedSteps);
197
211
  }
198
212
  function getCurrentStep(state) {
199
213
  if (!state.currentStepId) return void 0;
@@ -225,6 +239,7 @@ var initialState = {
225
239
  externalVars: {},
226
240
  currentStepId: null,
227
241
  history: [],
242
+ skippedSteps: [],
228
243
  isSubmitting: false,
229
244
  completed: false
230
245
  };
@@ -240,6 +255,7 @@ function buildStateCreator() {
240
255
  externalVars,
241
256
  currentStepId: firstStepId,
242
257
  history: firstStepId ? [firstStepId] : [],
258
+ skippedSteps: [],
243
259
  isSubmitting: false,
244
260
  completed: false
245
261
  });
@@ -281,6 +297,16 @@ function buildStateCreator() {
281
297
  setCompleted(b) {
282
298
  set({ completed: b });
283
299
  },
300
+ skipStep(stepId) {
301
+ set((state) => ({
302
+ skippedSteps: state.skippedSteps.includes(stepId) ? state.skippedSteps : [...state.skippedSteps, stepId]
303
+ }));
304
+ },
305
+ unskipStep(stepId) {
306
+ set((state) => ({
307
+ skippedSteps: state.skippedSteps.filter((id) => id !== stepId)
308
+ }));
309
+ },
284
310
  truncateHistoryAt(stepId) {
285
311
  set((state) => {
286
312
  const idx = state.history.indexOf(stepId);
@@ -319,6 +345,7 @@ function createRuntimeStore(options = {}) {
319
345
  data: state.data,
320
346
  currentStepId: state.currentStepId,
321
347
  history: state.history,
348
+ skippedSteps: state.skippedSteps,
322
349
  completed: state.completed
323
350
  })
324
351
  })
@@ -335,7 +362,13 @@ var customValidatorRegistry = {};
335
362
  function registerCustomValidator(id, fn) {
336
363
  customValidatorRegistry[id] = fn;
337
364
  }
338
- function buildFieldSchema(field, externalEnums) {
365
+ function resolveRuleValue(rule, data) {
366
+ if (rule.refField && data) {
367
+ return resolveFieldValue(rule.refField, data, {});
368
+ }
369
+ return rule.value;
370
+ }
371
+ function buildFieldSchema(field, externalEnums, data) {
339
372
  const rules = field.validation ?? [];
340
373
  const isRequired = rules.some((r) => r.type === "required");
341
374
  const isNumeric = field.type === "number";
@@ -353,28 +386,47 @@ function buildFieldSchema(field, externalEnums) {
353
386
  let numSchema = zod.z.coerce.number({
354
387
  invalid_type_error: "Must be a number"
355
388
  });
389
+ const numRefineRules = [];
356
390
  for (const rule of rules) {
391
+ const rv = resolveRuleValue(rule, data);
392
+ const isRef = !!rule.refField;
357
393
  if (rule.type === "min" || rule.type === "greaterThanOrEqual") {
358
- const n = Number(rule.value);
359
- if (!isNaN(n)) numSchema = numSchema.gte(n, rule.message);
394
+ const n = Number(rv);
395
+ if (!isNaN(n)) {
396
+ if (isRef) numRefineRules.push({ fn: (v) => v >= n, message: rule.message });
397
+ else numSchema = numSchema.gte(n, rule.message);
398
+ }
360
399
  } else if (rule.type === "max" || rule.type === "lessThanOrEqual") {
361
- const n = Number(rule.value);
362
- if (!isNaN(n)) numSchema = numSchema.lte(n, rule.message);
400
+ const n = Number(rv);
401
+ if (!isNaN(n)) {
402
+ if (isRef) numRefineRules.push({ fn: (v) => v <= n, message: rule.message });
403
+ else numSchema = numSchema.lte(n, rule.message);
404
+ }
363
405
  } else if (rule.type === "greaterThan") {
364
- const n = Number(rule.value);
365
- if (!isNaN(n)) numSchema = numSchema.gt(n, rule.message);
406
+ const n = Number(rv);
407
+ if (!isNaN(n)) {
408
+ if (isRef) numRefineRules.push({ fn: (v) => v > n, message: rule.message });
409
+ else numSchema = numSchema.gt(n, rule.message);
410
+ }
366
411
  } else if (rule.type === "lessThan") {
367
- const n = Number(rule.value);
368
- if (!isNaN(n)) numSchema = numSchema.lt(n, rule.message);
412
+ const n = Number(rv);
413
+ if (!isNaN(n)) {
414
+ if (isRef) numRefineRules.push({ fn: (v) => v < n, message: rule.message });
415
+ else numSchema = numSchema.lt(n, rule.message);
416
+ }
369
417
  } else if (rule.type === "equals") {
370
- const n = Number(rule.value);
371
- if (!isNaN(n)) numSchema = numSchema.refine((v) => v === n, rule.message);
418
+ const n = Number(rv);
419
+ if (!isNaN(n)) numRefineRules.push({ fn: (v) => v === n, message: rule.message });
372
420
  } else if (rule.type === "notEquals") {
373
- const n = Number(rule.value);
374
- if (!isNaN(n)) numSchema = numSchema.refine((v) => v !== n, rule.message);
421
+ const n = Number(rv);
422
+ if (!isNaN(n)) numRefineRules.push({ fn: (v) => v !== n, message: rule.message });
375
423
  }
376
424
  }
377
- return isRequired ? numSchema : numSchema.optional();
425
+ let numFinal = isRequired ? numSchema : numSchema.optional();
426
+ for (const { fn, message } of numRefineRules) {
427
+ numFinal = numFinal.refine((v) => v == null || fn(v), message);
428
+ }
429
+ return numFinal;
378
430
  }
379
431
  let strSchema = zod.z.string();
380
432
  const refineRules = [];
@@ -404,54 +456,70 @@ function buildFieldSchema(field, externalEnums) {
404
456
  strSchema = strSchema.regex(new RegExp(String(rule.value)), rule.message);
405
457
  }
406
458
  break;
407
- case "equals":
408
- if (rule.value !== void 0) {
409
- const eq = String(rule.value);
459
+ case "equals": {
460
+ const rv = resolveRuleValue(rule, data);
461
+ if (rv !== void 0) {
462
+ const eq = String(rv);
410
463
  refineRules.push({ fn: (v) => String(v) === eq, message: rule.message });
411
464
  }
412
465
  break;
413
- case "notEquals":
414
- if (rule.value !== void 0) {
415
- const neq = String(rule.value);
466
+ }
467
+ case "notEquals": {
468
+ const rv = resolveRuleValue(rule, data);
469
+ if (rv !== void 0) {
470
+ const neq = String(rv);
416
471
  refineRules.push({ fn: (v) => String(v) !== neq, message: rule.message });
417
472
  }
418
473
  break;
419
- case "greaterThan":
420
- if (rule.value !== void 0) {
421
- const gt = Number(rule.value);
474
+ }
475
+ case "greaterThan": {
476
+ const rv = resolveRuleValue(rule, data);
477
+ if (rv !== void 0) {
478
+ const gt = Number(rv);
422
479
  refineRules.push({ fn: (v) => Number(v) > gt, message: rule.message });
423
480
  }
424
481
  break;
425
- case "greaterThanOrEqual":
426
- if (rule.value !== void 0) {
427
- const gte = Number(rule.value);
482
+ }
483
+ case "greaterThanOrEqual": {
484
+ const rv = resolveRuleValue(rule, data);
485
+ if (rv !== void 0) {
486
+ const gte = Number(rv);
428
487
  refineRules.push({ fn: (v) => Number(v) >= gte, message: rule.message });
429
488
  }
430
489
  break;
431
- case "lessThan":
432
- if (rule.value !== void 0) {
433
- const lt = Number(rule.value);
490
+ }
491
+ case "lessThan": {
492
+ const rv = resolveRuleValue(rule, data);
493
+ if (rv !== void 0) {
494
+ const lt = Number(rv);
434
495
  refineRules.push({ fn: (v) => Number(v) < lt, message: rule.message });
435
496
  }
436
497
  break;
437
- case "lessThanOrEqual":
438
- if (rule.value !== void 0) {
439
- const lte = Number(rule.value);
498
+ }
499
+ case "lessThanOrEqual": {
500
+ const rv = resolveRuleValue(rule, data);
501
+ if (rv !== void 0) {
502
+ const lte = Number(rv);
440
503
  refineRules.push({ fn: (v) => Number(v) <= lte, message: rule.message });
441
504
  }
442
505
  break;
443
- case "contains":
444
- if (rule.value !== void 0) {
445
- const sub = String(rule.value);
506
+ }
507
+ case "contains": {
508
+ const rv = resolveRuleValue(rule, data);
509
+ if (rv !== void 0) {
510
+ const sub = String(rv);
446
511
  refineRules.push({ fn: (v) => String(v).includes(sub), message: rule.message });
447
512
  }
448
513
  break;
449
- case "notContains":
450
- if (rule.value !== void 0) {
451
- const nsub = String(rule.value);
514
+ }
515
+ case "notContains": {
516
+ const rv = resolveRuleValue(rule, data);
517
+ if (rv !== void 0) {
518
+ const nsub = String(rv);
452
519
  refineRules.push({ fn: (v) => !String(v).includes(nsub), message: rule.message });
453
520
  }
454
521
  break;
522
+ }
455
523
  case "matches":
456
524
  if (rule.value !== void 0 && rule.value !== null) {
457
525
  const rx = new RegExp(String(rule.value));
@@ -489,11 +557,11 @@ function buildFieldSchema(field, externalEnums) {
489
557
  }
490
558
  return finalSchema;
491
559
  }
492
- function buildZodSchema(fields, externalEnums) {
560
+ function buildZodSchema(fields, externalEnums, data) {
493
561
  const shape = {};
494
562
  for (const resolvedField of fields) {
495
563
  if (!resolvedField.visible) continue;
496
- shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition, externalEnums);
564
+ shape[resolvedField.definition.id] = buildFieldSchema(resolvedField.definition, externalEnums, data);
497
565
  }
498
566
  return zod.z.object(shape);
499
567
  }