@timeax/digital-service-engine 0.3.4 → 0.3.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/core/index.cjs +680 -159
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +48 -6
- package/dist/core/index.d.ts +48 -6
- package/dist/core/index.js +671 -158
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +2123 -999
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +115 -58
- package/dist/react/index.d.ts +115 -58
- package/dist/react/index.js +2123 -999
- package/dist/react/index.js.map +1 -1
- package/dist/schema/index.d.cts +19 -2
- package/dist/schema/index.d.ts +19 -2
- package/dist/workspace/index.cjs +1291 -372
- package/dist/workspace/index.cjs.map +1 -1
- package/dist/workspace/index.d.cts +176 -5
- package/dist/workspace/index.d.ts +176 -5
- package/dist/workspace/index.js +1291 -372
- package/dist/workspace/index.js.map +1 -1
- package/package.json +1 -1
- package/schema/editor-snapshot.schema.json +38 -0
- package/schema/service-props.schema.json +38 -0
package/dist/core/index.cjs
CHANGED
|
@@ -26,17 +26,25 @@ __export(core_exports, {
|
|
|
26
26
|
createBuilder: () => createBuilder,
|
|
27
27
|
createFallbackEditor: () => createFallbackEditor,
|
|
28
28
|
createNodeIndex: () => createNodeIndex,
|
|
29
|
+
fieldOptionIdSet: () => fieldOptionIdSet,
|
|
30
|
+
fieldOptionIds: () => fieldOptionIds,
|
|
31
|
+
filterFieldOptionsById: () => filterFieldOptionsById,
|
|
29
32
|
filterServicesForVisibleGroup: () => filterServicesForVisibleGroup,
|
|
33
|
+
findFieldOption: () => findFieldOption,
|
|
34
|
+
findOptionOwnerField: () => findOptionOwnerField,
|
|
30
35
|
getAssignedServiceIds: () => getAssignedServiceIds,
|
|
31
36
|
getEligibleFallbacks: () => getEligibleFallbacks,
|
|
32
37
|
getFallbackRegistrationInfo: () => getFallbackRegistrationInfo,
|
|
33
38
|
isRefExcludedBySelectedKeys: () => isRefExcludedBySelectedKeys,
|
|
34
39
|
normalise: () => normalise,
|
|
35
40
|
normalizeFieldValidation: () => normalizeFieldValidation,
|
|
41
|
+
optionOwnerMap: () => optionOwnerMap,
|
|
36
42
|
resolveServiceFallback: () => resolveServiceFallback,
|
|
37
43
|
validate: () => validate,
|
|
38
44
|
validateAsync: () => validateAsync,
|
|
39
|
-
validateRateCoherenceDeep: () => validateRateCoherenceDeep
|
|
45
|
+
validateRateCoherenceDeep: () => validateRateCoherenceDeep,
|
|
46
|
+
walkFieldOptions: () => walkFieldOptions,
|
|
47
|
+
walkOptions: () => walkOptions
|
|
40
48
|
});
|
|
41
49
|
module.exports = __toCommonJS(core_exports);
|
|
42
50
|
|
|
@@ -55,6 +63,9 @@ function normalise(input, opts = {}) {
|
|
|
55
63
|
const excludes_for_buttons = toStringArrayMap(
|
|
56
64
|
obj.excludes_for_buttons
|
|
57
65
|
);
|
|
66
|
+
const option_effects_for_buttons = toOptionEffectMap(
|
|
67
|
+
obj.option_effects_for_buttons
|
|
68
|
+
);
|
|
58
69
|
const orderKinds = toStringMap(obj.orderKinds);
|
|
59
70
|
const notices = toNoticeArray(obj.notices);
|
|
60
71
|
let filters = rawFilters.map((t) => coerceTag(t, constraints));
|
|
@@ -70,6 +81,9 @@ function normalise(input, opts = {}) {
|
|
|
70
81
|
...isNonEmpty(orderKinds) && { orderKinds },
|
|
71
82
|
...isNonEmpty(includes_for_buttons) && { includes_for_buttons },
|
|
72
83
|
...isNonEmpty(excludes_for_buttons) && { excludes_for_buttons },
|
|
84
|
+
...isNonEmpty(option_effects_for_buttons) && {
|
|
85
|
+
option_effects_for_buttons
|
|
86
|
+
},
|
|
73
87
|
...fallbacks && (isNonEmpty(fallbacks.nodes) || isNonEmpty(fallbacks.global)) && {
|
|
74
88
|
fallbacks
|
|
75
89
|
},
|
|
@@ -224,6 +238,7 @@ function coerceOption(src, inheritRole) {
|
|
|
224
238
|
const value = typeof src.value === "string" || typeof src.value === "number" ? src.value : void 0;
|
|
225
239
|
const pricing_role = src.pricing_role === "utility" || src.pricing_role === "base" ? src.pricing_role : inheritRole;
|
|
226
240
|
const meta = src.meta && typeof src.meta === "object" ? src.meta : void 0;
|
|
241
|
+
const children = Array.isArray(src.children) ? src.children.map((child) => coerceOption(child, pricing_role)) : void 0;
|
|
227
242
|
const option = {
|
|
228
243
|
id: "",
|
|
229
244
|
label: "",
|
|
@@ -232,7 +247,8 @@ function coerceOption(src, inheritRole) {
|
|
|
232
247
|
...value !== void 0 && { value },
|
|
233
248
|
...service_id !== void 0 && { service_id },
|
|
234
249
|
pricing_role,
|
|
235
|
-
...meta && { meta }
|
|
250
|
+
...meta && { meta },
|
|
251
|
+
...children && children.length && { children }
|
|
236
252
|
};
|
|
237
253
|
return option;
|
|
238
254
|
}
|
|
@@ -297,6 +313,35 @@ function toStringArrayMap(src) {
|
|
|
297
313
|
}
|
|
298
314
|
return Object.keys(out).length ? out : void 0;
|
|
299
315
|
}
|
|
316
|
+
function toOptionEffectMap(src) {
|
|
317
|
+
var _a, _b;
|
|
318
|
+
if (!src || typeof src !== "object") return void 0;
|
|
319
|
+
const out = {};
|
|
320
|
+
for (const [triggerId, rawTargets] of Object.entries(src)) {
|
|
321
|
+
if (!triggerId || !rawTargets || typeof rawTargets !== "object") {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const targets = {};
|
|
325
|
+
for (const [fieldId, rawEffect] of Object.entries(rawTargets)) {
|
|
326
|
+
if (!fieldId || !rawEffect || typeof rawEffect !== "object") {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const effect = rawEffect;
|
|
330
|
+
const include = toStringArray(effect.include);
|
|
331
|
+
const exclude = toStringArray(effect.exclude);
|
|
332
|
+
const next = {
|
|
333
|
+
...effect.forceVisible === true ? { forceVisible: true } : {},
|
|
334
|
+
...include.length ? { include: dedupe(include) } : {},
|
|
335
|
+
...exclude.length ? { exclude: dedupe(exclude) } : {}
|
|
336
|
+
};
|
|
337
|
+
if (next.forceVisible === true || ((_a = next.include) == null ? void 0 : _a.length) || ((_b = next.exclude) == null ? void 0 : _b.length)) {
|
|
338
|
+
targets[fieldId] = next;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (Object.keys(targets).length) out[triggerId] = targets;
|
|
342
|
+
}
|
|
343
|
+
return Object.keys(out).length ? out : void 0;
|
|
344
|
+
}
|
|
300
345
|
function toStringArray(v) {
|
|
301
346
|
if (!Array.isArray(v)) return [];
|
|
302
347
|
return v.map((x) => String(x)).filter((s) => !!s && s.trim().length > 0);
|
|
@@ -371,6 +416,76 @@ function normalizeFieldValidation(input) {
|
|
|
371
416
|
return one ? [one] : void 0;
|
|
372
417
|
}
|
|
373
418
|
|
|
419
|
+
// src/core/options.ts
|
|
420
|
+
function walkFieldOptions(field) {
|
|
421
|
+
const out = [];
|
|
422
|
+
const visit = (options, depth, parentId) => {
|
|
423
|
+
for (const option of options != null ? options : []) {
|
|
424
|
+
out.push({
|
|
425
|
+
field,
|
|
426
|
+
fieldId: field.id,
|
|
427
|
+
option,
|
|
428
|
+
optionId: option.id,
|
|
429
|
+
depth,
|
|
430
|
+
parentId
|
|
431
|
+
});
|
|
432
|
+
visit(option.children, depth + 1, option.id);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
visit(field.options, 0);
|
|
436
|
+
return out;
|
|
437
|
+
}
|
|
438
|
+
function walkOptions(props) {
|
|
439
|
+
var _a;
|
|
440
|
+
return ((_a = props.fields) != null ? _a : []).flatMap((field) => walkFieldOptions(field));
|
|
441
|
+
}
|
|
442
|
+
function fieldOptionIds(field) {
|
|
443
|
+
return walkFieldOptions(field).map((visit) => visit.optionId);
|
|
444
|
+
}
|
|
445
|
+
function fieldOptionIdSet(field) {
|
|
446
|
+
return new Set(fieldOptionIds(field));
|
|
447
|
+
}
|
|
448
|
+
function findFieldOption(field, optionId) {
|
|
449
|
+
var _a;
|
|
450
|
+
if (!field) return void 0;
|
|
451
|
+
return (_a = walkFieldOptions(field).find((visit) => visit.optionId === optionId)) == null ? void 0 : _a.option;
|
|
452
|
+
}
|
|
453
|
+
function findOptionOwnerField(fields, optionId) {
|
|
454
|
+
for (const field of fields) {
|
|
455
|
+
if (findFieldOption(field, optionId)) return field;
|
|
456
|
+
}
|
|
457
|
+
return void 0;
|
|
458
|
+
}
|
|
459
|
+
function optionOwnerMap(fields) {
|
|
460
|
+
const out = /* @__PURE__ */ new Map();
|
|
461
|
+
for (const field of fields) {
|
|
462
|
+
for (const visit of walkFieldOptions(field)) {
|
|
463
|
+
if (!out.has(visit.optionId)) {
|
|
464
|
+
out.set(visit.optionId, {
|
|
465
|
+
fieldId: field.id,
|
|
466
|
+
option: visit.option
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return out;
|
|
472
|
+
}
|
|
473
|
+
function filterFieldOptionsById(options, allowed) {
|
|
474
|
+
if (!Array.isArray(options)) return void 0;
|
|
475
|
+
const out = [];
|
|
476
|
+
for (const option of options) {
|
|
477
|
+
const children = filterFieldOptionsById(option.children, allowed);
|
|
478
|
+
if (!allowed.has(option.id) && (!children || children.length === 0)) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
out.push({
|
|
482
|
+
...option,
|
|
483
|
+
...children ? { children } : {}
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
return out;
|
|
487
|
+
}
|
|
488
|
+
|
|
374
489
|
// src/core/validate/shared.ts
|
|
375
490
|
function isFiniteNumber(v) {
|
|
376
491
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -379,8 +494,9 @@ function isServiceIdRef(v) {
|
|
|
379
494
|
return typeof v === "string" && v.trim().length > 0 || typeof v === "number" && Number.isFinite(v);
|
|
380
495
|
}
|
|
381
496
|
function hasAnyServiceOption(f) {
|
|
382
|
-
|
|
383
|
-
|
|
497
|
+
return walkFieldOptions(f).some(
|
|
498
|
+
(visit) => isServiceIdRef(visit.option.service_id)
|
|
499
|
+
);
|
|
384
500
|
}
|
|
385
501
|
function getByPath(obj, path) {
|
|
386
502
|
if (!path) return void 0;
|
|
@@ -469,14 +585,14 @@ function withAffected(details, ids) {
|
|
|
469
585
|
|
|
470
586
|
// src/core/node-map.ts
|
|
471
587
|
function buildNodeMap(props) {
|
|
472
|
-
var _a, _b
|
|
588
|
+
var _a, _b;
|
|
473
589
|
const map = /* @__PURE__ */ new Map();
|
|
474
590
|
for (const t of (_a = props.filters) != null ? _a : []) {
|
|
475
591
|
if (!map.has(t.id)) map.set(t.id, { kind: "tag", id: t.id, node: t });
|
|
476
592
|
}
|
|
477
593
|
for (const f of (_b = props.fields) != null ? _b : []) {
|
|
478
594
|
if (!map.has(f.id)) map.set(f.id, { kind: "field", id: f.id, node: f });
|
|
479
|
-
for (const o of (
|
|
595
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
480
596
|
if (!map.has(o.id))
|
|
481
597
|
map.set(o.id, {
|
|
482
598
|
kind: "option",
|
|
@@ -489,12 +605,6 @@ function buildNodeMap(props) {
|
|
|
489
605
|
return map;
|
|
490
606
|
}
|
|
491
607
|
function resolveTrigger(trigger, nodeMap) {
|
|
492
|
-
const idx = trigger.indexOf("::");
|
|
493
|
-
if (idx !== -1) {
|
|
494
|
-
const fieldId = trigger.slice(0, idx);
|
|
495
|
-
const optionId = trigger.slice(idx + 2);
|
|
496
|
-
return { kind: "composite", triggerKey: trigger, fieldId, optionId };
|
|
497
|
-
}
|
|
498
608
|
const direct = nodeMap.get(trigger);
|
|
499
609
|
if (!direct) return void 0;
|
|
500
610
|
if (direct.kind === "option") {
|
|
@@ -546,11 +656,6 @@ function visibleFieldIdsUnder(props, tagId, opts = {}) {
|
|
|
546
656
|
const ownerDepthForTriggerKey = (triggerKey) => {
|
|
547
657
|
const t = resolveTrigger(triggerKey, nodeMap);
|
|
548
658
|
if (!t) return void 0;
|
|
549
|
-
if (t.kind === "composite") {
|
|
550
|
-
const f = fieldById.get(t.fieldId);
|
|
551
|
-
if (!f) return void 0;
|
|
552
|
-
return ownerDepthForField(f);
|
|
553
|
-
}
|
|
554
659
|
if (t.kind === "field") {
|
|
555
660
|
const f = fieldById.get(t.id);
|
|
556
661
|
if (!f || f.button !== true) return void 0;
|
|
@@ -633,6 +738,84 @@ function visibleFieldsUnder(props, tagId, opts = {}) {
|
|
|
633
738
|
const fieldById = new Map(((_a = props.fields) != null ? _a : []).map((f) => [f.id, f]));
|
|
634
739
|
return ids.map((id) => fieldById.get(id)).filter(Boolean);
|
|
635
740
|
}
|
|
741
|
+
function resolveVisibility(props, tagId, selectedKeys) {
|
|
742
|
+
var _a, _b, _c, _d;
|
|
743
|
+
const selected = new Set(selectedKeys != null ? selectedKeys : []);
|
|
744
|
+
const baseFieldIds = visibleFieldIdsUnder(props, tagId, { selectedKeys: selected });
|
|
745
|
+
const fieldById = new Map(((_a = props.fields) != null ? _a : []).map((field) => [field.id, field]));
|
|
746
|
+
const visible = new Set(baseFieldIds);
|
|
747
|
+
const forced = /* @__PURE__ */ new Set();
|
|
748
|
+
const optionsByFieldId = {};
|
|
749
|
+
const optionIdsByFieldId = /* @__PURE__ */ new Map();
|
|
750
|
+
const getOptionIds = (field) => {
|
|
751
|
+
let ids = optionIdsByFieldId.get(field.id);
|
|
752
|
+
if (!ids) {
|
|
753
|
+
ids = fieldOptionIds(field);
|
|
754
|
+
optionIdsByFieldId.set(field.id, ids);
|
|
755
|
+
}
|
|
756
|
+
return ids;
|
|
757
|
+
};
|
|
758
|
+
const ensureOptions = (field) => {
|
|
759
|
+
const ids = getOptionIds(field);
|
|
760
|
+
if (!ids.length) return void 0;
|
|
761
|
+
if (!optionsByFieldId[field.id]) optionsByFieldId[field.id] = [...ids];
|
|
762
|
+
return optionsByFieldId[field.id];
|
|
763
|
+
};
|
|
764
|
+
for (const fieldId of baseFieldIds) {
|
|
765
|
+
const field = fieldById.get(fieldId);
|
|
766
|
+
if (field) ensureOptions(field);
|
|
767
|
+
}
|
|
768
|
+
const effects = (_b = props.option_effects_for_buttons) != null ? _b : {};
|
|
769
|
+
for (const triggerId of selected) {
|
|
770
|
+
const targetRules = effects[triggerId];
|
|
771
|
+
if (!targetRules) continue;
|
|
772
|
+
for (const [targetFieldId, rule] of Object.entries(targetRules)) {
|
|
773
|
+
const field = fieldById.get(targetFieldId);
|
|
774
|
+
if (!field) continue;
|
|
775
|
+
const isVisible = visible.has(targetFieldId);
|
|
776
|
+
if (!isVisible && rule.forceVisible !== true) continue;
|
|
777
|
+
if (!isVisible && rule.forceVisible === true) {
|
|
778
|
+
visible.add(targetFieldId);
|
|
779
|
+
forced.add(targetFieldId);
|
|
780
|
+
}
|
|
781
|
+
const orderedOptionIds = getOptionIds(field);
|
|
782
|
+
if (!orderedOptionIds.length) continue;
|
|
783
|
+
const known = new Set(orderedOptionIds);
|
|
784
|
+
let allowed = (_c = optionsByFieldId[targetFieldId]) != null ? _c : [...orderedOptionIds];
|
|
785
|
+
if (Array.isArray(rule.include) && rule.include.length) {
|
|
786
|
+
const include = new Set(
|
|
787
|
+
rule.include.filter((optionId) => known.has(optionId))
|
|
788
|
+
);
|
|
789
|
+
allowed = orderedOptionIds.filter(
|
|
790
|
+
(optionId) => include.has(optionId) && allowed.includes(optionId)
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
if (Array.isArray(rule.exclude) && rule.exclude.length) {
|
|
794
|
+
const exclude = new Set(
|
|
795
|
+
rule.exclude.filter((optionId) => known.has(optionId))
|
|
796
|
+
);
|
|
797
|
+
allowed = allowed.filter((optionId) => !exclude.has(optionId));
|
|
798
|
+
}
|
|
799
|
+
optionsByFieldId[targetFieldId] = allowed;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const visibleFieldIds = baseFieldIds.filter((fieldId) => visible.has(fieldId));
|
|
803
|
+
const seen = new Set(visibleFieldIds);
|
|
804
|
+
for (const field of (_d = props.fields) != null ? _d : []) {
|
|
805
|
+
if (!visible.has(field.id) || seen.has(field.id)) continue;
|
|
806
|
+
seen.add(field.id);
|
|
807
|
+
visibleFieldIds.push(field.id);
|
|
808
|
+
ensureOptions(field);
|
|
809
|
+
}
|
|
810
|
+
for (const fieldId of Object.keys(optionsByFieldId)) {
|
|
811
|
+
if (!visible.has(fieldId)) delete optionsByFieldId[fieldId];
|
|
812
|
+
}
|
|
813
|
+
return {
|
|
814
|
+
fieldIds: visibleFieldIds,
|
|
815
|
+
optionsByFieldId,
|
|
816
|
+
forcedFieldIds: visibleFieldIds.filter((fieldId) => forced.has(fieldId))
|
|
817
|
+
};
|
|
818
|
+
}
|
|
636
819
|
|
|
637
820
|
// src/core/validate/steps/visibility.ts
|
|
638
821
|
function createFieldsVisibleUnder(v) {
|
|
@@ -650,7 +833,6 @@ function resolveRootTags(tags) {
|
|
|
650
833
|
return roots.length ? roots : tags.slice(0, 1);
|
|
651
834
|
}
|
|
652
835
|
function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKeys) {
|
|
653
|
-
var _a;
|
|
654
836
|
const visible = visibleFieldsUnder(v.props, tagId, {
|
|
655
837
|
selectedKeys
|
|
656
838
|
});
|
|
@@ -660,7 +842,7 @@ function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKey
|
|
|
660
842
|
const t = f.id;
|
|
661
843
|
if (effectfulKeys.has(t)) triggers.push(t);
|
|
662
844
|
}
|
|
663
|
-
for (const o of (
|
|
845
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
664
846
|
const t = o.id;
|
|
665
847
|
if (effectfulKeys.has(t)) triggers.push(t);
|
|
666
848
|
}
|
|
@@ -669,7 +851,7 @@ function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKey
|
|
|
669
851
|
return triggers;
|
|
670
852
|
}
|
|
671
853
|
function runVisibilityRulesOnce(v) {
|
|
672
|
-
var _a, _b, _c, _d
|
|
854
|
+
var _a, _b, _c, _d;
|
|
673
855
|
for (const t of v.tags) {
|
|
674
856
|
const visible = v.fieldsVisibleUnder(t.id);
|
|
675
857
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -719,9 +901,9 @@ function runVisibilityRulesOnce(v) {
|
|
|
719
901
|
let hasUtility = false;
|
|
720
902
|
const utilityOptionIds = [];
|
|
721
903
|
for (const f of visible) {
|
|
722
|
-
for (const o of (
|
|
904
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
723
905
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
724
|
-
const role = (
|
|
906
|
+
const role = (_d = (_c = o.pricing_role) != null ? _c : f.pricing_role) != null ? _d : "base";
|
|
725
907
|
if (role === "base") hasBase = true;
|
|
726
908
|
else if (role === "utility") {
|
|
727
909
|
hasUtility = true;
|
|
@@ -762,7 +944,7 @@ function dedupeErrorsInPlace(v, startIndex) {
|
|
|
762
944
|
v.errors.splice(startIndex, v.errors.length - startIndex, ...kept);
|
|
763
945
|
}
|
|
764
946
|
function validateVisibility(v, options = {}) {
|
|
765
|
-
var _a, _b, _c, _d, _e;
|
|
947
|
+
var _a, _b, _c, _d, _e, _f;
|
|
766
948
|
v.simulatedVisibilityContexts = [];
|
|
767
949
|
const simulate = options.simulate === true;
|
|
768
950
|
if (!simulate) {
|
|
@@ -787,10 +969,13 @@ function validateVisibility(v, options = {}) {
|
|
|
787
969
|
for (const key of Object.keys((_d = v.props.excludes_for_buttons) != null ? _d : {})) {
|
|
788
970
|
effectfulKeys.add(key);
|
|
789
971
|
}
|
|
972
|
+
for (const key of Object.keys((_e = v.props.option_effects_for_buttons) != null ? _e : {})) {
|
|
973
|
+
effectfulKeys.add(key);
|
|
974
|
+
}
|
|
790
975
|
}
|
|
791
976
|
const roots = resolveRootTags(v.tags);
|
|
792
977
|
const rootTags = options.simulateAllRoots ? roots : roots.slice(0, 1);
|
|
793
|
-
const originalSelected = new Set((
|
|
978
|
+
const originalSelected = new Set((_f = v.selectedKeys) != null ? _f : []);
|
|
794
979
|
const errorsStart = v.errors.length;
|
|
795
980
|
const visited = /* @__PURE__ */ new Set();
|
|
796
981
|
const seenContexts = /* @__PURE__ */ new Set();
|
|
@@ -931,7 +1116,7 @@ function validateStructure(v) {
|
|
|
931
1116
|
|
|
932
1117
|
// src/core/validate/steps/identity.ts
|
|
933
1118
|
function validateIdentity(v) {
|
|
934
|
-
var _a
|
|
1119
|
+
var _a;
|
|
935
1120
|
const tags = v.tags;
|
|
936
1121
|
const fields = v.fields;
|
|
937
1122
|
{
|
|
@@ -1031,7 +1216,7 @@ function validateIdentity(v) {
|
|
|
1031
1216
|
}
|
|
1032
1217
|
}
|
|
1033
1218
|
for (const f of fields) {
|
|
1034
|
-
for (const o of (
|
|
1219
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
1035
1220
|
if (!o.label || !o.label.trim()) {
|
|
1036
1221
|
v.errors.push({
|
|
1037
1222
|
code: "label_missing",
|
|
@@ -1046,25 +1231,11 @@ function validateIdentity(v) {
|
|
|
1046
1231
|
}
|
|
1047
1232
|
|
|
1048
1233
|
// src/core/validate/steps/option-maps.ts
|
|
1049
|
-
function parseFieldOptionKey(key) {
|
|
1050
|
-
const idx = key.indexOf("::");
|
|
1051
|
-
if (idx === -1) return null;
|
|
1052
|
-
const fieldId = key.slice(0, idx).trim();
|
|
1053
|
-
const optionId = key.slice(idx + 2).trim();
|
|
1054
|
-
if (!fieldId || !optionId) return null;
|
|
1055
|
-
return { fieldId, optionId };
|
|
1056
|
-
}
|
|
1057
|
-
function hasOption(v, fid, oid) {
|
|
1058
|
-
var _a;
|
|
1059
|
-
const f = v.fieldById.get(fid);
|
|
1060
|
-
if (!f) return false;
|
|
1061
|
-
return !!((_a = f.options) != null ? _a : []).find((o) => o.id === oid);
|
|
1062
|
-
}
|
|
1063
1234
|
function validateOptionMaps(v) {
|
|
1064
|
-
var _a, _b;
|
|
1235
|
+
var _a, _b, _c;
|
|
1065
1236
|
const incMap = (_a = v.props.includes_for_buttons) != null ? _a : {};
|
|
1066
1237
|
const excMap = (_b = v.props.excludes_for_buttons) != null ? _b : {};
|
|
1067
|
-
const badKeyMessage = (key) => `Invalid trigger-map key "${key}". Expected a known
|
|
1238
|
+
const badKeyMessage = (key) => `Invalid trigger-map key "${key}". Expected a known option id or button-field id.`;
|
|
1068
1239
|
const validateTriggerKey = (key) => {
|
|
1069
1240
|
const ref = v.nodeMap.get(key);
|
|
1070
1241
|
if (ref) {
|
|
@@ -1083,19 +1254,7 @@ function validateOptionMaps(v) {
|
|
|
1083
1254
|
}
|
|
1084
1255
|
return { ok: false, nodeId: ref.id, affected: [ref.id] };
|
|
1085
1256
|
}
|
|
1086
|
-
|
|
1087
|
-
if (!p) return { ok: false };
|
|
1088
|
-
if (!hasOption(v, p.fieldId, p.optionId))
|
|
1089
|
-
return {
|
|
1090
|
-
ok: false,
|
|
1091
|
-
nodeId: p.fieldId,
|
|
1092
|
-
affected: [p.fieldId, p.optionId]
|
|
1093
|
-
};
|
|
1094
|
-
return {
|
|
1095
|
-
ok: true,
|
|
1096
|
-
nodeId: p.fieldId,
|
|
1097
|
-
affected: [p.fieldId, p.optionId]
|
|
1098
|
-
};
|
|
1257
|
+
return { ok: false };
|
|
1099
1258
|
};
|
|
1100
1259
|
for (const k of Object.keys(incMap)) {
|
|
1101
1260
|
const r = validateTriggerKey(k);
|
|
@@ -1121,6 +1280,57 @@ function validateOptionMaps(v) {
|
|
|
1121
1280
|
});
|
|
1122
1281
|
}
|
|
1123
1282
|
}
|
|
1283
|
+
const effectMap = (_c = v.props.option_effects_for_buttons) != null ? _c : {};
|
|
1284
|
+
for (const [triggerKey, targets] of Object.entries(effectMap)) {
|
|
1285
|
+
const trigger = validateTriggerKey(triggerKey);
|
|
1286
|
+
if (!trigger.ok) {
|
|
1287
|
+
v.errors.push({
|
|
1288
|
+
code: "bad_option_effect_key",
|
|
1289
|
+
severity: "error",
|
|
1290
|
+
message: badKeyMessage(triggerKey),
|
|
1291
|
+
nodeId: trigger.nodeId,
|
|
1292
|
+
details: withAffected({ key: triggerKey }, trigger.affected)
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
for (const [targetFieldId, effect] of Object.entries(targets != null ? targets : {})) {
|
|
1296
|
+
const field = v.fieldById.get(targetFieldId);
|
|
1297
|
+
if (!field) {
|
|
1298
|
+
v.errors.push({
|
|
1299
|
+
code: "bad_option_effect_target",
|
|
1300
|
+
severity: "error",
|
|
1301
|
+
message: `Option effect trigger "${triggerKey}" targets unknown field "${targetFieldId}".`,
|
|
1302
|
+
details: withAffected(
|
|
1303
|
+
{ key: triggerKey, targetFieldId },
|
|
1304
|
+
trigger.affected
|
|
1305
|
+
)
|
|
1306
|
+
});
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
1310
|
+
const checkTargetOptions = (kind, optionIds) => {
|
|
1311
|
+
for (const optionId of optionIds != null ? optionIds : []) {
|
|
1312
|
+
if (validOptionIds.has(optionId)) continue;
|
|
1313
|
+
v.errors.push({
|
|
1314
|
+
code: "bad_option_effect_option",
|
|
1315
|
+
severity: "error",
|
|
1316
|
+
message: `Option effect trigger "${triggerKey}" references unknown ${kind} option "${optionId}" for field "${targetFieldId}".`,
|
|
1317
|
+
nodeId: targetFieldId,
|
|
1318
|
+
details: withAffected(
|
|
1319
|
+
{
|
|
1320
|
+
key: triggerKey,
|
|
1321
|
+
targetFieldId,
|
|
1322
|
+
optionId,
|
|
1323
|
+
kind
|
|
1324
|
+
},
|
|
1325
|
+
[targetFieldId, optionId]
|
|
1326
|
+
)
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
checkTargetOptions("include", effect == null ? void 0 : effect.include);
|
|
1331
|
+
checkTargetOptions("exclude", effect == null ? void 0 : effect.exclude);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1124
1334
|
for (const k of Object.keys(incMap)) {
|
|
1125
1335
|
if (!(k in excMap)) continue;
|
|
1126
1336
|
const r = validateTriggerKey(k);
|
|
@@ -1134,27 +1344,231 @@ function validateOptionMaps(v) {
|
|
|
1134
1344
|
}
|
|
1135
1345
|
}
|
|
1136
1346
|
|
|
1137
|
-
// src/
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
const
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1347
|
+
// src/core/validate/steps/visibility-cycles.ts
|
|
1348
|
+
var MAX_VISIBILITY_CYCLE_DEPTH = 20;
|
|
1349
|
+
function validateVisibilityCycles(v) {
|
|
1350
|
+
const triggerById = buildTriggerIndex(v.fields);
|
|
1351
|
+
if (!triggerById.size) return;
|
|
1352
|
+
const fieldTriggers = buildFieldTriggerIndex(v.fields);
|
|
1353
|
+
const revealTargetsByTrigger = buildRevealIndex(v, triggerById);
|
|
1354
|
+
const reported = /* @__PURE__ */ new Set();
|
|
1355
|
+
for (const rootTriggerId of Array.from(triggerById.keys()).sort()) {
|
|
1356
|
+
const required = makeRequiredState(triggerById, [rootTriggerId]);
|
|
1357
|
+
walkFromTrigger({
|
|
1358
|
+
v,
|
|
1359
|
+
triggerById,
|
|
1360
|
+
fieldTriggers,
|
|
1361
|
+
revealTargetsByTrigger,
|
|
1362
|
+
rootTriggerId,
|
|
1363
|
+
currentTriggerId: rootTriggerId,
|
|
1364
|
+
required,
|
|
1365
|
+
path: [rootTriggerId],
|
|
1366
|
+
visited: /* @__PURE__ */ new Set(),
|
|
1367
|
+
reported,
|
|
1368
|
+
depth: 0
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
function buildTriggerIndex(fields) {
|
|
1373
|
+
const out = /* @__PURE__ */ new Map();
|
|
1374
|
+
const owners = optionOwnerMap(fields);
|
|
1375
|
+
for (const field of fields) {
|
|
1376
|
+
if (field.button === true) {
|
|
1377
|
+
out.set(field.id, {
|
|
1378
|
+
kind: "field",
|
|
1379
|
+
id: field.id,
|
|
1380
|
+
ownerFieldId: field.id
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
for (const [optionId, owner] of owners) {
|
|
1385
|
+
out.set(optionId, {
|
|
1386
|
+
kind: "option",
|
|
1387
|
+
id: optionId,
|
|
1388
|
+
ownerFieldId: owner.fieldId
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
return out;
|
|
1392
|
+
}
|
|
1393
|
+
function buildFieldTriggerIndex(fields) {
|
|
1394
|
+
const out = /* @__PURE__ */ new Map();
|
|
1395
|
+
for (const field of fields) {
|
|
1396
|
+
const triggers = [];
|
|
1397
|
+
if (field.button === true) triggers.push(field.id);
|
|
1398
|
+
for (const visit of walkFieldOptions(field)) {
|
|
1399
|
+
triggers.push(visit.optionId);
|
|
1400
|
+
}
|
|
1401
|
+
out.set(field.id, triggers);
|
|
1402
|
+
}
|
|
1403
|
+
return out;
|
|
1404
|
+
}
|
|
1405
|
+
function buildRevealIndex(v, triggerById) {
|
|
1406
|
+
var _a, _b;
|
|
1407
|
+
const out = /* @__PURE__ */ new Map();
|
|
1408
|
+
const addReveal = (triggerId, targetFieldId) => {
|
|
1409
|
+
var _a2;
|
|
1410
|
+
if (!triggerById.has(triggerId)) return;
|
|
1411
|
+
if (!v.fieldById.has(targetFieldId)) return;
|
|
1412
|
+
const set = (_a2 = out.get(triggerId)) != null ? _a2 : /* @__PURE__ */ new Set();
|
|
1413
|
+
set.add(targetFieldId);
|
|
1414
|
+
out.set(triggerId, set);
|
|
1415
|
+
};
|
|
1416
|
+
for (const [triggerId, targetIds] of Object.entries(
|
|
1417
|
+
(_a = v.props.includes_for_buttons) != null ? _a : {}
|
|
1418
|
+
)) {
|
|
1419
|
+
for (const targetId of targetIds != null ? targetIds : []) addReveal(triggerId, targetId);
|
|
1420
|
+
}
|
|
1421
|
+
for (const [triggerId, targets] of Object.entries(
|
|
1422
|
+
(_b = v.props.option_effects_for_buttons) != null ? _b : {}
|
|
1423
|
+
)) {
|
|
1424
|
+
for (const [targetFieldId, effect] of Object.entries(targets != null ? targets : {})) {
|
|
1425
|
+
if ((effect == null ? void 0 : effect.forceVisible) === true)
|
|
1426
|
+
addReveal(triggerId, targetFieldId);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return new Map(
|
|
1430
|
+
Array.from(out.entries()).map(([triggerId, fieldIds]) => [
|
|
1431
|
+
triggerId,
|
|
1432
|
+
Array.from(fieldIds).sort()
|
|
1433
|
+
])
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
function walkFromTrigger(args) {
|
|
1437
|
+
var _a, _b, _c;
|
|
1438
|
+
if (args.depth >= MAX_VISIBILITY_CYCLE_DEPTH) return;
|
|
1439
|
+
const visitedKey = `${args.rootTriggerId}::${args.currentTriggerId}::${args.path.join(">")}`;
|
|
1440
|
+
if (args.visited.has(visitedKey)) return;
|
|
1441
|
+
args.visited.add(visitedKey);
|
|
1442
|
+
const revealedFieldIds = (_a = args.revealTargetsByTrigger.get(args.currentTriggerId)) != null ? _a : [];
|
|
1443
|
+
for (const revealedFieldId of revealedFieldIds) {
|
|
1444
|
+
const reachableTriggers = (_c = (_b = args.fieldTriggers.get(revealedFieldId)) == null ? void 0 : _b.slice().sort()) != null ? _c : [];
|
|
1445
|
+
for (const reachableTriggerId of reachableTriggers) {
|
|
1446
|
+
const invalidation = invalidatesRequiredPath(
|
|
1447
|
+
args.v,
|
|
1448
|
+
args.triggerById,
|
|
1449
|
+
reachableTriggerId,
|
|
1450
|
+
args.required
|
|
1451
|
+
);
|
|
1452
|
+
if (invalidation) {
|
|
1453
|
+
emitCycleError({
|
|
1454
|
+
v: args.v,
|
|
1455
|
+
rootTriggerId: args.rootTriggerId,
|
|
1456
|
+
revealedFieldId,
|
|
1457
|
+
conflictingTriggerId: reachableTriggerId,
|
|
1458
|
+
invalidatedId: invalidation.invalidatedId,
|
|
1459
|
+
path: [...args.path, reachableTriggerId],
|
|
1460
|
+
reported: args.reported
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
if (args.path.includes(reachableTriggerId)) continue;
|
|
1464
|
+
walkFromTrigger({
|
|
1465
|
+
...args,
|
|
1466
|
+
currentTriggerId: reachableTriggerId,
|
|
1467
|
+
required: addRequiredTrigger(
|
|
1468
|
+
args.triggerById,
|
|
1469
|
+
args.required,
|
|
1470
|
+
reachableTriggerId
|
|
1471
|
+
),
|
|
1472
|
+
path: [...args.path, reachableTriggerId],
|
|
1473
|
+
depth: args.depth + 1
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
function makeRequiredState(triggerById, triggerIds) {
|
|
1479
|
+
let required = {
|
|
1480
|
+
triggers: /* @__PURE__ */ new Set(),
|
|
1481
|
+
ownerFields: /* @__PURE__ */ new Set()
|
|
1482
|
+
};
|
|
1483
|
+
for (const triggerId of triggerIds) {
|
|
1484
|
+
required = addRequiredTrigger(triggerById, required, triggerId);
|
|
1485
|
+
}
|
|
1486
|
+
return required;
|
|
1487
|
+
}
|
|
1488
|
+
function addRequiredTrigger(triggerById, current, triggerId) {
|
|
1489
|
+
const next = {
|
|
1490
|
+
triggers: new Set(current.triggers),
|
|
1491
|
+
ownerFields: new Set(current.ownerFields)
|
|
1492
|
+
};
|
|
1493
|
+
const trigger = triggerById.get(triggerId);
|
|
1494
|
+
if (!trigger) return next;
|
|
1495
|
+
next.triggers.add(triggerId);
|
|
1496
|
+
next.ownerFields.add(trigger.ownerFieldId);
|
|
1497
|
+
return next;
|
|
1498
|
+
}
|
|
1499
|
+
function invalidatesRequiredPath(v, triggerById, conflictingTriggerId, required) {
|
|
1500
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1501
|
+
for (const targetId of (_b = (_a = v.props.excludes_for_buttons) == null ? void 0 : _a[conflictingTriggerId]) != null ? _b : []) {
|
|
1502
|
+
if (required.ownerFields.has(targetId)) {
|
|
1503
|
+
return { invalidatedId: targetId };
|
|
1504
|
+
}
|
|
1505
|
+
const targetTrigger = triggerById.get(targetId);
|
|
1506
|
+
if ((targetTrigger == null ? void 0 : targetTrigger.kind) === "option" && required.triggers.has(targetId)) {
|
|
1507
|
+
return { invalidatedId: targetId };
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const effects = (_d = (_c = v.props.option_effects_for_buttons) == null ? void 0 : _c[conflictingTriggerId]) != null ? _d : {};
|
|
1511
|
+
for (const [targetFieldId, effect] of Object.entries(effects)) {
|
|
1512
|
+
if (!v.fieldById.has(targetFieldId)) continue;
|
|
1513
|
+
if ((_e = effect == null ? void 0 : effect.exclude) == null ? void 0 : _e.length) {
|
|
1514
|
+
const excluded = new Set(effect.exclude);
|
|
1515
|
+
for (const requiredTriggerId of required.triggers) {
|
|
1516
|
+
const requiredTrigger = triggerById.get(requiredTriggerId);
|
|
1517
|
+
if ((requiredTrigger == null ? void 0 : requiredTrigger.kind) !== "option") continue;
|
|
1518
|
+
if (requiredTrigger.ownerFieldId !== targetFieldId) continue;
|
|
1519
|
+
if (excluded.has(requiredTriggerId)) {
|
|
1520
|
+
return { invalidatedId: requiredTriggerId };
|
|
1521
|
+
}
|
|
1148
1522
|
}
|
|
1149
1523
|
}
|
|
1150
|
-
if (
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1524
|
+
if ((_f = effect == null ? void 0 : effect.include) == null ? void 0 : _f.length) {
|
|
1525
|
+
const included = new Set(effect.include);
|
|
1526
|
+
for (const requiredTriggerId of required.triggers) {
|
|
1527
|
+
const requiredTrigger = triggerById.get(requiredTriggerId);
|
|
1528
|
+
if ((requiredTrigger == null ? void 0 : requiredTrigger.kind) !== "option") continue;
|
|
1529
|
+
if (requiredTrigger.ownerFieldId !== targetFieldId) continue;
|
|
1530
|
+
if (!included.has(requiredTriggerId)) {
|
|
1531
|
+
return { invalidatedId: requiredTriggerId };
|
|
1532
|
+
}
|
|
1154
1533
|
}
|
|
1155
1534
|
}
|
|
1156
|
-
return void 0;
|
|
1157
1535
|
}
|
|
1536
|
+
return void 0;
|
|
1537
|
+
}
|
|
1538
|
+
function emitCycleError(args) {
|
|
1539
|
+
const key = [
|
|
1540
|
+
args.rootTriggerId,
|
|
1541
|
+
args.conflictingTriggerId,
|
|
1542
|
+
args.invalidatedId,
|
|
1543
|
+
args.path.join(">")
|
|
1544
|
+
].join("::");
|
|
1545
|
+
if (args.reported.has(key)) return;
|
|
1546
|
+
args.reported.add(key);
|
|
1547
|
+
args.v.errors.push({
|
|
1548
|
+
code: "visibility_dependency_cycle",
|
|
1549
|
+
severity: "error",
|
|
1550
|
+
message: `Visibility dependency cycle: trigger "${args.rootTriggerId}" reveals "${args.revealedFieldId}", but reachable trigger "${args.conflictingTriggerId}" can hide or remove "${args.invalidatedId}".`,
|
|
1551
|
+
nodeId: args.conflictingTriggerId,
|
|
1552
|
+
details: withAffected(
|
|
1553
|
+
{
|
|
1554
|
+
rootTriggerId: args.rootTriggerId,
|
|
1555
|
+
conflictingTriggerId: args.conflictingTriggerId,
|
|
1556
|
+
invalidatedId: args.invalidatedId,
|
|
1557
|
+
path: args.path
|
|
1558
|
+
},
|
|
1559
|
+
[
|
|
1560
|
+
args.rootTriggerId,
|
|
1561
|
+
args.revealedFieldId,
|
|
1562
|
+
args.conflictingTriggerId,
|
|
1563
|
+
args.invalidatedId
|
|
1564
|
+
]
|
|
1565
|
+
)
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
// src/utils/order-kind.ts
|
|
1570
|
+
function normalizeSelectedTriggerKey(key, nodeMap) {
|
|
1571
|
+
if (!key) return void 0;
|
|
1158
1572
|
const ref = nodeMap.get(key);
|
|
1159
1573
|
if (!ref) return void 0;
|
|
1160
1574
|
if (ref.kind !== "field" && ref.kind !== "option") return void 0;
|
|
@@ -1313,8 +1727,7 @@ function validateUtilityMarkers(v) {
|
|
|
1313
1727
|
"percent"
|
|
1314
1728
|
]);
|
|
1315
1729
|
for (const f of v.fields) {
|
|
1316
|
-
const
|
|
1317
|
-
for (const o of optsArr) {
|
|
1730
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
1318
1731
|
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
1319
1732
|
const hasService = isServiceIdRef(o.service_id);
|
|
1320
1733
|
const util = (_c = o.meta) == null ? void 0 : _c.utility;
|
|
@@ -1550,13 +1963,13 @@ function normalizeServiceRef(value) {
|
|
|
1550
1963
|
|
|
1551
1964
|
// src/core/validate/steps/rates.ts
|
|
1552
1965
|
function validateRates(v) {
|
|
1553
|
-
var _a, _b
|
|
1966
|
+
var _a, _b;
|
|
1554
1967
|
const ratePolicy = normalizeRatePolicy(v.options.ratePolicy);
|
|
1555
1968
|
for (const f of v.fields) {
|
|
1556
1969
|
if (!isMultiField(f)) continue;
|
|
1557
1970
|
const baseRates = [];
|
|
1558
|
-
for (const o of (
|
|
1559
|
-
const role = (
|
|
1971
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
1972
|
+
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
1560
1973
|
if (role !== "base") continue;
|
|
1561
1974
|
const sid = o.service_id;
|
|
1562
1975
|
if (!isServiceIdRef(sid)) continue;
|
|
@@ -1758,8 +2171,9 @@ function collectAnchors(fields) {
|
|
|
1758
2171
|
const anchors = [];
|
|
1759
2172
|
for (const field of fields) {
|
|
1760
2173
|
if (!isButton(field)) continue;
|
|
1761
|
-
|
|
1762
|
-
|
|
2174
|
+
const optionVisits = walkFieldOptions(field);
|
|
2175
|
+
if (optionVisits.length > 0) {
|
|
2176
|
+
for (const { option } of optionVisits) {
|
|
1763
2177
|
anchors.push({
|
|
1764
2178
|
kind: "option",
|
|
1765
2179
|
id: option.id,
|
|
@@ -1808,8 +2222,9 @@ function collectFieldReferences(field, services) {
|
|
|
1808
2222
|
function collectBaseMembers(field, services) {
|
|
1809
2223
|
var _a, _b, _c;
|
|
1810
2224
|
const members = [];
|
|
1811
|
-
|
|
1812
|
-
|
|
2225
|
+
const optionVisits = walkFieldOptions(field);
|
|
2226
|
+
if (optionVisits.length > 0) {
|
|
2227
|
+
for (const { option } of optionVisits) {
|
|
1813
2228
|
const role2 = normalizeRole((_a = option.pricing_role) != null ? _a : field.pricing_role, "base");
|
|
1814
2229
|
if (role2 !== "base") continue;
|
|
1815
2230
|
if (option.service_id === void 0 || option.service_id === null) {
|
|
@@ -2224,7 +2639,7 @@ function effectiveConstraints(v, tagId) {
|
|
|
2224
2639
|
return out;
|
|
2225
2640
|
}
|
|
2226
2641
|
function validateConstraints(v) {
|
|
2227
|
-
var _a
|
|
2642
|
+
var _a;
|
|
2228
2643
|
for (const t of v.tags) {
|
|
2229
2644
|
const eff = effectiveConstraints(v, t.id);
|
|
2230
2645
|
const hasAnyRequired = Object.values(eff).some(
|
|
@@ -2233,7 +2648,7 @@ function validateConstraints(v) {
|
|
|
2233
2648
|
if (!hasAnyRequired) continue;
|
|
2234
2649
|
const visible = v.fieldsVisibleUnder(t.id);
|
|
2235
2650
|
for (const f of visible) {
|
|
2236
|
-
for (const o of (
|
|
2651
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2237
2652
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
2238
2653
|
const svc = getServiceCapability(v.serviceMap, o.service_id);
|
|
2239
2654
|
if (!svc || typeof svc !== "object") continue;
|
|
@@ -2287,7 +2702,7 @@ function validateConstraints(v) {
|
|
|
2287
2702
|
if (!row) continue;
|
|
2288
2703
|
const from = row.from === true;
|
|
2289
2704
|
const to = row.to === true;
|
|
2290
|
-
const origin = String((
|
|
2705
|
+
const origin = String((_a = row.origin) != null ? _a : "");
|
|
2291
2706
|
v.errors.push({
|
|
2292
2707
|
code: "constraint_overridden",
|
|
2293
2708
|
severity: "warning",
|
|
@@ -2321,14 +2736,14 @@ function validateCustomFields(v) {
|
|
|
2321
2736
|
|
|
2322
2737
|
// src/core/validate/steps/global-utility-guard.ts
|
|
2323
2738
|
function validateGlobalUtilityGuard(v) {
|
|
2324
|
-
var _a, _b
|
|
2739
|
+
var _a, _b;
|
|
2325
2740
|
if (!v.options.globalUtilityGuard) return;
|
|
2326
2741
|
let hasUtility = false;
|
|
2327
2742
|
let hasBase = false;
|
|
2328
2743
|
for (const f of v.fields) {
|
|
2329
|
-
for (const o of (
|
|
2744
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2330
2745
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
2331
|
-
const role = (
|
|
2746
|
+
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
2332
2747
|
if (role === "base") hasBase = true;
|
|
2333
2748
|
else if (role === "utility") hasUtility = true;
|
|
2334
2749
|
if (hasUtility && hasBase) break;
|
|
@@ -2530,7 +2945,7 @@ function applyFilterAllowLists(tagId, fieldId, filter) {
|
|
|
2530
2945
|
return true;
|
|
2531
2946
|
}
|
|
2532
2947
|
function collectServiceItems(args) {
|
|
2533
|
-
var _a, _b, _c, _d
|
|
2948
|
+
var _a, _b, _c, _d;
|
|
2534
2949
|
const filter = args.filter;
|
|
2535
2950
|
const roleFilter = (_a = filter == null ? void 0 : filter.role) != null ? _a : "both";
|
|
2536
2951
|
const where = filter == null ? void 0 : filter.where;
|
|
@@ -2580,7 +2995,7 @@ function collectServiceItems(args) {
|
|
|
2580
2995
|
affectedIds: [`field:${f.id}`, `service:${String(fSid)}`]
|
|
2581
2996
|
});
|
|
2582
2997
|
}
|
|
2583
|
-
for (const o of (
|
|
2998
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2584
2999
|
const oSid = o.service_id;
|
|
2585
3000
|
if (!isServiceIdRef2(oSid)) continue;
|
|
2586
3001
|
const role = fieldRoleOf(f, o);
|
|
@@ -2665,7 +3080,7 @@ function collectServiceItems(args) {
|
|
|
2665
3080
|
}
|
|
2666
3081
|
} else if (includeGroupFallbacks) {
|
|
2667
3082
|
const allowPrimaries = new Set(
|
|
2668
|
-
((
|
|
3083
|
+
((_d = args.visiblePrimaries) != null ? _d : []).map((x) => String(x))
|
|
2669
3084
|
);
|
|
2670
3085
|
for (const primaryKey of allowPrimaries) {
|
|
2671
3086
|
const list = globalFb[primaryKey];
|
|
@@ -2746,17 +3161,15 @@ function affectedFromItems(items) {
|
|
|
2746
3161
|
return uniq(ids);
|
|
2747
3162
|
}
|
|
2748
3163
|
function visibleGroupNodeIds(tag, fields) {
|
|
2749
|
-
var _a;
|
|
2750
3164
|
const ids = [tag.id];
|
|
2751
3165
|
for (const f of fields) {
|
|
2752
|
-
for (const o of (
|
|
3166
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2753
3167
|
ids.push(o.id);
|
|
2754
3168
|
}
|
|
2755
3169
|
}
|
|
2756
3170
|
return uniq(ids);
|
|
2757
3171
|
}
|
|
2758
3172
|
function visibleGroupPrimaries(tag, fields) {
|
|
2759
|
-
var _a;
|
|
2760
3173
|
const prim = [];
|
|
2761
3174
|
const tagSid = tag.service_id;
|
|
2762
3175
|
if (typeof tagSid === "string" || typeof tagSid === "number" && Number.isFinite(tagSid)) {
|
|
@@ -2767,7 +3180,7 @@ function visibleGroupPrimaries(tag, fields) {
|
|
|
2767
3180
|
if (typeof fsid === "string" || typeof fsid === "number" && Number.isFinite(fsid)) {
|
|
2768
3181
|
prim.push(fsid);
|
|
2769
3182
|
}
|
|
2770
|
-
for (const o of (
|
|
3183
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2771
3184
|
const osid = o.service_id;
|
|
2772
3185
|
if (typeof osid === "string" || typeof osid === "number" && Number.isFinite(osid)) {
|
|
2773
3186
|
prim.push(osid);
|
|
@@ -2991,6 +3404,7 @@ function validate(props, ctx = {}) {
|
|
|
2991
3404
|
validateStructure(v);
|
|
2992
3405
|
validateIdentity(v);
|
|
2993
3406
|
validateOptionMaps(v);
|
|
3407
|
+
validateVisibilityCycles(v);
|
|
2994
3408
|
validateOrderKinds(v);
|
|
2995
3409
|
v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
|
|
2996
3410
|
const visSim = readVisibilitySimOpts(options);
|
|
@@ -3135,14 +3549,14 @@ var BuilderImpl = class {
|
|
|
3135
3549
|
const showOptions = showSet.has(f.id);
|
|
3136
3550
|
if (!showOptions) continue;
|
|
3137
3551
|
if (!Array.isArray(f.options)) continue;
|
|
3138
|
-
for (const o of f
|
|
3552
|
+
for (const { option: o, parentId } of walkFieldOptions(f)) {
|
|
3139
3553
|
nodes.push({
|
|
3140
3554
|
id: o.id,
|
|
3141
3555
|
kind: "option",
|
|
3142
3556
|
label: o.label
|
|
3143
3557
|
});
|
|
3144
3558
|
const e = {
|
|
3145
|
-
from: f.id,
|
|
3559
|
+
from: parentId != null ? parentId : f.id,
|
|
3146
3560
|
to: o.id,
|
|
3147
3561
|
kind: "option",
|
|
3148
3562
|
meta: { ownerField: f.id }
|
|
@@ -3189,7 +3603,7 @@ var BuilderImpl = class {
|
|
|
3189
3603
|
return { nodes, edges };
|
|
3190
3604
|
}
|
|
3191
3605
|
cleanedProps() {
|
|
3192
|
-
var _a, _b, _c, _d, _e;
|
|
3606
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3193
3607
|
const fieldIds = new Set(this.props.fields.map((f) => f.id));
|
|
3194
3608
|
const optionIds = /* @__PURE__ */ new Set();
|
|
3195
3609
|
this.optionOwnerById.forEach((_v, oid) => optionIds.add(oid));
|
|
@@ -3201,6 +3615,7 @@ var BuilderImpl = class {
|
|
|
3201
3615
|
}
|
|
3202
3616
|
const incMap = (_c = this.props.includes_for_buttons) != null ? _c : {};
|
|
3203
3617
|
const excMap = (_d = this.props.excludes_for_buttons) != null ? _d : {};
|
|
3618
|
+
const effectMap = (_e = this.props.option_effects_for_buttons) != null ? _e : {};
|
|
3204
3619
|
const includedByButtons = /* @__PURE__ */ new Set();
|
|
3205
3620
|
const referencedKeys = /* @__PURE__ */ new Set();
|
|
3206
3621
|
const referencedOwnerFields = /* @__PURE__ */ new Set();
|
|
@@ -3220,6 +3635,14 @@ var BuilderImpl = class {
|
|
|
3220
3635
|
void fid;
|
|
3221
3636
|
}
|
|
3222
3637
|
}
|
|
3638
|
+
for (const [key, targets] of Object.entries(effectMap)) {
|
|
3639
|
+
referencedKeys.add(key);
|
|
3640
|
+
const owner = this.optionOwnerById.get(key);
|
|
3641
|
+
if (owner) referencedOwnerFields.add(owner.fieldId);
|
|
3642
|
+
for (const [fid, effect] of Object.entries(targets != null ? targets : {})) {
|
|
3643
|
+
if ((effect == null ? void 0 : effect.forceVisible) === true) includedByButtons.add(fid);
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3223
3646
|
const boundIds = /* @__PURE__ */ new Set();
|
|
3224
3647
|
for (const f of this.props.fields) {
|
|
3225
3648
|
const b = f.bind_id;
|
|
@@ -3237,6 +3660,7 @@ var BuilderImpl = class {
|
|
|
3237
3660
|
return bound || included || referenced || !excluded;
|
|
3238
3661
|
});
|
|
3239
3662
|
const allowedTargets = new Set(fields.map((f) => f.id));
|
|
3663
|
+
const allowedFieldById = new Map(fields.map((f) => [f.id, f]));
|
|
3240
3664
|
const pruneButtons = (src) => {
|
|
3241
3665
|
if (!src) return void 0;
|
|
3242
3666
|
const out2 = {};
|
|
@@ -3256,13 +3680,52 @@ var BuilderImpl = class {
|
|
|
3256
3680
|
const excludes_for_buttons = pruneButtons(
|
|
3257
3681
|
this.props.excludes_for_buttons
|
|
3258
3682
|
);
|
|
3683
|
+
const pruneOptionEffects = (src) => {
|
|
3684
|
+
var _a2, _b2, _c2, _d2;
|
|
3685
|
+
if (!src) return void 0;
|
|
3686
|
+
const out2 = {};
|
|
3687
|
+
for (const [key, targets] of Object.entries(src)) {
|
|
3688
|
+
const keyIsValid = optionIds.has(key) || fieldIds.has(key);
|
|
3689
|
+
if (!keyIsValid) continue;
|
|
3690
|
+
const cleanedTargets = {};
|
|
3691
|
+
for (const [targetFieldId, effect] of Object.entries(
|
|
3692
|
+
targets != null ? targets : {}
|
|
3693
|
+
)) {
|
|
3694
|
+
const field = allowedFieldById.get(targetFieldId);
|
|
3695
|
+
if (!field || !effect) continue;
|
|
3696
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
3697
|
+
const include = Array.from(
|
|
3698
|
+
new Set((_a2 = effect.include) != null ? _a2 : [])
|
|
3699
|
+
).filter((optionId) => validOptionIds.has(optionId));
|
|
3700
|
+
const exclude = Array.from(
|
|
3701
|
+
new Set((_b2 = effect.exclude) != null ? _b2 : [])
|
|
3702
|
+
).filter((optionId) => validOptionIds.has(optionId));
|
|
3703
|
+
const next = {
|
|
3704
|
+
...effect.forceVisible === true ? { forceVisible: true } : {},
|
|
3705
|
+
...include.length ? { include } : {},
|
|
3706
|
+
...exclude.length ? { exclude } : {}
|
|
3707
|
+
};
|
|
3708
|
+
if (next.forceVisible === true || ((_c2 = next.include) == null ? void 0 : _c2.length) || ((_d2 = next.exclude) == null ? void 0 : _d2.length)) {
|
|
3709
|
+
cleanedTargets[targetFieldId] = next;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
if (Object.keys(cleanedTargets).length) {
|
|
3713
|
+
out2[key] = cleanedTargets;
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
return Object.keys(out2).length ? out2 : void 0;
|
|
3717
|
+
};
|
|
3718
|
+
const option_effects_for_buttons = pruneOptionEffects(
|
|
3719
|
+
this.props.option_effects_for_buttons
|
|
3720
|
+
);
|
|
3259
3721
|
const out = {
|
|
3260
3722
|
filters: this.props.filters.slice(),
|
|
3261
3723
|
fields,
|
|
3262
3724
|
...this.props.orderKinds ? { orderKinds: this.props.orderKinds } : {},
|
|
3263
3725
|
...includes_for_buttons && { includes_for_buttons },
|
|
3264
3726
|
...excludes_for_buttons && { excludes_for_buttons },
|
|
3265
|
-
|
|
3727
|
+
...option_effects_for_buttons && { option_effects_for_buttons },
|
|
3728
|
+
schema_version: (_f = this.props.schema_version) != null ? _f : "1.0",
|
|
3266
3729
|
// keep fallbacks & other maps as-is
|
|
3267
3730
|
...this.props.fallbacks ? { fallbacks: this.props.fallbacks } : {}
|
|
3268
3731
|
};
|
|
@@ -3275,12 +3738,15 @@ var BuilderImpl = class {
|
|
|
3275
3738
|
return (0, import_lodash_es2.cloneDeep)(this.options);
|
|
3276
3739
|
}
|
|
3277
3740
|
visibleFields(tagId, selectedKeys) {
|
|
3741
|
+
return this.resolveVisibility(tagId, selectedKeys).fieldIds;
|
|
3742
|
+
}
|
|
3743
|
+
resolveVisibility(tagId, selectedKeys) {
|
|
3278
3744
|
var _a;
|
|
3279
|
-
return
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
)
|
|
3283
|
-
|
|
3745
|
+
return resolveVisibility(
|
|
3746
|
+
this.props,
|
|
3747
|
+
tagId,
|
|
3748
|
+
(_a = selectedKeys != null ? selectedKeys : this.options.selectedOptionKeys) != null ? _a : []
|
|
3749
|
+
);
|
|
3284
3750
|
}
|
|
3285
3751
|
getNodeMap() {
|
|
3286
3752
|
if (!this._nodemap) this._nodemap = buildNodeMap(this.getProps());
|
|
@@ -3295,9 +3761,8 @@ var BuilderImpl = class {
|
|
|
3295
3761
|
for (const t of this.props.filters) this.tagById.set(t.id, t);
|
|
3296
3762
|
for (const f of this.props.fields) {
|
|
3297
3763
|
this.fieldById.set(f.id, f);
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
this.optionOwnerById.set(o.id, { fieldId: f.id });
|
|
3764
|
+
for (const [optionId, owner] of optionOwnerMap([f])) {
|
|
3765
|
+
this.optionOwnerById.set(optionId, { fieldId: owner.fieldId });
|
|
3301
3766
|
}
|
|
3302
3767
|
}
|
|
3303
3768
|
}
|
|
@@ -4775,24 +5240,44 @@ function isFiniteNumber2(v) {
|
|
|
4775
5240
|
|
|
4776
5241
|
// src/utils/build-order-snapshot/selection.ts
|
|
4777
5242
|
function isOptionBased(f) {
|
|
4778
|
-
const hasOptions =
|
|
5243
|
+
const hasOptions = fieldOptionIdSet(f).size > 0;
|
|
4779
5244
|
return hasOptions || isMultiField(f);
|
|
4780
5245
|
}
|
|
4781
5246
|
function toSelectedOptionKeys(byField) {
|
|
4782
5247
|
const keys = [];
|
|
4783
|
-
for (const
|
|
5248
|
+
for (const optionIds of Object.values(byField != null ? byField : {})) {
|
|
4784
5249
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4785
|
-
keys.push(
|
|
5250
|
+
keys.push(optionId);
|
|
4786
5251
|
}
|
|
4787
5252
|
}
|
|
4788
5253
|
return keys;
|
|
4789
5254
|
}
|
|
4790
|
-
function getSelectedOptionsByFieldId(selection, fieldById) {
|
|
4791
|
-
|
|
5255
|
+
function getSelectedOptionsByFieldId(selection, fieldById, mode, visibleOptionsByFieldId) {
|
|
5256
|
+
var _a;
|
|
5257
|
+
const collected = {};
|
|
4792
5258
|
for (const visit of buildSelectedNodeVisitOrder(selection, fieldById)) {
|
|
4793
5259
|
if (visit.kind !== "option") continue;
|
|
4794
|
-
if (!
|
|
4795
|
-
|
|
5260
|
+
if (!collected[visit.fieldId]) collected[visit.fieldId] = [];
|
|
5261
|
+
collected[visit.fieldId].push(visit.optionId);
|
|
5262
|
+
}
|
|
5263
|
+
const out = {};
|
|
5264
|
+
for (const [fieldId, optionIds] of Object.entries(collected)) {
|
|
5265
|
+
const field = fieldById.get(fieldId);
|
|
5266
|
+
if (!field) continue;
|
|
5267
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
5268
|
+
const visibleOptionIds = (visibleOptionsByFieldId == null ? void 0 : visibleOptionsByFieldId[fieldId]) ? new Set(visibleOptionsByFieldId[fieldId]) : void 0;
|
|
5269
|
+
const dedupedValid = [];
|
|
5270
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5271
|
+
for (const optionId of optionIds) {
|
|
5272
|
+
if (!validOptionIds.has(optionId)) continue;
|
|
5273
|
+
if (visibleOptionIds && !visibleOptionIds.has(optionId)) continue;
|
|
5274
|
+
if (seen.has(optionId)) continue;
|
|
5275
|
+
seen.add(optionId);
|
|
5276
|
+
dedupedValid.push(optionId);
|
|
5277
|
+
}
|
|
5278
|
+
const isMulti = ((_a = field.meta) == null ? void 0 : _a.multi) === true;
|
|
5279
|
+
const normalized = mode === "prod" && !isMulti ? dedupedValid.length ? [dedupedValid[dedupedValid.length - 1]] : [] : dedupedValid;
|
|
5280
|
+
if (normalized.length) out[fieldId] = normalized;
|
|
4796
5281
|
}
|
|
4797
5282
|
return out;
|
|
4798
5283
|
}
|
|
@@ -4807,57 +5292,49 @@ function buildSelectedNodeVisitOrder(selection, fieldById) {
|
|
|
4807
5292
|
out.push({ kind: "field", fieldId });
|
|
4808
5293
|
}
|
|
4809
5294
|
function pushOption(fieldId, optionId) {
|
|
4810
|
-
const key = `option:${
|
|
5295
|
+
const key = `option:${optionId}`;
|
|
4811
5296
|
if (seen.has(key)) return;
|
|
4812
5297
|
seen.add(key);
|
|
4813
5298
|
out.push({ kind: "option", fieldId, optionId });
|
|
4814
5299
|
}
|
|
4815
|
-
for (const
|
|
4816
|
-
|
|
5300
|
+
for (const optionId of (_a = selection.optionTraversalOrder) != null ? _a : []) {
|
|
5301
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5302
|
+
if (ownerField) pushOption(ownerField.id, optionId);
|
|
4817
5303
|
}
|
|
4818
5304
|
for (const rawKey of (_b = selection.selectedKeys) != null ? _b : []) {
|
|
4819
5305
|
const key = String(rawKey);
|
|
4820
|
-
if (key.includes("::")) {
|
|
4821
|
-
const [fieldId, optionId] = key.split("::", 2);
|
|
4822
|
-
if (fieldId && optionId) pushOption(fieldId, optionId);
|
|
4823
|
-
continue;
|
|
4824
|
-
}
|
|
4825
5306
|
const field = fieldById.get(key);
|
|
4826
5307
|
if (field) {
|
|
4827
5308
|
pushField(field.id);
|
|
4828
5309
|
continue;
|
|
4829
5310
|
}
|
|
4830
|
-
const ownerField = findOptionOwnerField(
|
|
5311
|
+
const ownerField = findOptionOwnerField(fieldById.values(), key);
|
|
4831
5312
|
if (ownerField) pushOption(ownerField.id, key);
|
|
4832
5313
|
}
|
|
4833
5314
|
for (const [fieldId, optionIds] of Object.entries(
|
|
4834
5315
|
(_c = selection.optionSelectionsByFieldId) != null ? _c : {}
|
|
4835
5316
|
)) {
|
|
4836
|
-
|
|
5317
|
+
const hintedField = fieldById.get(fieldId);
|
|
5318
|
+
if (!hintedField) continue;
|
|
4837
5319
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4838
|
-
|
|
5320
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5321
|
+
if ((ownerField == null ? void 0 : ownerField.id) === hintedField.id) {
|
|
5322
|
+
pushOption(ownerField.id, optionId);
|
|
5323
|
+
}
|
|
4839
5324
|
}
|
|
4840
5325
|
}
|
|
4841
5326
|
return out;
|
|
4842
5327
|
}
|
|
4843
|
-
function findOptionOwnerField(optionId, fieldById) {
|
|
4844
|
-
var _a;
|
|
4845
|
-
for (const field of fieldById.values()) {
|
|
4846
|
-
if ((_a = field.options) == null ? void 0 : _a.some((option) => option.id === optionId)) return field;
|
|
4847
|
-
}
|
|
4848
|
-
return void 0;
|
|
4849
|
-
}
|
|
4850
5328
|
|
|
4851
5329
|
// src/utils/build-order-snapshot/services.ts
|
|
4852
5330
|
function isServiceBased(field) {
|
|
4853
|
-
var _a;
|
|
4854
5331
|
if (field.service_id !== void 0 && field.service_id !== null) return true;
|
|
4855
|
-
return
|
|
4856
|
-
(
|
|
4857
|
-
)
|
|
5332
|
+
return walkFieldOptions(field).some(
|
|
5333
|
+
({ option }) => option.service_id !== void 0 && option.service_id !== null
|
|
5334
|
+
);
|
|
4858
5335
|
}
|
|
4859
5336
|
function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById, services) {
|
|
4860
|
-
var _a, _b, _c
|
|
5337
|
+
var _a, _b, _c;
|
|
4861
5338
|
const serviceMap = {};
|
|
4862
5339
|
const visible = new Set(visibleFieldIds);
|
|
4863
5340
|
const selectedBaseServices = [];
|
|
@@ -4884,9 +5361,9 @@ function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById,
|
|
|
4884
5361
|
}
|
|
4885
5362
|
continue;
|
|
4886
5363
|
}
|
|
4887
|
-
const option = (
|
|
5364
|
+
const option = findFieldOption(field, visit.optionId);
|
|
4888
5365
|
if (!option) continue;
|
|
4889
|
-
const role = (
|
|
5366
|
+
const role = (_c = (_b = option.pricing_role) != null ? _b : field.pricing_role) != null ? _c : "base";
|
|
4890
5367
|
if (role === "utility") continue;
|
|
4891
5368
|
if (option.service_id !== void 0 && option.service_id !== null) {
|
|
4892
5369
|
addSelectedBaseService(option.id, option.service_id);
|
|
@@ -5017,16 +5494,15 @@ function resolveQuantity(visibleFieldIds, fieldById, tagById, selection, tagId,
|
|
|
5017
5494
|
return { quantity: hostDefault, source: { kind: "default", defaultedFromHost: true } };
|
|
5018
5495
|
}
|
|
5019
5496
|
function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selection, tagId) {
|
|
5020
|
-
var _a, _b
|
|
5497
|
+
var _a, _b;
|
|
5021
5498
|
const visible = new Set(visibleFieldIds);
|
|
5022
5499
|
const visits = buildSelectedNodeVisitOrder(selection, fieldById);
|
|
5023
5500
|
for (const visit of visits) {
|
|
5024
5501
|
if (visit.kind !== "option") continue;
|
|
5025
5502
|
if (!visible.has(visit.fieldId)) continue;
|
|
5026
5503
|
const field = fieldById.get(visit.fieldId);
|
|
5027
|
-
|
|
5028
|
-
const
|
|
5029
|
-
const quantity = readPositiveFiniteNumber((_b = option == null ? void 0 : option.meta) == null ? void 0 : _b.quantityDefault);
|
|
5504
|
+
const option = findFieldOption(field, visit.optionId);
|
|
5505
|
+
const quantity = readPositiveFiniteNumber((_a = option == null ? void 0 : option.meta) == null ? void 0 : _a.quantityDefault);
|
|
5030
5506
|
if (quantity !== void 0) {
|
|
5031
5507
|
return { quantity, source: { kind: "option", id: option.id } };
|
|
5032
5508
|
}
|
|
@@ -5041,7 +5517,7 @@ function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selecti
|
|
|
5041
5517
|
}
|
|
5042
5518
|
}
|
|
5043
5519
|
const tag = tagById.get(tagId);
|
|
5044
|
-
const tagQuantity = readPositiveFiniteNumber((
|
|
5520
|
+
const tagQuantity = readPositiveFiniteNumber((_b = tag == null ? void 0 : tag.meta) == null ? void 0 : _b.quantityDefault);
|
|
5045
5521
|
if (tagQuantity !== void 0) {
|
|
5046
5522
|
return { quantity: tagQuantity, source: { kind: "tag", id: tagId } };
|
|
5047
5523
|
}
|
|
@@ -5144,12 +5620,10 @@ function collectUtilityLineItems(visibleFieldIds, fieldById, selection, selected
|
|
|
5144
5620
|
const item = buildUtilityItemFromMarker(field.id, marker, quantity, value);
|
|
5145
5621
|
if (item) items.push(item);
|
|
5146
5622
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
if (!selectedOptionIds.length) continue;
|
|
5150
|
-
const optById = new Map(field.options.map((o) => [o.id, o]));
|
|
5623
|
+
const selectedOptionIds = (_c = selectedOptionsByFieldId[field.id]) != null ? _c : [];
|
|
5624
|
+
if (selectedOptionIds.length) {
|
|
5151
5625
|
for (const oid of selectedOptionIds) {
|
|
5152
|
-
const option =
|
|
5626
|
+
const option = findFieldOption(field, oid);
|
|
5153
5627
|
if (!option) continue;
|
|
5154
5628
|
if (((_d = option.pricing_role) != null ? _d : "base") !== "utility") continue;
|
|
5155
5629
|
const optionMarker = readUtilityMarker((_e = option.meta) == null ? void 0 : _e.utility);
|
|
@@ -5265,7 +5739,7 @@ function buildDevWarnings(props, svcMap, originalFallbacks, fieldById, visibleFi
|
|
|
5265
5739
|
|
|
5266
5740
|
// src/utils/build-order-snapshot/index.ts
|
|
5267
5741
|
function buildOrderSnapshot(props, builder, selection, services, settings = {}) {
|
|
5268
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5742
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
5269
5743
|
const mode = (_a = settings.mode) != null ? _a : "prod";
|
|
5270
5744
|
const hostDefaultQty = Number.isFinite((_b = settings.hostDefaultQuantity) != null ? _b : 1) ? settings.hostDefaultQuantity : 1;
|
|
5271
5745
|
const fbSettings = {
|
|
@@ -5278,11 +5752,32 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5278
5752
|
const builtAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5279
5753
|
const tagId = selection.activeTagId;
|
|
5280
5754
|
const selectedButtonKeys = (_d = selection.selectedKeys) != null ? _d : toSelectedOptionKeys(selection.optionSelectionsByFieldId);
|
|
5281
|
-
const visibleFieldIds = builder.visibleFields(tagId, selectedButtonKeys);
|
|
5282
5755
|
const tagById = new Map(((_e = props.filters) != null ? _e : []).map((t) => [t.id, t]));
|
|
5283
5756
|
const fieldById = new Map(((_f = props.fields) != null ? _f : []).map((f) => [f.id, f]));
|
|
5284
|
-
const
|
|
5285
|
-
|
|
5757
|
+
const resolve = typeof builder.resolveVisibility === "function" ? builder.resolveVisibility.bind(builder) : void 0;
|
|
5758
|
+
let resolvedVisibility = resolve == null ? void 0 : resolve(tagId, selectedButtonKeys);
|
|
5759
|
+
let visibleFieldIds = (_g = resolvedVisibility == null ? void 0 : resolvedVisibility.fieldIds) != null ? _g : builder.visibleFields(tagId, selectedButtonKeys);
|
|
5760
|
+
const filteredSelectedButtonKeys = filterSelectedKeysByVisibility(
|
|
5761
|
+
selectedButtonKeys,
|
|
5762
|
+
visibleFieldIds,
|
|
5763
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId,
|
|
5764
|
+
fieldById
|
|
5765
|
+
);
|
|
5766
|
+
if (resolve && filteredSelectedButtonKeys.join("\0") !== selectedButtonKeys.join("\0")) {
|
|
5767
|
+
resolvedVisibility = resolve(tagId, filteredSelectedButtonKeys);
|
|
5768
|
+
visibleFieldIds = resolvedVisibility.fieldIds;
|
|
5769
|
+
}
|
|
5770
|
+
const effectiveSelection = {
|
|
5771
|
+
...selection,
|
|
5772
|
+
selectedKeys: filteredSelectedButtonKeys
|
|
5773
|
+
};
|
|
5774
|
+
const tagConstraints = (_i = (_h = tagById.get(tagId)) == null ? void 0 : _h.constraints) != null ? _i : void 0;
|
|
5775
|
+
const selectedOptionsByFieldId = getSelectedOptionsByFieldId(
|
|
5776
|
+
effectiveSelection,
|
|
5777
|
+
fieldById,
|
|
5778
|
+
mode,
|
|
5779
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId
|
|
5780
|
+
);
|
|
5286
5781
|
const selectionFields = visibleFieldIds.map((fid) => fieldById.get(fid)).filter((f) => !!f).map((f) => {
|
|
5287
5782
|
var _a2;
|
|
5288
5783
|
const optionIds = isOptionBased(f) ? (_a2 = selectedOptionsByFieldId[f.id]) != null ? _a2 : [] : void 0;
|
|
@@ -5295,21 +5790,21 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5295
5790
|
const { formValues, selections } = buildInputs(
|
|
5296
5791
|
visibleFieldIds,
|
|
5297
5792
|
fieldById,
|
|
5298
|
-
|
|
5793
|
+
effectiveSelection,
|
|
5299
5794
|
selectedOptionsByFieldId
|
|
5300
5795
|
);
|
|
5301
5796
|
const qtyRes = resolveQuantity(
|
|
5302
5797
|
visibleFieldIds,
|
|
5303
5798
|
fieldById,
|
|
5304
5799
|
tagById,
|
|
5305
|
-
|
|
5800
|
+
effectiveSelection,
|
|
5306
5801
|
tagId,
|
|
5307
5802
|
hostDefaultQty
|
|
5308
5803
|
);
|
|
5309
5804
|
const { serviceMap, servicesList } = resolveServices(
|
|
5310
5805
|
tagId,
|
|
5311
5806
|
visibleFieldIds,
|
|
5312
|
-
|
|
5807
|
+
effectiveSelection,
|
|
5313
5808
|
tagById,
|
|
5314
5809
|
fieldById,
|
|
5315
5810
|
services
|
|
@@ -5331,7 +5826,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5331
5826
|
const utilities = collectUtilityLineItems(
|
|
5332
5827
|
visibleFieldIds,
|
|
5333
5828
|
fieldById,
|
|
5334
|
-
|
|
5829
|
+
effectiveSelection,
|
|
5335
5830
|
selectedOptionsByFieldId,
|
|
5336
5831
|
qtyRes.quantity
|
|
5337
5832
|
);
|
|
@@ -5341,7 +5836,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5341
5836
|
prunedFallbacks.original,
|
|
5342
5837
|
fieldById,
|
|
5343
5838
|
visibleFieldIds,
|
|
5344
|
-
|
|
5839
|
+
effectiveSelection
|
|
5345
5840
|
) : void 0;
|
|
5346
5841
|
const meta = {
|
|
5347
5842
|
schema_version: props.schema_version,
|
|
@@ -5354,7 +5849,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5354
5849
|
tagId,
|
|
5355
5850
|
visibleFieldIds,
|
|
5356
5851
|
fieldById,
|
|
5357
|
-
|
|
5852
|
+
effectiveSelection,
|
|
5358
5853
|
selectedOptionsByFieldId
|
|
5359
5854
|
),
|
|
5360
5855
|
policy: toSnapshotPolicy(fbSettings)
|
|
@@ -5366,7 +5861,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5366
5861
|
builtAt,
|
|
5367
5862
|
selection: {
|
|
5368
5863
|
tag: tagId,
|
|
5369
|
-
buttons:
|
|
5864
|
+
buttons: filteredSelectedButtonKeys,
|
|
5370
5865
|
fields: selectionFields
|
|
5371
5866
|
},
|
|
5372
5867
|
inputs: { form: formValues, selections },
|
|
@@ -5384,6 +5879,24 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5384
5879
|
meta
|
|
5385
5880
|
};
|
|
5386
5881
|
}
|
|
5882
|
+
function filterSelectedKeysByVisibility(selectedKeys, visibleFieldIds, optionsByFieldId, fieldById) {
|
|
5883
|
+
if (!optionsByFieldId) return selectedKeys;
|
|
5884
|
+
const visibleFields = new Set(visibleFieldIds);
|
|
5885
|
+
const out = [];
|
|
5886
|
+
for (const rawKey of selectedKeys) {
|
|
5887
|
+
const key = String(rawKey);
|
|
5888
|
+
if (fieldById.has(key)) {
|
|
5889
|
+
if (visibleFields.has(key)) out.push(key);
|
|
5890
|
+
continue;
|
|
5891
|
+
}
|
|
5892
|
+
const owner = findOptionOwnerField(fieldById.values(), key);
|
|
5893
|
+
if (!owner || !visibleFields.has(owner.id)) continue;
|
|
5894
|
+
const allowed = optionsByFieldId[owner.id];
|
|
5895
|
+
if (allowed && !allowed.includes(key)) continue;
|
|
5896
|
+
out.push(key);
|
|
5897
|
+
}
|
|
5898
|
+
return out;
|
|
5899
|
+
}
|
|
5387
5900
|
|
|
5388
5901
|
// src/core/fallback-editor.ts
|
|
5389
5902
|
function createFallbackEditor(options = {}) {
|
|
@@ -5765,16 +6278,24 @@ function mapDiagReason(reason) {
|
|
|
5765
6278
|
createBuilder,
|
|
5766
6279
|
createFallbackEditor,
|
|
5767
6280
|
createNodeIndex,
|
|
6281
|
+
fieldOptionIdSet,
|
|
6282
|
+
fieldOptionIds,
|
|
6283
|
+
filterFieldOptionsById,
|
|
5768
6284
|
filterServicesForVisibleGroup,
|
|
6285
|
+
findFieldOption,
|
|
6286
|
+
findOptionOwnerField,
|
|
5769
6287
|
getAssignedServiceIds,
|
|
5770
6288
|
getEligibleFallbacks,
|
|
5771
6289
|
getFallbackRegistrationInfo,
|
|
5772
6290
|
isRefExcludedBySelectedKeys,
|
|
5773
6291
|
normalise,
|
|
5774
6292
|
normalizeFieldValidation,
|
|
6293
|
+
optionOwnerMap,
|
|
5775
6294
|
resolveServiceFallback,
|
|
5776
6295
|
validate,
|
|
5777
6296
|
validateAsync,
|
|
5778
|
-
validateRateCoherenceDeep
|
|
6297
|
+
validateRateCoherenceDeep,
|
|
6298
|
+
walkFieldOptions,
|
|
6299
|
+
walkOptions
|
|
5779
6300
|
});
|
|
5780
6301
|
//# sourceMappingURL=index.cjs.map
|