@timeax/digital-service-engine 0.3.5 → 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 +659 -162
- 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 +650 -161
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +1424 -448
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +48 -5
- package/dist/react/index.d.ts +48 -5
- package/dist/react/index.js +1424 -448
- 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 +1235 -374
- package/dist/workspace/index.cjs.map +1 -1
- package/dist/workspace/index.d.cts +45 -4
- package/dist/workspace/index.d.ts +45 -4
- package/dist/workspace/index.js +1235 -374
- 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,20 +5240,20 @@ 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, mode) {
|
|
4791
|
-
var _a
|
|
5255
|
+
function getSelectedOptionsByFieldId(selection, fieldById, mode, visibleOptionsByFieldId) {
|
|
5256
|
+
var _a;
|
|
4792
5257
|
const collected = {};
|
|
4793
5258
|
for (const visit of buildSelectedNodeVisitOrder(selection, fieldById)) {
|
|
4794
5259
|
if (visit.kind !== "option") continue;
|
|
@@ -4799,18 +5264,18 @@ function getSelectedOptionsByFieldId(selection, fieldById, mode) {
|
|
|
4799
5264
|
for (const [fieldId, optionIds] of Object.entries(collected)) {
|
|
4800
5265
|
const field = fieldById.get(fieldId);
|
|
4801
5266
|
if (!field) continue;
|
|
4802
|
-
const validOptionIds =
|
|
4803
|
-
|
|
4804
|
-
);
|
|
5267
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
5268
|
+
const visibleOptionIds = (visibleOptionsByFieldId == null ? void 0 : visibleOptionsByFieldId[fieldId]) ? new Set(visibleOptionsByFieldId[fieldId]) : void 0;
|
|
4805
5269
|
const dedupedValid = [];
|
|
4806
5270
|
const seen = /* @__PURE__ */ new Set();
|
|
4807
5271
|
for (const optionId of optionIds) {
|
|
4808
5272
|
if (!validOptionIds.has(optionId)) continue;
|
|
5273
|
+
if (visibleOptionIds && !visibleOptionIds.has(optionId)) continue;
|
|
4809
5274
|
if (seen.has(optionId)) continue;
|
|
4810
5275
|
seen.add(optionId);
|
|
4811
5276
|
dedupedValid.push(optionId);
|
|
4812
5277
|
}
|
|
4813
|
-
const isMulti = ((
|
|
5278
|
+
const isMulti = ((_a = field.meta) == null ? void 0 : _a.multi) === true;
|
|
4814
5279
|
const normalized = mode === "prod" && !isMulti ? dedupedValid.length ? [dedupedValid[dedupedValid.length - 1]] : [] : dedupedValid;
|
|
4815
5280
|
if (normalized.length) out[fieldId] = normalized;
|
|
4816
5281
|
}
|
|
@@ -4827,57 +5292,49 @@ function buildSelectedNodeVisitOrder(selection, fieldById) {
|
|
|
4827
5292
|
out.push({ kind: "field", fieldId });
|
|
4828
5293
|
}
|
|
4829
5294
|
function pushOption(fieldId, optionId) {
|
|
4830
|
-
const key = `option:${
|
|
5295
|
+
const key = `option:${optionId}`;
|
|
4831
5296
|
if (seen.has(key)) return;
|
|
4832
5297
|
seen.add(key);
|
|
4833
5298
|
out.push({ kind: "option", fieldId, optionId });
|
|
4834
5299
|
}
|
|
4835
|
-
for (const
|
|
4836
|
-
|
|
5300
|
+
for (const optionId of (_a = selection.optionTraversalOrder) != null ? _a : []) {
|
|
5301
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5302
|
+
if (ownerField) pushOption(ownerField.id, optionId);
|
|
4837
5303
|
}
|
|
4838
5304
|
for (const rawKey of (_b = selection.selectedKeys) != null ? _b : []) {
|
|
4839
5305
|
const key = String(rawKey);
|
|
4840
|
-
if (key.includes("::")) {
|
|
4841
|
-
const [fieldId, optionId] = key.split("::", 2);
|
|
4842
|
-
if (fieldId && optionId) pushOption(fieldId, optionId);
|
|
4843
|
-
continue;
|
|
4844
|
-
}
|
|
4845
5306
|
const field = fieldById.get(key);
|
|
4846
5307
|
if (field) {
|
|
4847
5308
|
pushField(field.id);
|
|
4848
5309
|
continue;
|
|
4849
5310
|
}
|
|
4850
|
-
const ownerField = findOptionOwnerField(
|
|
5311
|
+
const ownerField = findOptionOwnerField(fieldById.values(), key);
|
|
4851
5312
|
if (ownerField) pushOption(ownerField.id, key);
|
|
4852
5313
|
}
|
|
4853
5314
|
for (const [fieldId, optionIds] of Object.entries(
|
|
4854
5315
|
(_c = selection.optionSelectionsByFieldId) != null ? _c : {}
|
|
4855
5316
|
)) {
|
|
4856
|
-
|
|
5317
|
+
const hintedField = fieldById.get(fieldId);
|
|
5318
|
+
if (!hintedField) continue;
|
|
4857
5319
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4858
|
-
|
|
5320
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5321
|
+
if ((ownerField == null ? void 0 : ownerField.id) === hintedField.id) {
|
|
5322
|
+
pushOption(ownerField.id, optionId);
|
|
5323
|
+
}
|
|
4859
5324
|
}
|
|
4860
5325
|
}
|
|
4861
5326
|
return out;
|
|
4862
5327
|
}
|
|
4863
|
-
function findOptionOwnerField(optionId, fieldById) {
|
|
4864
|
-
var _a;
|
|
4865
|
-
for (const field of fieldById.values()) {
|
|
4866
|
-
if ((_a = field.options) == null ? void 0 : _a.some((option) => option.id === optionId)) return field;
|
|
4867
|
-
}
|
|
4868
|
-
return void 0;
|
|
4869
|
-
}
|
|
4870
5328
|
|
|
4871
5329
|
// src/utils/build-order-snapshot/services.ts
|
|
4872
5330
|
function isServiceBased(field) {
|
|
4873
|
-
var _a;
|
|
4874
5331
|
if (field.service_id !== void 0 && field.service_id !== null) return true;
|
|
4875
|
-
return
|
|
4876
|
-
(
|
|
4877
|
-
)
|
|
5332
|
+
return walkFieldOptions(field).some(
|
|
5333
|
+
({ option }) => option.service_id !== void 0 && option.service_id !== null
|
|
5334
|
+
);
|
|
4878
5335
|
}
|
|
4879
5336
|
function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById, services) {
|
|
4880
|
-
var _a, _b, _c
|
|
5337
|
+
var _a, _b, _c;
|
|
4881
5338
|
const serviceMap = {};
|
|
4882
5339
|
const visible = new Set(visibleFieldIds);
|
|
4883
5340
|
const selectedBaseServices = [];
|
|
@@ -4904,9 +5361,9 @@ function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById,
|
|
|
4904
5361
|
}
|
|
4905
5362
|
continue;
|
|
4906
5363
|
}
|
|
4907
|
-
const option = (
|
|
5364
|
+
const option = findFieldOption(field, visit.optionId);
|
|
4908
5365
|
if (!option) continue;
|
|
4909
|
-
const role = (
|
|
5366
|
+
const role = (_c = (_b = option.pricing_role) != null ? _b : field.pricing_role) != null ? _c : "base";
|
|
4910
5367
|
if (role === "utility") continue;
|
|
4911
5368
|
if (option.service_id !== void 0 && option.service_id !== null) {
|
|
4912
5369
|
addSelectedBaseService(option.id, option.service_id);
|
|
@@ -5037,16 +5494,15 @@ function resolveQuantity(visibleFieldIds, fieldById, tagById, selection, tagId,
|
|
|
5037
5494
|
return { quantity: hostDefault, source: { kind: "default", defaultedFromHost: true } };
|
|
5038
5495
|
}
|
|
5039
5496
|
function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selection, tagId) {
|
|
5040
|
-
var _a, _b
|
|
5497
|
+
var _a, _b;
|
|
5041
5498
|
const visible = new Set(visibleFieldIds);
|
|
5042
5499
|
const visits = buildSelectedNodeVisitOrder(selection, fieldById);
|
|
5043
5500
|
for (const visit of visits) {
|
|
5044
5501
|
if (visit.kind !== "option") continue;
|
|
5045
5502
|
if (!visible.has(visit.fieldId)) continue;
|
|
5046
5503
|
const field = fieldById.get(visit.fieldId);
|
|
5047
|
-
|
|
5048
|
-
const
|
|
5049
|
-
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);
|
|
5050
5506
|
if (quantity !== void 0) {
|
|
5051
5507
|
return { quantity, source: { kind: "option", id: option.id } };
|
|
5052
5508
|
}
|
|
@@ -5061,7 +5517,7 @@ function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selecti
|
|
|
5061
5517
|
}
|
|
5062
5518
|
}
|
|
5063
5519
|
const tag = tagById.get(tagId);
|
|
5064
|
-
const tagQuantity = readPositiveFiniteNumber((
|
|
5520
|
+
const tagQuantity = readPositiveFiniteNumber((_b = tag == null ? void 0 : tag.meta) == null ? void 0 : _b.quantityDefault);
|
|
5065
5521
|
if (tagQuantity !== void 0) {
|
|
5066
5522
|
return { quantity: tagQuantity, source: { kind: "tag", id: tagId } };
|
|
5067
5523
|
}
|
|
@@ -5164,12 +5620,10 @@ function collectUtilityLineItems(visibleFieldIds, fieldById, selection, selected
|
|
|
5164
5620
|
const item = buildUtilityItemFromMarker(field.id, marker, quantity, value);
|
|
5165
5621
|
if (item) items.push(item);
|
|
5166
5622
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
if (!selectedOptionIds.length) continue;
|
|
5170
|
-
const optById = new Map(field.options.map((o) => [o.id, o]));
|
|
5623
|
+
const selectedOptionIds = (_c = selectedOptionsByFieldId[field.id]) != null ? _c : [];
|
|
5624
|
+
if (selectedOptionIds.length) {
|
|
5171
5625
|
for (const oid of selectedOptionIds) {
|
|
5172
|
-
const option =
|
|
5626
|
+
const option = findFieldOption(field, oid);
|
|
5173
5627
|
if (!option) continue;
|
|
5174
5628
|
if (((_d = option.pricing_role) != null ? _d : "base") !== "utility") continue;
|
|
5175
5629
|
const optionMarker = readUtilityMarker((_e = option.meta) == null ? void 0 : _e.utility);
|
|
@@ -5285,7 +5739,7 @@ function buildDevWarnings(props, svcMap, originalFallbacks, fieldById, visibleFi
|
|
|
5285
5739
|
|
|
5286
5740
|
// src/utils/build-order-snapshot/index.ts
|
|
5287
5741
|
function buildOrderSnapshot(props, builder, selection, services, settings = {}) {
|
|
5288
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5742
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
5289
5743
|
const mode = (_a = settings.mode) != null ? _a : "prod";
|
|
5290
5744
|
const hostDefaultQty = Number.isFinite((_b = settings.hostDefaultQuantity) != null ? _b : 1) ? settings.hostDefaultQuantity : 1;
|
|
5291
5745
|
const fbSettings = {
|
|
@@ -5298,14 +5752,31 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5298
5752
|
const builtAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5299
5753
|
const tagId = selection.activeTagId;
|
|
5300
5754
|
const selectedButtonKeys = (_d = selection.selectedKeys) != null ? _d : toSelectedOptionKeys(selection.optionSelectionsByFieldId);
|
|
5301
|
-
const visibleFieldIds = builder.visibleFields(tagId, selectedButtonKeys);
|
|
5302
5755
|
const tagById = new Map(((_e = props.filters) != null ? _e : []).map((t) => [t.id, t]));
|
|
5303
5756
|
const fieldById = new Map(((_f = props.fields) != null ? _f : []).map((f) => [f.id, f]));
|
|
5304
|
-
const
|
|
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;
|
|
5305
5775
|
const selectedOptionsByFieldId = getSelectedOptionsByFieldId(
|
|
5306
|
-
|
|
5776
|
+
effectiveSelection,
|
|
5307
5777
|
fieldById,
|
|
5308
|
-
mode
|
|
5778
|
+
mode,
|
|
5779
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId
|
|
5309
5780
|
);
|
|
5310
5781
|
const selectionFields = visibleFieldIds.map((fid) => fieldById.get(fid)).filter((f) => !!f).map((f) => {
|
|
5311
5782
|
var _a2;
|
|
@@ -5319,21 +5790,21 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5319
5790
|
const { formValues, selections } = buildInputs(
|
|
5320
5791
|
visibleFieldIds,
|
|
5321
5792
|
fieldById,
|
|
5322
|
-
|
|
5793
|
+
effectiveSelection,
|
|
5323
5794
|
selectedOptionsByFieldId
|
|
5324
5795
|
);
|
|
5325
5796
|
const qtyRes = resolveQuantity(
|
|
5326
5797
|
visibleFieldIds,
|
|
5327
5798
|
fieldById,
|
|
5328
5799
|
tagById,
|
|
5329
|
-
|
|
5800
|
+
effectiveSelection,
|
|
5330
5801
|
tagId,
|
|
5331
5802
|
hostDefaultQty
|
|
5332
5803
|
);
|
|
5333
5804
|
const { serviceMap, servicesList } = resolveServices(
|
|
5334
5805
|
tagId,
|
|
5335
5806
|
visibleFieldIds,
|
|
5336
|
-
|
|
5807
|
+
effectiveSelection,
|
|
5337
5808
|
tagById,
|
|
5338
5809
|
fieldById,
|
|
5339
5810
|
services
|
|
@@ -5355,7 +5826,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5355
5826
|
const utilities = collectUtilityLineItems(
|
|
5356
5827
|
visibleFieldIds,
|
|
5357
5828
|
fieldById,
|
|
5358
|
-
|
|
5829
|
+
effectiveSelection,
|
|
5359
5830
|
selectedOptionsByFieldId,
|
|
5360
5831
|
qtyRes.quantity
|
|
5361
5832
|
);
|
|
@@ -5365,7 +5836,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5365
5836
|
prunedFallbacks.original,
|
|
5366
5837
|
fieldById,
|
|
5367
5838
|
visibleFieldIds,
|
|
5368
|
-
|
|
5839
|
+
effectiveSelection
|
|
5369
5840
|
) : void 0;
|
|
5370
5841
|
const meta = {
|
|
5371
5842
|
schema_version: props.schema_version,
|
|
@@ -5378,7 +5849,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5378
5849
|
tagId,
|
|
5379
5850
|
visibleFieldIds,
|
|
5380
5851
|
fieldById,
|
|
5381
|
-
|
|
5852
|
+
effectiveSelection,
|
|
5382
5853
|
selectedOptionsByFieldId
|
|
5383
5854
|
),
|
|
5384
5855
|
policy: toSnapshotPolicy(fbSettings)
|
|
@@ -5390,7 +5861,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5390
5861
|
builtAt,
|
|
5391
5862
|
selection: {
|
|
5392
5863
|
tag: tagId,
|
|
5393
|
-
buttons:
|
|
5864
|
+
buttons: filteredSelectedButtonKeys,
|
|
5394
5865
|
fields: selectionFields
|
|
5395
5866
|
},
|
|
5396
5867
|
inputs: { form: formValues, selections },
|
|
@@ -5408,6 +5879,24 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5408
5879
|
meta
|
|
5409
5880
|
};
|
|
5410
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
|
+
}
|
|
5411
5900
|
|
|
5412
5901
|
// src/core/fallback-editor.ts
|
|
5413
5902
|
function createFallbackEditor(options = {}) {
|
|
@@ -5789,16 +6278,24 @@ function mapDiagReason(reason) {
|
|
|
5789
6278
|
createBuilder,
|
|
5790
6279
|
createFallbackEditor,
|
|
5791
6280
|
createNodeIndex,
|
|
6281
|
+
fieldOptionIdSet,
|
|
6282
|
+
fieldOptionIds,
|
|
6283
|
+
filterFieldOptionsById,
|
|
5792
6284
|
filterServicesForVisibleGroup,
|
|
6285
|
+
findFieldOption,
|
|
6286
|
+
findOptionOwnerField,
|
|
5793
6287
|
getAssignedServiceIds,
|
|
5794
6288
|
getEligibleFallbacks,
|
|
5795
6289
|
getFallbackRegistrationInfo,
|
|
5796
6290
|
isRefExcludedBySelectedKeys,
|
|
5797
6291
|
normalise,
|
|
5798
6292
|
normalizeFieldValidation,
|
|
6293
|
+
optionOwnerMap,
|
|
5799
6294
|
resolveServiceFallback,
|
|
5800
6295
|
validate,
|
|
5801
6296
|
validateAsync,
|
|
5802
|
-
validateRateCoherenceDeep
|
|
6297
|
+
validateRateCoherenceDeep,
|
|
6298
|
+
walkFieldOptions,
|
|
6299
|
+
walkOptions
|
|
5803
6300
|
});
|
|
5804
6301
|
//# sourceMappingURL=index.cjs.map
|