@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.js
CHANGED
|
@@ -13,6 +13,9 @@ function normalise(input, opts = {}) {
|
|
|
13
13
|
const excludes_for_buttons = toStringArrayMap(
|
|
14
14
|
obj.excludes_for_buttons
|
|
15
15
|
);
|
|
16
|
+
const option_effects_for_buttons = toOptionEffectMap(
|
|
17
|
+
obj.option_effects_for_buttons
|
|
18
|
+
);
|
|
16
19
|
const orderKinds = toStringMap(obj.orderKinds);
|
|
17
20
|
const notices = toNoticeArray(obj.notices);
|
|
18
21
|
let filters = rawFilters.map((t) => coerceTag(t, constraints));
|
|
@@ -28,6 +31,9 @@ function normalise(input, opts = {}) {
|
|
|
28
31
|
...isNonEmpty(orderKinds) && { orderKinds },
|
|
29
32
|
...isNonEmpty(includes_for_buttons) && { includes_for_buttons },
|
|
30
33
|
...isNonEmpty(excludes_for_buttons) && { excludes_for_buttons },
|
|
34
|
+
...isNonEmpty(option_effects_for_buttons) && {
|
|
35
|
+
option_effects_for_buttons
|
|
36
|
+
},
|
|
31
37
|
...fallbacks && (isNonEmpty(fallbacks.nodes) || isNonEmpty(fallbacks.global)) && {
|
|
32
38
|
fallbacks
|
|
33
39
|
},
|
|
@@ -182,6 +188,7 @@ function coerceOption(src, inheritRole) {
|
|
|
182
188
|
const value = typeof src.value === "string" || typeof src.value === "number" ? src.value : void 0;
|
|
183
189
|
const pricing_role = src.pricing_role === "utility" || src.pricing_role === "base" ? src.pricing_role : inheritRole;
|
|
184
190
|
const meta = src.meta && typeof src.meta === "object" ? src.meta : void 0;
|
|
191
|
+
const children = Array.isArray(src.children) ? src.children.map((child) => coerceOption(child, pricing_role)) : void 0;
|
|
185
192
|
const option = {
|
|
186
193
|
id: "",
|
|
187
194
|
label: "",
|
|
@@ -190,7 +197,8 @@ function coerceOption(src, inheritRole) {
|
|
|
190
197
|
...value !== void 0 && { value },
|
|
191
198
|
...service_id !== void 0 && { service_id },
|
|
192
199
|
pricing_role,
|
|
193
|
-
...meta && { meta }
|
|
200
|
+
...meta && { meta },
|
|
201
|
+
...children && children.length && { children }
|
|
194
202
|
};
|
|
195
203
|
return option;
|
|
196
204
|
}
|
|
@@ -255,6 +263,35 @@ function toStringArrayMap(src) {
|
|
|
255
263
|
}
|
|
256
264
|
return Object.keys(out).length ? out : void 0;
|
|
257
265
|
}
|
|
266
|
+
function toOptionEffectMap(src) {
|
|
267
|
+
var _a, _b;
|
|
268
|
+
if (!src || typeof src !== "object") return void 0;
|
|
269
|
+
const out = {};
|
|
270
|
+
for (const [triggerId, rawTargets] of Object.entries(src)) {
|
|
271
|
+
if (!triggerId || !rawTargets || typeof rawTargets !== "object") {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const targets = {};
|
|
275
|
+
for (const [fieldId, rawEffect] of Object.entries(rawTargets)) {
|
|
276
|
+
if (!fieldId || !rawEffect || typeof rawEffect !== "object") {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const effect = rawEffect;
|
|
280
|
+
const include = toStringArray(effect.include);
|
|
281
|
+
const exclude = toStringArray(effect.exclude);
|
|
282
|
+
const next = {
|
|
283
|
+
...effect.forceVisible === true ? { forceVisible: true } : {},
|
|
284
|
+
...include.length ? { include: dedupe(include) } : {},
|
|
285
|
+
...exclude.length ? { exclude: dedupe(exclude) } : {}
|
|
286
|
+
};
|
|
287
|
+
if (next.forceVisible === true || ((_a = next.include) == null ? void 0 : _a.length) || ((_b = next.exclude) == null ? void 0 : _b.length)) {
|
|
288
|
+
targets[fieldId] = next;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (Object.keys(targets).length) out[triggerId] = targets;
|
|
292
|
+
}
|
|
293
|
+
return Object.keys(out).length ? out : void 0;
|
|
294
|
+
}
|
|
258
295
|
function toStringArray(v) {
|
|
259
296
|
if (!Array.isArray(v)) return [];
|
|
260
297
|
return v.map((x) => String(x)).filter((s) => !!s && s.trim().length > 0);
|
|
@@ -329,6 +366,76 @@ function normalizeFieldValidation(input) {
|
|
|
329
366
|
return one ? [one] : void 0;
|
|
330
367
|
}
|
|
331
368
|
|
|
369
|
+
// src/core/options.ts
|
|
370
|
+
function walkFieldOptions(field) {
|
|
371
|
+
const out = [];
|
|
372
|
+
const visit = (options, depth, parentId) => {
|
|
373
|
+
for (const option of options != null ? options : []) {
|
|
374
|
+
out.push({
|
|
375
|
+
field,
|
|
376
|
+
fieldId: field.id,
|
|
377
|
+
option,
|
|
378
|
+
optionId: option.id,
|
|
379
|
+
depth,
|
|
380
|
+
parentId
|
|
381
|
+
});
|
|
382
|
+
visit(option.children, depth + 1, option.id);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
visit(field.options, 0);
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
function walkOptions(props) {
|
|
389
|
+
var _a;
|
|
390
|
+
return ((_a = props.fields) != null ? _a : []).flatMap((field) => walkFieldOptions(field));
|
|
391
|
+
}
|
|
392
|
+
function fieldOptionIds(field) {
|
|
393
|
+
return walkFieldOptions(field).map((visit) => visit.optionId);
|
|
394
|
+
}
|
|
395
|
+
function fieldOptionIdSet(field) {
|
|
396
|
+
return new Set(fieldOptionIds(field));
|
|
397
|
+
}
|
|
398
|
+
function findFieldOption(field, optionId) {
|
|
399
|
+
var _a;
|
|
400
|
+
if (!field) return void 0;
|
|
401
|
+
return (_a = walkFieldOptions(field).find((visit) => visit.optionId === optionId)) == null ? void 0 : _a.option;
|
|
402
|
+
}
|
|
403
|
+
function findOptionOwnerField(fields, optionId) {
|
|
404
|
+
for (const field of fields) {
|
|
405
|
+
if (findFieldOption(field, optionId)) return field;
|
|
406
|
+
}
|
|
407
|
+
return void 0;
|
|
408
|
+
}
|
|
409
|
+
function optionOwnerMap(fields) {
|
|
410
|
+
const out = /* @__PURE__ */ new Map();
|
|
411
|
+
for (const field of fields) {
|
|
412
|
+
for (const visit of walkFieldOptions(field)) {
|
|
413
|
+
if (!out.has(visit.optionId)) {
|
|
414
|
+
out.set(visit.optionId, {
|
|
415
|
+
fieldId: field.id,
|
|
416
|
+
option: visit.option
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return out;
|
|
422
|
+
}
|
|
423
|
+
function filterFieldOptionsById(options, allowed) {
|
|
424
|
+
if (!Array.isArray(options)) return void 0;
|
|
425
|
+
const out = [];
|
|
426
|
+
for (const option of options) {
|
|
427
|
+
const children = filterFieldOptionsById(option.children, allowed);
|
|
428
|
+
if (!allowed.has(option.id) && (!children || children.length === 0)) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
out.push({
|
|
432
|
+
...option,
|
|
433
|
+
...children ? { children } : {}
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return out;
|
|
437
|
+
}
|
|
438
|
+
|
|
332
439
|
// src/core/validate/shared.ts
|
|
333
440
|
function isFiniteNumber(v) {
|
|
334
441
|
return typeof v === "number" && Number.isFinite(v);
|
|
@@ -337,8 +444,9 @@ function isServiceIdRef(v) {
|
|
|
337
444
|
return typeof v === "string" && v.trim().length > 0 || typeof v === "number" && Number.isFinite(v);
|
|
338
445
|
}
|
|
339
446
|
function hasAnyServiceOption(f) {
|
|
340
|
-
|
|
341
|
-
|
|
447
|
+
return walkFieldOptions(f).some(
|
|
448
|
+
(visit) => isServiceIdRef(visit.option.service_id)
|
|
449
|
+
);
|
|
342
450
|
}
|
|
343
451
|
function getByPath(obj, path) {
|
|
344
452
|
if (!path) return void 0;
|
|
@@ -427,14 +535,14 @@ function withAffected(details, ids) {
|
|
|
427
535
|
|
|
428
536
|
// src/core/node-map.ts
|
|
429
537
|
function buildNodeMap(props) {
|
|
430
|
-
var _a, _b
|
|
538
|
+
var _a, _b;
|
|
431
539
|
const map = /* @__PURE__ */ new Map();
|
|
432
540
|
for (const t of (_a = props.filters) != null ? _a : []) {
|
|
433
541
|
if (!map.has(t.id)) map.set(t.id, { kind: "tag", id: t.id, node: t });
|
|
434
542
|
}
|
|
435
543
|
for (const f of (_b = props.fields) != null ? _b : []) {
|
|
436
544
|
if (!map.has(f.id)) map.set(f.id, { kind: "field", id: f.id, node: f });
|
|
437
|
-
for (const o of (
|
|
545
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
438
546
|
if (!map.has(o.id))
|
|
439
547
|
map.set(o.id, {
|
|
440
548
|
kind: "option",
|
|
@@ -447,12 +555,6 @@ function buildNodeMap(props) {
|
|
|
447
555
|
return map;
|
|
448
556
|
}
|
|
449
557
|
function resolveTrigger(trigger, nodeMap) {
|
|
450
|
-
const idx = trigger.indexOf("::");
|
|
451
|
-
if (idx !== -1) {
|
|
452
|
-
const fieldId = trigger.slice(0, idx);
|
|
453
|
-
const optionId = trigger.slice(idx + 2);
|
|
454
|
-
return { kind: "composite", triggerKey: trigger, fieldId, optionId };
|
|
455
|
-
}
|
|
456
558
|
const direct = nodeMap.get(trigger);
|
|
457
559
|
if (!direct) return void 0;
|
|
458
560
|
if (direct.kind === "option") {
|
|
@@ -504,11 +606,6 @@ function visibleFieldIdsUnder(props, tagId, opts = {}) {
|
|
|
504
606
|
const ownerDepthForTriggerKey = (triggerKey) => {
|
|
505
607
|
const t = resolveTrigger(triggerKey, nodeMap);
|
|
506
608
|
if (!t) return void 0;
|
|
507
|
-
if (t.kind === "composite") {
|
|
508
|
-
const f = fieldById.get(t.fieldId);
|
|
509
|
-
if (!f) return void 0;
|
|
510
|
-
return ownerDepthForField(f);
|
|
511
|
-
}
|
|
512
609
|
if (t.kind === "field") {
|
|
513
610
|
const f = fieldById.get(t.id);
|
|
514
611
|
if (!f || f.button !== true) return void 0;
|
|
@@ -591,6 +688,84 @@ function visibleFieldsUnder(props, tagId, opts = {}) {
|
|
|
591
688
|
const fieldById = new Map(((_a = props.fields) != null ? _a : []).map((f) => [f.id, f]));
|
|
592
689
|
return ids.map((id) => fieldById.get(id)).filter(Boolean);
|
|
593
690
|
}
|
|
691
|
+
function resolveVisibility(props, tagId, selectedKeys) {
|
|
692
|
+
var _a, _b, _c, _d;
|
|
693
|
+
const selected = new Set(selectedKeys != null ? selectedKeys : []);
|
|
694
|
+
const baseFieldIds = visibleFieldIdsUnder(props, tagId, { selectedKeys: selected });
|
|
695
|
+
const fieldById = new Map(((_a = props.fields) != null ? _a : []).map((field) => [field.id, field]));
|
|
696
|
+
const visible = new Set(baseFieldIds);
|
|
697
|
+
const forced = /* @__PURE__ */ new Set();
|
|
698
|
+
const optionsByFieldId = {};
|
|
699
|
+
const optionIdsByFieldId = /* @__PURE__ */ new Map();
|
|
700
|
+
const getOptionIds = (field) => {
|
|
701
|
+
let ids = optionIdsByFieldId.get(field.id);
|
|
702
|
+
if (!ids) {
|
|
703
|
+
ids = fieldOptionIds(field);
|
|
704
|
+
optionIdsByFieldId.set(field.id, ids);
|
|
705
|
+
}
|
|
706
|
+
return ids;
|
|
707
|
+
};
|
|
708
|
+
const ensureOptions = (field) => {
|
|
709
|
+
const ids = getOptionIds(field);
|
|
710
|
+
if (!ids.length) return void 0;
|
|
711
|
+
if (!optionsByFieldId[field.id]) optionsByFieldId[field.id] = [...ids];
|
|
712
|
+
return optionsByFieldId[field.id];
|
|
713
|
+
};
|
|
714
|
+
for (const fieldId of baseFieldIds) {
|
|
715
|
+
const field = fieldById.get(fieldId);
|
|
716
|
+
if (field) ensureOptions(field);
|
|
717
|
+
}
|
|
718
|
+
const effects = (_b = props.option_effects_for_buttons) != null ? _b : {};
|
|
719
|
+
for (const triggerId of selected) {
|
|
720
|
+
const targetRules = effects[triggerId];
|
|
721
|
+
if (!targetRules) continue;
|
|
722
|
+
for (const [targetFieldId, rule] of Object.entries(targetRules)) {
|
|
723
|
+
const field = fieldById.get(targetFieldId);
|
|
724
|
+
if (!field) continue;
|
|
725
|
+
const isVisible = visible.has(targetFieldId);
|
|
726
|
+
if (!isVisible && rule.forceVisible !== true) continue;
|
|
727
|
+
if (!isVisible && rule.forceVisible === true) {
|
|
728
|
+
visible.add(targetFieldId);
|
|
729
|
+
forced.add(targetFieldId);
|
|
730
|
+
}
|
|
731
|
+
const orderedOptionIds = getOptionIds(field);
|
|
732
|
+
if (!orderedOptionIds.length) continue;
|
|
733
|
+
const known = new Set(orderedOptionIds);
|
|
734
|
+
let allowed = (_c = optionsByFieldId[targetFieldId]) != null ? _c : [...orderedOptionIds];
|
|
735
|
+
if (Array.isArray(rule.include) && rule.include.length) {
|
|
736
|
+
const include = new Set(
|
|
737
|
+
rule.include.filter((optionId) => known.has(optionId))
|
|
738
|
+
);
|
|
739
|
+
allowed = orderedOptionIds.filter(
|
|
740
|
+
(optionId) => include.has(optionId) && allowed.includes(optionId)
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
if (Array.isArray(rule.exclude) && rule.exclude.length) {
|
|
744
|
+
const exclude = new Set(
|
|
745
|
+
rule.exclude.filter((optionId) => known.has(optionId))
|
|
746
|
+
);
|
|
747
|
+
allowed = allowed.filter((optionId) => !exclude.has(optionId));
|
|
748
|
+
}
|
|
749
|
+
optionsByFieldId[targetFieldId] = allowed;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const visibleFieldIds = baseFieldIds.filter((fieldId) => visible.has(fieldId));
|
|
753
|
+
const seen = new Set(visibleFieldIds);
|
|
754
|
+
for (const field of (_d = props.fields) != null ? _d : []) {
|
|
755
|
+
if (!visible.has(field.id) || seen.has(field.id)) continue;
|
|
756
|
+
seen.add(field.id);
|
|
757
|
+
visibleFieldIds.push(field.id);
|
|
758
|
+
ensureOptions(field);
|
|
759
|
+
}
|
|
760
|
+
for (const fieldId of Object.keys(optionsByFieldId)) {
|
|
761
|
+
if (!visible.has(fieldId)) delete optionsByFieldId[fieldId];
|
|
762
|
+
}
|
|
763
|
+
return {
|
|
764
|
+
fieldIds: visibleFieldIds,
|
|
765
|
+
optionsByFieldId,
|
|
766
|
+
forcedFieldIds: visibleFieldIds.filter((fieldId) => forced.has(fieldId))
|
|
767
|
+
};
|
|
768
|
+
}
|
|
594
769
|
|
|
595
770
|
// src/core/validate/steps/visibility.ts
|
|
596
771
|
function createFieldsVisibleUnder(v) {
|
|
@@ -608,7 +783,6 @@ function resolveRootTags(tags) {
|
|
|
608
783
|
return roots.length ? roots : tags.slice(0, 1);
|
|
609
784
|
}
|
|
610
785
|
function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKeys) {
|
|
611
|
-
var _a;
|
|
612
786
|
const visible = visibleFieldsUnder(v.props, tagId, {
|
|
613
787
|
selectedKeys
|
|
614
788
|
});
|
|
@@ -618,7 +792,7 @@ function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKey
|
|
|
618
792
|
const t = f.id;
|
|
619
793
|
if (effectfulKeys.has(t)) triggers.push(t);
|
|
620
794
|
}
|
|
621
|
-
for (const o of (
|
|
795
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
622
796
|
const t = o.id;
|
|
623
797
|
if (effectfulKeys.has(t)) triggers.push(t);
|
|
624
798
|
}
|
|
@@ -627,7 +801,7 @@ function collectSelectableTriggersInContext(v, tagId, selectedKeys, effectfulKey
|
|
|
627
801
|
return triggers;
|
|
628
802
|
}
|
|
629
803
|
function runVisibilityRulesOnce(v) {
|
|
630
|
-
var _a, _b, _c, _d
|
|
804
|
+
var _a, _b, _c, _d;
|
|
631
805
|
for (const t of v.tags) {
|
|
632
806
|
const visible = v.fieldsVisibleUnder(t.id);
|
|
633
807
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -677,9 +851,9 @@ function runVisibilityRulesOnce(v) {
|
|
|
677
851
|
let hasUtility = false;
|
|
678
852
|
const utilityOptionIds = [];
|
|
679
853
|
for (const f of visible) {
|
|
680
|
-
for (const o of (
|
|
854
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
681
855
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
682
|
-
const role = (
|
|
856
|
+
const role = (_d = (_c = o.pricing_role) != null ? _c : f.pricing_role) != null ? _d : "base";
|
|
683
857
|
if (role === "base") hasBase = true;
|
|
684
858
|
else if (role === "utility") {
|
|
685
859
|
hasUtility = true;
|
|
@@ -720,7 +894,7 @@ function dedupeErrorsInPlace(v, startIndex) {
|
|
|
720
894
|
v.errors.splice(startIndex, v.errors.length - startIndex, ...kept);
|
|
721
895
|
}
|
|
722
896
|
function validateVisibility(v, options = {}) {
|
|
723
|
-
var _a, _b, _c, _d, _e;
|
|
897
|
+
var _a, _b, _c, _d, _e, _f;
|
|
724
898
|
v.simulatedVisibilityContexts = [];
|
|
725
899
|
const simulate = options.simulate === true;
|
|
726
900
|
if (!simulate) {
|
|
@@ -745,10 +919,13 @@ function validateVisibility(v, options = {}) {
|
|
|
745
919
|
for (const key of Object.keys((_d = v.props.excludes_for_buttons) != null ? _d : {})) {
|
|
746
920
|
effectfulKeys.add(key);
|
|
747
921
|
}
|
|
922
|
+
for (const key of Object.keys((_e = v.props.option_effects_for_buttons) != null ? _e : {})) {
|
|
923
|
+
effectfulKeys.add(key);
|
|
924
|
+
}
|
|
748
925
|
}
|
|
749
926
|
const roots = resolveRootTags(v.tags);
|
|
750
927
|
const rootTags = options.simulateAllRoots ? roots : roots.slice(0, 1);
|
|
751
|
-
const originalSelected = new Set((
|
|
928
|
+
const originalSelected = new Set((_f = v.selectedKeys) != null ? _f : []);
|
|
752
929
|
const errorsStart = v.errors.length;
|
|
753
930
|
const visited = /* @__PURE__ */ new Set();
|
|
754
931
|
const seenContexts = /* @__PURE__ */ new Set();
|
|
@@ -889,7 +1066,7 @@ function validateStructure(v) {
|
|
|
889
1066
|
|
|
890
1067
|
// src/core/validate/steps/identity.ts
|
|
891
1068
|
function validateIdentity(v) {
|
|
892
|
-
var _a
|
|
1069
|
+
var _a;
|
|
893
1070
|
const tags = v.tags;
|
|
894
1071
|
const fields = v.fields;
|
|
895
1072
|
{
|
|
@@ -989,7 +1166,7 @@ function validateIdentity(v) {
|
|
|
989
1166
|
}
|
|
990
1167
|
}
|
|
991
1168
|
for (const f of fields) {
|
|
992
|
-
for (const o of (
|
|
1169
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
993
1170
|
if (!o.label || !o.label.trim()) {
|
|
994
1171
|
v.errors.push({
|
|
995
1172
|
code: "label_missing",
|
|
@@ -1004,25 +1181,11 @@ function validateIdentity(v) {
|
|
|
1004
1181
|
}
|
|
1005
1182
|
|
|
1006
1183
|
// src/core/validate/steps/option-maps.ts
|
|
1007
|
-
function parseFieldOptionKey(key) {
|
|
1008
|
-
const idx = key.indexOf("::");
|
|
1009
|
-
if (idx === -1) return null;
|
|
1010
|
-
const fieldId = key.slice(0, idx).trim();
|
|
1011
|
-
const optionId = key.slice(idx + 2).trim();
|
|
1012
|
-
if (!fieldId || !optionId) return null;
|
|
1013
|
-
return { fieldId, optionId };
|
|
1014
|
-
}
|
|
1015
|
-
function hasOption(v, fid, oid) {
|
|
1016
|
-
var _a;
|
|
1017
|
-
const f = v.fieldById.get(fid);
|
|
1018
|
-
if (!f) return false;
|
|
1019
|
-
return !!((_a = f.options) != null ? _a : []).find((o) => o.id === oid);
|
|
1020
|
-
}
|
|
1021
1184
|
function validateOptionMaps(v) {
|
|
1022
|
-
var _a, _b;
|
|
1185
|
+
var _a, _b, _c;
|
|
1023
1186
|
const incMap = (_a = v.props.includes_for_buttons) != null ? _a : {};
|
|
1024
1187
|
const excMap = (_b = v.props.excludes_for_buttons) != null ? _b : {};
|
|
1025
|
-
const badKeyMessage = (key) => `Invalid trigger-map key "${key}". Expected a known
|
|
1188
|
+
const badKeyMessage = (key) => `Invalid trigger-map key "${key}". Expected a known option id or button-field id.`;
|
|
1026
1189
|
const validateTriggerKey = (key) => {
|
|
1027
1190
|
const ref = v.nodeMap.get(key);
|
|
1028
1191
|
if (ref) {
|
|
@@ -1041,19 +1204,7 @@ function validateOptionMaps(v) {
|
|
|
1041
1204
|
}
|
|
1042
1205
|
return { ok: false, nodeId: ref.id, affected: [ref.id] };
|
|
1043
1206
|
}
|
|
1044
|
-
|
|
1045
|
-
if (!p) return { ok: false };
|
|
1046
|
-
if (!hasOption(v, p.fieldId, p.optionId))
|
|
1047
|
-
return {
|
|
1048
|
-
ok: false,
|
|
1049
|
-
nodeId: p.fieldId,
|
|
1050
|
-
affected: [p.fieldId, p.optionId]
|
|
1051
|
-
};
|
|
1052
|
-
return {
|
|
1053
|
-
ok: true,
|
|
1054
|
-
nodeId: p.fieldId,
|
|
1055
|
-
affected: [p.fieldId, p.optionId]
|
|
1056
|
-
};
|
|
1207
|
+
return { ok: false };
|
|
1057
1208
|
};
|
|
1058
1209
|
for (const k of Object.keys(incMap)) {
|
|
1059
1210
|
const r = validateTriggerKey(k);
|
|
@@ -1079,6 +1230,57 @@ function validateOptionMaps(v) {
|
|
|
1079
1230
|
});
|
|
1080
1231
|
}
|
|
1081
1232
|
}
|
|
1233
|
+
const effectMap = (_c = v.props.option_effects_for_buttons) != null ? _c : {};
|
|
1234
|
+
for (const [triggerKey, targets] of Object.entries(effectMap)) {
|
|
1235
|
+
const trigger = validateTriggerKey(triggerKey);
|
|
1236
|
+
if (!trigger.ok) {
|
|
1237
|
+
v.errors.push({
|
|
1238
|
+
code: "bad_option_effect_key",
|
|
1239
|
+
severity: "error",
|
|
1240
|
+
message: badKeyMessage(triggerKey),
|
|
1241
|
+
nodeId: trigger.nodeId,
|
|
1242
|
+
details: withAffected({ key: triggerKey }, trigger.affected)
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
for (const [targetFieldId, effect] of Object.entries(targets != null ? targets : {})) {
|
|
1246
|
+
const field = v.fieldById.get(targetFieldId);
|
|
1247
|
+
if (!field) {
|
|
1248
|
+
v.errors.push({
|
|
1249
|
+
code: "bad_option_effect_target",
|
|
1250
|
+
severity: "error",
|
|
1251
|
+
message: `Option effect trigger "${triggerKey}" targets unknown field "${targetFieldId}".`,
|
|
1252
|
+
details: withAffected(
|
|
1253
|
+
{ key: triggerKey, targetFieldId },
|
|
1254
|
+
trigger.affected
|
|
1255
|
+
)
|
|
1256
|
+
});
|
|
1257
|
+
continue;
|
|
1258
|
+
}
|
|
1259
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
1260
|
+
const checkTargetOptions = (kind, optionIds) => {
|
|
1261
|
+
for (const optionId of optionIds != null ? optionIds : []) {
|
|
1262
|
+
if (validOptionIds.has(optionId)) continue;
|
|
1263
|
+
v.errors.push({
|
|
1264
|
+
code: "bad_option_effect_option",
|
|
1265
|
+
severity: "error",
|
|
1266
|
+
message: `Option effect trigger "${triggerKey}" references unknown ${kind} option "${optionId}" for field "${targetFieldId}".`,
|
|
1267
|
+
nodeId: targetFieldId,
|
|
1268
|
+
details: withAffected(
|
|
1269
|
+
{
|
|
1270
|
+
key: triggerKey,
|
|
1271
|
+
targetFieldId,
|
|
1272
|
+
optionId,
|
|
1273
|
+
kind
|
|
1274
|
+
},
|
|
1275
|
+
[targetFieldId, optionId]
|
|
1276
|
+
)
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
checkTargetOptions("include", effect == null ? void 0 : effect.include);
|
|
1281
|
+
checkTargetOptions("exclude", effect == null ? void 0 : effect.exclude);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1082
1284
|
for (const k of Object.keys(incMap)) {
|
|
1083
1285
|
if (!(k in excMap)) continue;
|
|
1084
1286
|
const r = validateTriggerKey(k);
|
|
@@ -1092,27 +1294,231 @@ function validateOptionMaps(v) {
|
|
|
1092
1294
|
}
|
|
1093
1295
|
}
|
|
1094
1296
|
|
|
1095
|
-
// src/
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
const
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1297
|
+
// src/core/validate/steps/visibility-cycles.ts
|
|
1298
|
+
var MAX_VISIBILITY_CYCLE_DEPTH = 20;
|
|
1299
|
+
function validateVisibilityCycles(v) {
|
|
1300
|
+
const triggerById = buildTriggerIndex(v.fields);
|
|
1301
|
+
if (!triggerById.size) return;
|
|
1302
|
+
const fieldTriggers = buildFieldTriggerIndex(v.fields);
|
|
1303
|
+
const revealTargetsByTrigger = buildRevealIndex(v, triggerById);
|
|
1304
|
+
const reported = /* @__PURE__ */ new Set();
|
|
1305
|
+
for (const rootTriggerId of Array.from(triggerById.keys()).sort()) {
|
|
1306
|
+
const required = makeRequiredState(triggerById, [rootTriggerId]);
|
|
1307
|
+
walkFromTrigger({
|
|
1308
|
+
v,
|
|
1309
|
+
triggerById,
|
|
1310
|
+
fieldTriggers,
|
|
1311
|
+
revealTargetsByTrigger,
|
|
1312
|
+
rootTriggerId,
|
|
1313
|
+
currentTriggerId: rootTriggerId,
|
|
1314
|
+
required,
|
|
1315
|
+
path: [rootTriggerId],
|
|
1316
|
+
visited: /* @__PURE__ */ new Set(),
|
|
1317
|
+
reported,
|
|
1318
|
+
depth: 0
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
function buildTriggerIndex(fields) {
|
|
1323
|
+
const out = /* @__PURE__ */ new Map();
|
|
1324
|
+
const owners = optionOwnerMap(fields);
|
|
1325
|
+
for (const field of fields) {
|
|
1326
|
+
if (field.button === true) {
|
|
1327
|
+
out.set(field.id, {
|
|
1328
|
+
kind: "field",
|
|
1329
|
+
id: field.id,
|
|
1330
|
+
ownerFieldId: field.id
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
for (const [optionId, owner] of owners) {
|
|
1335
|
+
out.set(optionId, {
|
|
1336
|
+
kind: "option",
|
|
1337
|
+
id: optionId,
|
|
1338
|
+
ownerFieldId: owner.fieldId
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
return out;
|
|
1342
|
+
}
|
|
1343
|
+
function buildFieldTriggerIndex(fields) {
|
|
1344
|
+
const out = /* @__PURE__ */ new Map();
|
|
1345
|
+
for (const field of fields) {
|
|
1346
|
+
const triggers = [];
|
|
1347
|
+
if (field.button === true) triggers.push(field.id);
|
|
1348
|
+
for (const visit of walkFieldOptions(field)) {
|
|
1349
|
+
triggers.push(visit.optionId);
|
|
1350
|
+
}
|
|
1351
|
+
out.set(field.id, triggers);
|
|
1352
|
+
}
|
|
1353
|
+
return out;
|
|
1354
|
+
}
|
|
1355
|
+
function buildRevealIndex(v, triggerById) {
|
|
1356
|
+
var _a, _b;
|
|
1357
|
+
const out = /* @__PURE__ */ new Map();
|
|
1358
|
+
const addReveal = (triggerId, targetFieldId) => {
|
|
1359
|
+
var _a2;
|
|
1360
|
+
if (!triggerById.has(triggerId)) return;
|
|
1361
|
+
if (!v.fieldById.has(targetFieldId)) return;
|
|
1362
|
+
const set = (_a2 = out.get(triggerId)) != null ? _a2 : /* @__PURE__ */ new Set();
|
|
1363
|
+
set.add(targetFieldId);
|
|
1364
|
+
out.set(triggerId, set);
|
|
1365
|
+
};
|
|
1366
|
+
for (const [triggerId, targetIds] of Object.entries(
|
|
1367
|
+
(_a = v.props.includes_for_buttons) != null ? _a : {}
|
|
1368
|
+
)) {
|
|
1369
|
+
for (const targetId of targetIds != null ? targetIds : []) addReveal(triggerId, targetId);
|
|
1370
|
+
}
|
|
1371
|
+
for (const [triggerId, targets] of Object.entries(
|
|
1372
|
+
(_b = v.props.option_effects_for_buttons) != null ? _b : {}
|
|
1373
|
+
)) {
|
|
1374
|
+
for (const [targetFieldId, effect] of Object.entries(targets != null ? targets : {})) {
|
|
1375
|
+
if ((effect == null ? void 0 : effect.forceVisible) === true)
|
|
1376
|
+
addReveal(triggerId, targetFieldId);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return new Map(
|
|
1380
|
+
Array.from(out.entries()).map(([triggerId, fieldIds]) => [
|
|
1381
|
+
triggerId,
|
|
1382
|
+
Array.from(fieldIds).sort()
|
|
1383
|
+
])
|
|
1384
|
+
);
|
|
1385
|
+
}
|
|
1386
|
+
function walkFromTrigger(args) {
|
|
1387
|
+
var _a, _b, _c;
|
|
1388
|
+
if (args.depth >= MAX_VISIBILITY_CYCLE_DEPTH) return;
|
|
1389
|
+
const visitedKey = `${args.rootTriggerId}::${args.currentTriggerId}::${args.path.join(">")}`;
|
|
1390
|
+
if (args.visited.has(visitedKey)) return;
|
|
1391
|
+
args.visited.add(visitedKey);
|
|
1392
|
+
const revealedFieldIds = (_a = args.revealTargetsByTrigger.get(args.currentTriggerId)) != null ? _a : [];
|
|
1393
|
+
for (const revealedFieldId of revealedFieldIds) {
|
|
1394
|
+
const reachableTriggers = (_c = (_b = args.fieldTriggers.get(revealedFieldId)) == null ? void 0 : _b.slice().sort()) != null ? _c : [];
|
|
1395
|
+
for (const reachableTriggerId of reachableTriggers) {
|
|
1396
|
+
const invalidation = invalidatesRequiredPath(
|
|
1397
|
+
args.v,
|
|
1398
|
+
args.triggerById,
|
|
1399
|
+
reachableTriggerId,
|
|
1400
|
+
args.required
|
|
1401
|
+
);
|
|
1402
|
+
if (invalidation) {
|
|
1403
|
+
emitCycleError({
|
|
1404
|
+
v: args.v,
|
|
1405
|
+
rootTriggerId: args.rootTriggerId,
|
|
1406
|
+
revealedFieldId,
|
|
1407
|
+
conflictingTriggerId: reachableTriggerId,
|
|
1408
|
+
invalidatedId: invalidation.invalidatedId,
|
|
1409
|
+
path: [...args.path, reachableTriggerId],
|
|
1410
|
+
reported: args.reported
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
if (args.path.includes(reachableTriggerId)) continue;
|
|
1414
|
+
walkFromTrigger({
|
|
1415
|
+
...args,
|
|
1416
|
+
currentTriggerId: reachableTriggerId,
|
|
1417
|
+
required: addRequiredTrigger(
|
|
1418
|
+
args.triggerById,
|
|
1419
|
+
args.required,
|
|
1420
|
+
reachableTriggerId
|
|
1421
|
+
),
|
|
1422
|
+
path: [...args.path, reachableTriggerId],
|
|
1423
|
+
depth: args.depth + 1
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
function makeRequiredState(triggerById, triggerIds) {
|
|
1429
|
+
let required = {
|
|
1430
|
+
triggers: /* @__PURE__ */ new Set(),
|
|
1431
|
+
ownerFields: /* @__PURE__ */ new Set()
|
|
1432
|
+
};
|
|
1433
|
+
for (const triggerId of triggerIds) {
|
|
1434
|
+
required = addRequiredTrigger(triggerById, required, triggerId);
|
|
1435
|
+
}
|
|
1436
|
+
return required;
|
|
1437
|
+
}
|
|
1438
|
+
function addRequiredTrigger(triggerById, current, triggerId) {
|
|
1439
|
+
const next = {
|
|
1440
|
+
triggers: new Set(current.triggers),
|
|
1441
|
+
ownerFields: new Set(current.ownerFields)
|
|
1442
|
+
};
|
|
1443
|
+
const trigger = triggerById.get(triggerId);
|
|
1444
|
+
if (!trigger) return next;
|
|
1445
|
+
next.triggers.add(triggerId);
|
|
1446
|
+
next.ownerFields.add(trigger.ownerFieldId);
|
|
1447
|
+
return next;
|
|
1448
|
+
}
|
|
1449
|
+
function invalidatesRequiredPath(v, triggerById, conflictingTriggerId, required) {
|
|
1450
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1451
|
+
for (const targetId of (_b = (_a = v.props.excludes_for_buttons) == null ? void 0 : _a[conflictingTriggerId]) != null ? _b : []) {
|
|
1452
|
+
if (required.ownerFields.has(targetId)) {
|
|
1453
|
+
return { invalidatedId: targetId };
|
|
1454
|
+
}
|
|
1455
|
+
const targetTrigger = triggerById.get(targetId);
|
|
1456
|
+
if ((targetTrigger == null ? void 0 : targetTrigger.kind) === "option" && required.triggers.has(targetId)) {
|
|
1457
|
+
return { invalidatedId: targetId };
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
const effects = (_d = (_c = v.props.option_effects_for_buttons) == null ? void 0 : _c[conflictingTriggerId]) != null ? _d : {};
|
|
1461
|
+
for (const [targetFieldId, effect] of Object.entries(effects)) {
|
|
1462
|
+
if (!v.fieldById.has(targetFieldId)) continue;
|
|
1463
|
+
if ((_e = effect == null ? void 0 : effect.exclude) == null ? void 0 : _e.length) {
|
|
1464
|
+
const excluded = new Set(effect.exclude);
|
|
1465
|
+
for (const requiredTriggerId of required.triggers) {
|
|
1466
|
+
const requiredTrigger = triggerById.get(requiredTriggerId);
|
|
1467
|
+
if ((requiredTrigger == null ? void 0 : requiredTrigger.kind) !== "option") continue;
|
|
1468
|
+
if (requiredTrigger.ownerFieldId !== targetFieldId) continue;
|
|
1469
|
+
if (excluded.has(requiredTriggerId)) {
|
|
1470
|
+
return { invalidatedId: requiredTriggerId };
|
|
1471
|
+
}
|
|
1106
1472
|
}
|
|
1107
1473
|
}
|
|
1108
|
-
if (
|
|
1109
|
-
const
|
|
1110
|
-
|
|
1111
|
-
|
|
1474
|
+
if ((_f = effect == null ? void 0 : effect.include) == null ? void 0 : _f.length) {
|
|
1475
|
+
const included = new Set(effect.include);
|
|
1476
|
+
for (const requiredTriggerId of required.triggers) {
|
|
1477
|
+
const requiredTrigger = triggerById.get(requiredTriggerId);
|
|
1478
|
+
if ((requiredTrigger == null ? void 0 : requiredTrigger.kind) !== "option") continue;
|
|
1479
|
+
if (requiredTrigger.ownerFieldId !== targetFieldId) continue;
|
|
1480
|
+
if (!included.has(requiredTriggerId)) {
|
|
1481
|
+
return { invalidatedId: requiredTriggerId };
|
|
1482
|
+
}
|
|
1112
1483
|
}
|
|
1113
1484
|
}
|
|
1114
|
-
return void 0;
|
|
1115
1485
|
}
|
|
1486
|
+
return void 0;
|
|
1487
|
+
}
|
|
1488
|
+
function emitCycleError(args) {
|
|
1489
|
+
const key = [
|
|
1490
|
+
args.rootTriggerId,
|
|
1491
|
+
args.conflictingTriggerId,
|
|
1492
|
+
args.invalidatedId,
|
|
1493
|
+
args.path.join(">")
|
|
1494
|
+
].join("::");
|
|
1495
|
+
if (args.reported.has(key)) return;
|
|
1496
|
+
args.reported.add(key);
|
|
1497
|
+
args.v.errors.push({
|
|
1498
|
+
code: "visibility_dependency_cycle",
|
|
1499
|
+
severity: "error",
|
|
1500
|
+
message: `Visibility dependency cycle: trigger "${args.rootTriggerId}" reveals "${args.revealedFieldId}", but reachable trigger "${args.conflictingTriggerId}" can hide or remove "${args.invalidatedId}".`,
|
|
1501
|
+
nodeId: args.conflictingTriggerId,
|
|
1502
|
+
details: withAffected(
|
|
1503
|
+
{
|
|
1504
|
+
rootTriggerId: args.rootTriggerId,
|
|
1505
|
+
conflictingTriggerId: args.conflictingTriggerId,
|
|
1506
|
+
invalidatedId: args.invalidatedId,
|
|
1507
|
+
path: args.path
|
|
1508
|
+
},
|
|
1509
|
+
[
|
|
1510
|
+
args.rootTriggerId,
|
|
1511
|
+
args.revealedFieldId,
|
|
1512
|
+
args.conflictingTriggerId,
|
|
1513
|
+
args.invalidatedId
|
|
1514
|
+
]
|
|
1515
|
+
)
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// src/utils/order-kind.ts
|
|
1520
|
+
function normalizeSelectedTriggerKey(key, nodeMap) {
|
|
1521
|
+
if (!key) return void 0;
|
|
1116
1522
|
const ref = nodeMap.get(key);
|
|
1117
1523
|
if (!ref) return void 0;
|
|
1118
1524
|
if (ref.kind !== "field" && ref.kind !== "option") return void 0;
|
|
@@ -1271,8 +1677,7 @@ function validateUtilityMarkers(v) {
|
|
|
1271
1677
|
"percent"
|
|
1272
1678
|
]);
|
|
1273
1679
|
for (const f of v.fields) {
|
|
1274
|
-
const
|
|
1275
|
-
for (const o of optsArr) {
|
|
1680
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
1276
1681
|
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
1277
1682
|
const hasService = isServiceIdRef(o.service_id);
|
|
1278
1683
|
const util = (_c = o.meta) == null ? void 0 : _c.utility;
|
|
@@ -1508,13 +1913,13 @@ function normalizeServiceRef(value) {
|
|
|
1508
1913
|
|
|
1509
1914
|
// src/core/validate/steps/rates.ts
|
|
1510
1915
|
function validateRates(v) {
|
|
1511
|
-
var _a, _b
|
|
1916
|
+
var _a, _b;
|
|
1512
1917
|
const ratePolicy = normalizeRatePolicy(v.options.ratePolicy);
|
|
1513
1918
|
for (const f of v.fields) {
|
|
1514
1919
|
if (!isMultiField(f)) continue;
|
|
1515
1920
|
const baseRates = [];
|
|
1516
|
-
for (const o of (
|
|
1517
|
-
const role = (
|
|
1921
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
1922
|
+
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
1518
1923
|
if (role !== "base") continue;
|
|
1519
1924
|
const sid = o.service_id;
|
|
1520
1925
|
if (!isServiceIdRef(sid)) continue;
|
|
@@ -1716,8 +2121,9 @@ function collectAnchors(fields) {
|
|
|
1716
2121
|
const anchors = [];
|
|
1717
2122
|
for (const field of fields) {
|
|
1718
2123
|
if (!isButton(field)) continue;
|
|
1719
|
-
|
|
1720
|
-
|
|
2124
|
+
const optionVisits = walkFieldOptions(field);
|
|
2125
|
+
if (optionVisits.length > 0) {
|
|
2126
|
+
for (const { option } of optionVisits) {
|
|
1721
2127
|
anchors.push({
|
|
1722
2128
|
kind: "option",
|
|
1723
2129
|
id: option.id,
|
|
@@ -1766,8 +2172,9 @@ function collectFieldReferences(field, services) {
|
|
|
1766
2172
|
function collectBaseMembers(field, services) {
|
|
1767
2173
|
var _a, _b, _c;
|
|
1768
2174
|
const members = [];
|
|
1769
|
-
|
|
1770
|
-
|
|
2175
|
+
const optionVisits = walkFieldOptions(field);
|
|
2176
|
+
if (optionVisits.length > 0) {
|
|
2177
|
+
for (const { option } of optionVisits) {
|
|
1771
2178
|
const role2 = normalizeRole((_a = option.pricing_role) != null ? _a : field.pricing_role, "base");
|
|
1772
2179
|
if (role2 !== "base") continue;
|
|
1773
2180
|
if (option.service_id === void 0 || option.service_id === null) {
|
|
@@ -2182,7 +2589,7 @@ function effectiveConstraints(v, tagId) {
|
|
|
2182
2589
|
return out;
|
|
2183
2590
|
}
|
|
2184
2591
|
function validateConstraints(v) {
|
|
2185
|
-
var _a
|
|
2592
|
+
var _a;
|
|
2186
2593
|
for (const t of v.tags) {
|
|
2187
2594
|
const eff = effectiveConstraints(v, t.id);
|
|
2188
2595
|
const hasAnyRequired = Object.values(eff).some(
|
|
@@ -2191,7 +2598,7 @@ function validateConstraints(v) {
|
|
|
2191
2598
|
if (!hasAnyRequired) continue;
|
|
2192
2599
|
const visible = v.fieldsVisibleUnder(t.id);
|
|
2193
2600
|
for (const f of visible) {
|
|
2194
|
-
for (const o of (
|
|
2601
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2195
2602
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
2196
2603
|
const svc = getServiceCapability(v.serviceMap, o.service_id);
|
|
2197
2604
|
if (!svc || typeof svc !== "object") continue;
|
|
@@ -2245,7 +2652,7 @@ function validateConstraints(v) {
|
|
|
2245
2652
|
if (!row) continue;
|
|
2246
2653
|
const from = row.from === true;
|
|
2247
2654
|
const to = row.to === true;
|
|
2248
|
-
const origin = String((
|
|
2655
|
+
const origin = String((_a = row.origin) != null ? _a : "");
|
|
2249
2656
|
v.errors.push({
|
|
2250
2657
|
code: "constraint_overridden",
|
|
2251
2658
|
severity: "warning",
|
|
@@ -2279,14 +2686,14 @@ function validateCustomFields(v) {
|
|
|
2279
2686
|
|
|
2280
2687
|
// src/core/validate/steps/global-utility-guard.ts
|
|
2281
2688
|
function validateGlobalUtilityGuard(v) {
|
|
2282
|
-
var _a, _b
|
|
2689
|
+
var _a, _b;
|
|
2283
2690
|
if (!v.options.globalUtilityGuard) return;
|
|
2284
2691
|
let hasUtility = false;
|
|
2285
2692
|
let hasBase = false;
|
|
2286
2693
|
for (const f of v.fields) {
|
|
2287
|
-
for (const o of (
|
|
2694
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2288
2695
|
if (!isServiceIdRef(o.service_id)) continue;
|
|
2289
|
-
const role = (
|
|
2696
|
+
const role = (_b = (_a = o.pricing_role) != null ? _a : f.pricing_role) != null ? _b : "base";
|
|
2290
2697
|
if (role === "base") hasBase = true;
|
|
2291
2698
|
else if (role === "utility") hasUtility = true;
|
|
2292
2699
|
if (hasUtility && hasBase) break;
|
|
@@ -2488,7 +2895,7 @@ function applyFilterAllowLists(tagId, fieldId, filter) {
|
|
|
2488
2895
|
return true;
|
|
2489
2896
|
}
|
|
2490
2897
|
function collectServiceItems(args) {
|
|
2491
|
-
var _a, _b, _c, _d
|
|
2898
|
+
var _a, _b, _c, _d;
|
|
2492
2899
|
const filter = args.filter;
|
|
2493
2900
|
const roleFilter = (_a = filter == null ? void 0 : filter.role) != null ? _a : "both";
|
|
2494
2901
|
const where = filter == null ? void 0 : filter.where;
|
|
@@ -2538,7 +2945,7 @@ function collectServiceItems(args) {
|
|
|
2538
2945
|
affectedIds: [`field:${f.id}`, `service:${String(fSid)}`]
|
|
2539
2946
|
});
|
|
2540
2947
|
}
|
|
2541
|
-
for (const o of (
|
|
2948
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2542
2949
|
const oSid = o.service_id;
|
|
2543
2950
|
if (!isServiceIdRef2(oSid)) continue;
|
|
2544
2951
|
const role = fieldRoleOf(f, o);
|
|
@@ -2623,7 +3030,7 @@ function collectServiceItems(args) {
|
|
|
2623
3030
|
}
|
|
2624
3031
|
} else if (includeGroupFallbacks) {
|
|
2625
3032
|
const allowPrimaries = new Set(
|
|
2626
|
-
((
|
|
3033
|
+
((_d = args.visiblePrimaries) != null ? _d : []).map((x) => String(x))
|
|
2627
3034
|
);
|
|
2628
3035
|
for (const primaryKey of allowPrimaries) {
|
|
2629
3036
|
const list = globalFb[primaryKey];
|
|
@@ -2704,17 +3111,15 @@ function affectedFromItems(items) {
|
|
|
2704
3111
|
return uniq(ids);
|
|
2705
3112
|
}
|
|
2706
3113
|
function visibleGroupNodeIds(tag, fields) {
|
|
2707
|
-
var _a;
|
|
2708
3114
|
const ids = [tag.id];
|
|
2709
3115
|
for (const f of fields) {
|
|
2710
|
-
for (const o of (
|
|
3116
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2711
3117
|
ids.push(o.id);
|
|
2712
3118
|
}
|
|
2713
3119
|
}
|
|
2714
3120
|
return uniq(ids);
|
|
2715
3121
|
}
|
|
2716
3122
|
function visibleGroupPrimaries(tag, fields) {
|
|
2717
|
-
var _a;
|
|
2718
3123
|
const prim = [];
|
|
2719
3124
|
const tagSid = tag.service_id;
|
|
2720
3125
|
if (typeof tagSid === "string" || typeof tagSid === "number" && Number.isFinite(tagSid)) {
|
|
@@ -2725,7 +3130,7 @@ function visibleGroupPrimaries(tag, fields) {
|
|
|
2725
3130
|
if (typeof fsid === "string" || typeof fsid === "number" && Number.isFinite(fsid)) {
|
|
2726
3131
|
prim.push(fsid);
|
|
2727
3132
|
}
|
|
2728
|
-
for (const o of (
|
|
3133
|
+
for (const { option: o } of walkFieldOptions(f)) {
|
|
2729
3134
|
const osid = o.service_id;
|
|
2730
3135
|
if (typeof osid === "string" || typeof osid === "number" && Number.isFinite(osid)) {
|
|
2731
3136
|
prim.push(osid);
|
|
@@ -2949,6 +3354,7 @@ function validate(props, ctx = {}) {
|
|
|
2949
3354
|
validateStructure(v);
|
|
2950
3355
|
validateIdentity(v);
|
|
2951
3356
|
validateOptionMaps(v);
|
|
3357
|
+
validateVisibilityCycles(v);
|
|
2952
3358
|
validateOrderKinds(v);
|
|
2953
3359
|
v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
|
|
2954
3360
|
const visSim = readVisibilitySimOpts(options);
|
|
@@ -3093,14 +3499,14 @@ var BuilderImpl = class {
|
|
|
3093
3499
|
const showOptions = showSet.has(f.id);
|
|
3094
3500
|
if (!showOptions) continue;
|
|
3095
3501
|
if (!Array.isArray(f.options)) continue;
|
|
3096
|
-
for (const o of f
|
|
3502
|
+
for (const { option: o, parentId } of walkFieldOptions(f)) {
|
|
3097
3503
|
nodes.push({
|
|
3098
3504
|
id: o.id,
|
|
3099
3505
|
kind: "option",
|
|
3100
3506
|
label: o.label
|
|
3101
3507
|
});
|
|
3102
3508
|
const e = {
|
|
3103
|
-
from: f.id,
|
|
3509
|
+
from: parentId != null ? parentId : f.id,
|
|
3104
3510
|
to: o.id,
|
|
3105
3511
|
kind: "option",
|
|
3106
3512
|
meta: { ownerField: f.id }
|
|
@@ -3147,7 +3553,7 @@ var BuilderImpl = class {
|
|
|
3147
3553
|
return { nodes, edges };
|
|
3148
3554
|
}
|
|
3149
3555
|
cleanedProps() {
|
|
3150
|
-
var _a, _b, _c, _d, _e;
|
|
3556
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3151
3557
|
const fieldIds = new Set(this.props.fields.map((f) => f.id));
|
|
3152
3558
|
const optionIds = /* @__PURE__ */ new Set();
|
|
3153
3559
|
this.optionOwnerById.forEach((_v, oid) => optionIds.add(oid));
|
|
@@ -3159,6 +3565,7 @@ var BuilderImpl = class {
|
|
|
3159
3565
|
}
|
|
3160
3566
|
const incMap = (_c = this.props.includes_for_buttons) != null ? _c : {};
|
|
3161
3567
|
const excMap = (_d = this.props.excludes_for_buttons) != null ? _d : {};
|
|
3568
|
+
const effectMap = (_e = this.props.option_effects_for_buttons) != null ? _e : {};
|
|
3162
3569
|
const includedByButtons = /* @__PURE__ */ new Set();
|
|
3163
3570
|
const referencedKeys = /* @__PURE__ */ new Set();
|
|
3164
3571
|
const referencedOwnerFields = /* @__PURE__ */ new Set();
|
|
@@ -3178,6 +3585,14 @@ var BuilderImpl = class {
|
|
|
3178
3585
|
void fid;
|
|
3179
3586
|
}
|
|
3180
3587
|
}
|
|
3588
|
+
for (const [key, targets] of Object.entries(effectMap)) {
|
|
3589
|
+
referencedKeys.add(key);
|
|
3590
|
+
const owner = this.optionOwnerById.get(key);
|
|
3591
|
+
if (owner) referencedOwnerFields.add(owner.fieldId);
|
|
3592
|
+
for (const [fid, effect] of Object.entries(targets != null ? targets : {})) {
|
|
3593
|
+
if ((effect == null ? void 0 : effect.forceVisible) === true) includedByButtons.add(fid);
|
|
3594
|
+
}
|
|
3595
|
+
}
|
|
3181
3596
|
const boundIds = /* @__PURE__ */ new Set();
|
|
3182
3597
|
for (const f of this.props.fields) {
|
|
3183
3598
|
const b = f.bind_id;
|
|
@@ -3195,6 +3610,7 @@ var BuilderImpl = class {
|
|
|
3195
3610
|
return bound || included || referenced || !excluded;
|
|
3196
3611
|
});
|
|
3197
3612
|
const allowedTargets = new Set(fields.map((f) => f.id));
|
|
3613
|
+
const allowedFieldById = new Map(fields.map((f) => [f.id, f]));
|
|
3198
3614
|
const pruneButtons = (src) => {
|
|
3199
3615
|
if (!src) return void 0;
|
|
3200
3616
|
const out2 = {};
|
|
@@ -3214,13 +3630,52 @@ var BuilderImpl = class {
|
|
|
3214
3630
|
const excludes_for_buttons = pruneButtons(
|
|
3215
3631
|
this.props.excludes_for_buttons
|
|
3216
3632
|
);
|
|
3633
|
+
const pruneOptionEffects = (src) => {
|
|
3634
|
+
var _a2, _b2, _c2, _d2;
|
|
3635
|
+
if (!src) return void 0;
|
|
3636
|
+
const out2 = {};
|
|
3637
|
+
for (const [key, targets] of Object.entries(src)) {
|
|
3638
|
+
const keyIsValid = optionIds.has(key) || fieldIds.has(key);
|
|
3639
|
+
if (!keyIsValid) continue;
|
|
3640
|
+
const cleanedTargets = {};
|
|
3641
|
+
for (const [targetFieldId, effect] of Object.entries(
|
|
3642
|
+
targets != null ? targets : {}
|
|
3643
|
+
)) {
|
|
3644
|
+
const field = allowedFieldById.get(targetFieldId);
|
|
3645
|
+
if (!field || !effect) continue;
|
|
3646
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
3647
|
+
const include = Array.from(
|
|
3648
|
+
new Set((_a2 = effect.include) != null ? _a2 : [])
|
|
3649
|
+
).filter((optionId) => validOptionIds.has(optionId));
|
|
3650
|
+
const exclude = Array.from(
|
|
3651
|
+
new Set((_b2 = effect.exclude) != null ? _b2 : [])
|
|
3652
|
+
).filter((optionId) => validOptionIds.has(optionId));
|
|
3653
|
+
const next = {
|
|
3654
|
+
...effect.forceVisible === true ? { forceVisible: true } : {},
|
|
3655
|
+
...include.length ? { include } : {},
|
|
3656
|
+
...exclude.length ? { exclude } : {}
|
|
3657
|
+
};
|
|
3658
|
+
if (next.forceVisible === true || ((_c2 = next.include) == null ? void 0 : _c2.length) || ((_d2 = next.exclude) == null ? void 0 : _d2.length)) {
|
|
3659
|
+
cleanedTargets[targetFieldId] = next;
|
|
3660
|
+
}
|
|
3661
|
+
}
|
|
3662
|
+
if (Object.keys(cleanedTargets).length) {
|
|
3663
|
+
out2[key] = cleanedTargets;
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
return Object.keys(out2).length ? out2 : void 0;
|
|
3667
|
+
};
|
|
3668
|
+
const option_effects_for_buttons = pruneOptionEffects(
|
|
3669
|
+
this.props.option_effects_for_buttons
|
|
3670
|
+
);
|
|
3217
3671
|
const out = {
|
|
3218
3672
|
filters: this.props.filters.slice(),
|
|
3219
3673
|
fields,
|
|
3220
3674
|
...this.props.orderKinds ? { orderKinds: this.props.orderKinds } : {},
|
|
3221
3675
|
...includes_for_buttons && { includes_for_buttons },
|
|
3222
3676
|
...excludes_for_buttons && { excludes_for_buttons },
|
|
3223
|
-
|
|
3677
|
+
...option_effects_for_buttons && { option_effects_for_buttons },
|
|
3678
|
+
schema_version: (_f = this.props.schema_version) != null ? _f : "1.0",
|
|
3224
3679
|
// keep fallbacks & other maps as-is
|
|
3225
3680
|
...this.props.fallbacks ? { fallbacks: this.props.fallbacks } : {}
|
|
3226
3681
|
};
|
|
@@ -3233,12 +3688,15 @@ var BuilderImpl = class {
|
|
|
3233
3688
|
return cloneDeep2(this.options);
|
|
3234
3689
|
}
|
|
3235
3690
|
visibleFields(tagId, selectedKeys) {
|
|
3691
|
+
return this.resolveVisibility(tagId, selectedKeys).fieldIds;
|
|
3692
|
+
}
|
|
3693
|
+
resolveVisibility(tagId, selectedKeys) {
|
|
3236
3694
|
var _a;
|
|
3237
|
-
return
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
)
|
|
3241
|
-
|
|
3695
|
+
return resolveVisibility(
|
|
3696
|
+
this.props,
|
|
3697
|
+
tagId,
|
|
3698
|
+
(_a = selectedKeys != null ? selectedKeys : this.options.selectedOptionKeys) != null ? _a : []
|
|
3699
|
+
);
|
|
3242
3700
|
}
|
|
3243
3701
|
getNodeMap() {
|
|
3244
3702
|
if (!this._nodemap) this._nodemap = buildNodeMap(this.getProps());
|
|
@@ -3253,9 +3711,8 @@ var BuilderImpl = class {
|
|
|
3253
3711
|
for (const t of this.props.filters) this.tagById.set(t.id, t);
|
|
3254
3712
|
for (const f of this.props.fields) {
|
|
3255
3713
|
this.fieldById.set(f.id, f);
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
this.optionOwnerById.set(o.id, { fieldId: f.id });
|
|
3714
|
+
for (const [optionId, owner] of optionOwnerMap([f])) {
|
|
3715
|
+
this.optionOwnerById.set(optionId, { fieldId: owner.fieldId });
|
|
3259
3716
|
}
|
|
3260
3717
|
}
|
|
3261
3718
|
}
|
|
@@ -4733,20 +5190,20 @@ function isFiniteNumber2(v) {
|
|
|
4733
5190
|
|
|
4734
5191
|
// src/utils/build-order-snapshot/selection.ts
|
|
4735
5192
|
function isOptionBased(f) {
|
|
4736
|
-
const hasOptions =
|
|
5193
|
+
const hasOptions = fieldOptionIdSet(f).size > 0;
|
|
4737
5194
|
return hasOptions || isMultiField(f);
|
|
4738
5195
|
}
|
|
4739
5196
|
function toSelectedOptionKeys(byField) {
|
|
4740
5197
|
const keys = [];
|
|
4741
|
-
for (const
|
|
5198
|
+
for (const optionIds of Object.values(byField != null ? byField : {})) {
|
|
4742
5199
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4743
|
-
keys.push(
|
|
5200
|
+
keys.push(optionId);
|
|
4744
5201
|
}
|
|
4745
5202
|
}
|
|
4746
5203
|
return keys;
|
|
4747
5204
|
}
|
|
4748
|
-
function getSelectedOptionsByFieldId(selection, fieldById, mode) {
|
|
4749
|
-
var _a
|
|
5205
|
+
function getSelectedOptionsByFieldId(selection, fieldById, mode, visibleOptionsByFieldId) {
|
|
5206
|
+
var _a;
|
|
4750
5207
|
const collected = {};
|
|
4751
5208
|
for (const visit of buildSelectedNodeVisitOrder(selection, fieldById)) {
|
|
4752
5209
|
if (visit.kind !== "option") continue;
|
|
@@ -4757,18 +5214,18 @@ function getSelectedOptionsByFieldId(selection, fieldById, mode) {
|
|
|
4757
5214
|
for (const [fieldId, optionIds] of Object.entries(collected)) {
|
|
4758
5215
|
const field = fieldById.get(fieldId);
|
|
4759
5216
|
if (!field) continue;
|
|
4760
|
-
const validOptionIds =
|
|
4761
|
-
|
|
4762
|
-
);
|
|
5217
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
5218
|
+
const visibleOptionIds = (visibleOptionsByFieldId == null ? void 0 : visibleOptionsByFieldId[fieldId]) ? new Set(visibleOptionsByFieldId[fieldId]) : void 0;
|
|
4763
5219
|
const dedupedValid = [];
|
|
4764
5220
|
const seen = /* @__PURE__ */ new Set();
|
|
4765
5221
|
for (const optionId of optionIds) {
|
|
4766
5222
|
if (!validOptionIds.has(optionId)) continue;
|
|
5223
|
+
if (visibleOptionIds && !visibleOptionIds.has(optionId)) continue;
|
|
4767
5224
|
if (seen.has(optionId)) continue;
|
|
4768
5225
|
seen.add(optionId);
|
|
4769
5226
|
dedupedValid.push(optionId);
|
|
4770
5227
|
}
|
|
4771
|
-
const isMulti = ((
|
|
5228
|
+
const isMulti = ((_a = field.meta) == null ? void 0 : _a.multi) === true;
|
|
4772
5229
|
const normalized = mode === "prod" && !isMulti ? dedupedValid.length ? [dedupedValid[dedupedValid.length - 1]] : [] : dedupedValid;
|
|
4773
5230
|
if (normalized.length) out[fieldId] = normalized;
|
|
4774
5231
|
}
|
|
@@ -4785,57 +5242,49 @@ function buildSelectedNodeVisitOrder(selection, fieldById) {
|
|
|
4785
5242
|
out.push({ kind: "field", fieldId });
|
|
4786
5243
|
}
|
|
4787
5244
|
function pushOption(fieldId, optionId) {
|
|
4788
|
-
const key = `option:${
|
|
5245
|
+
const key = `option:${optionId}`;
|
|
4789
5246
|
if (seen.has(key)) return;
|
|
4790
5247
|
seen.add(key);
|
|
4791
5248
|
out.push({ kind: "option", fieldId, optionId });
|
|
4792
5249
|
}
|
|
4793
|
-
for (const
|
|
4794
|
-
|
|
5250
|
+
for (const optionId of (_a = selection.optionTraversalOrder) != null ? _a : []) {
|
|
5251
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5252
|
+
if (ownerField) pushOption(ownerField.id, optionId);
|
|
4795
5253
|
}
|
|
4796
5254
|
for (const rawKey of (_b = selection.selectedKeys) != null ? _b : []) {
|
|
4797
5255
|
const key = String(rawKey);
|
|
4798
|
-
if (key.includes("::")) {
|
|
4799
|
-
const [fieldId, optionId] = key.split("::", 2);
|
|
4800
|
-
if (fieldId && optionId) pushOption(fieldId, optionId);
|
|
4801
|
-
continue;
|
|
4802
|
-
}
|
|
4803
5256
|
const field = fieldById.get(key);
|
|
4804
5257
|
if (field) {
|
|
4805
5258
|
pushField(field.id);
|
|
4806
5259
|
continue;
|
|
4807
5260
|
}
|
|
4808
|
-
const ownerField = findOptionOwnerField(
|
|
5261
|
+
const ownerField = findOptionOwnerField(fieldById.values(), key);
|
|
4809
5262
|
if (ownerField) pushOption(ownerField.id, key);
|
|
4810
5263
|
}
|
|
4811
5264
|
for (const [fieldId, optionIds] of Object.entries(
|
|
4812
5265
|
(_c = selection.optionSelectionsByFieldId) != null ? _c : {}
|
|
4813
5266
|
)) {
|
|
4814
|
-
|
|
5267
|
+
const hintedField = fieldById.get(fieldId);
|
|
5268
|
+
if (!hintedField) continue;
|
|
4815
5269
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4816
|
-
|
|
5270
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5271
|
+
if ((ownerField == null ? void 0 : ownerField.id) === hintedField.id) {
|
|
5272
|
+
pushOption(ownerField.id, optionId);
|
|
5273
|
+
}
|
|
4817
5274
|
}
|
|
4818
5275
|
}
|
|
4819
5276
|
return out;
|
|
4820
5277
|
}
|
|
4821
|
-
function findOptionOwnerField(optionId, fieldById) {
|
|
4822
|
-
var _a;
|
|
4823
|
-
for (const field of fieldById.values()) {
|
|
4824
|
-
if ((_a = field.options) == null ? void 0 : _a.some((option) => option.id === optionId)) return field;
|
|
4825
|
-
}
|
|
4826
|
-
return void 0;
|
|
4827
|
-
}
|
|
4828
5278
|
|
|
4829
5279
|
// src/utils/build-order-snapshot/services.ts
|
|
4830
5280
|
function isServiceBased(field) {
|
|
4831
|
-
var _a;
|
|
4832
5281
|
if (field.service_id !== void 0 && field.service_id !== null) return true;
|
|
4833
|
-
return
|
|
4834
|
-
(
|
|
4835
|
-
)
|
|
5282
|
+
return walkFieldOptions(field).some(
|
|
5283
|
+
({ option }) => option.service_id !== void 0 && option.service_id !== null
|
|
5284
|
+
);
|
|
4836
5285
|
}
|
|
4837
5286
|
function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById, services) {
|
|
4838
|
-
var _a, _b, _c
|
|
5287
|
+
var _a, _b, _c;
|
|
4839
5288
|
const serviceMap = {};
|
|
4840
5289
|
const visible = new Set(visibleFieldIds);
|
|
4841
5290
|
const selectedBaseServices = [];
|
|
@@ -4862,9 +5311,9 @@ function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById,
|
|
|
4862
5311
|
}
|
|
4863
5312
|
continue;
|
|
4864
5313
|
}
|
|
4865
|
-
const option = (
|
|
5314
|
+
const option = findFieldOption(field, visit.optionId);
|
|
4866
5315
|
if (!option) continue;
|
|
4867
|
-
const role = (
|
|
5316
|
+
const role = (_c = (_b = option.pricing_role) != null ? _b : field.pricing_role) != null ? _c : "base";
|
|
4868
5317
|
if (role === "utility") continue;
|
|
4869
5318
|
if (option.service_id !== void 0 && option.service_id !== null) {
|
|
4870
5319
|
addSelectedBaseService(option.id, option.service_id);
|
|
@@ -4995,16 +5444,15 @@ function resolveQuantity(visibleFieldIds, fieldById, tagById, selection, tagId,
|
|
|
4995
5444
|
return { quantity: hostDefault, source: { kind: "default", defaultedFromHost: true } };
|
|
4996
5445
|
}
|
|
4997
5446
|
function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selection, tagId) {
|
|
4998
|
-
var _a, _b
|
|
5447
|
+
var _a, _b;
|
|
4999
5448
|
const visible = new Set(visibleFieldIds);
|
|
5000
5449
|
const visits = buildSelectedNodeVisitOrder(selection, fieldById);
|
|
5001
5450
|
for (const visit of visits) {
|
|
5002
5451
|
if (visit.kind !== "option") continue;
|
|
5003
5452
|
if (!visible.has(visit.fieldId)) continue;
|
|
5004
5453
|
const field = fieldById.get(visit.fieldId);
|
|
5005
|
-
|
|
5006
|
-
const
|
|
5007
|
-
const quantity = readPositiveFiniteNumber((_b = option == null ? void 0 : option.meta) == null ? void 0 : _b.quantityDefault);
|
|
5454
|
+
const option = findFieldOption(field, visit.optionId);
|
|
5455
|
+
const quantity = readPositiveFiniteNumber((_a = option == null ? void 0 : option.meta) == null ? void 0 : _a.quantityDefault);
|
|
5008
5456
|
if (quantity !== void 0) {
|
|
5009
5457
|
return { quantity, source: { kind: "option", id: option.id } };
|
|
5010
5458
|
}
|
|
@@ -5019,7 +5467,7 @@ function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selecti
|
|
|
5019
5467
|
}
|
|
5020
5468
|
}
|
|
5021
5469
|
const tag = tagById.get(tagId);
|
|
5022
|
-
const tagQuantity = readPositiveFiniteNumber((
|
|
5470
|
+
const tagQuantity = readPositiveFiniteNumber((_b = tag == null ? void 0 : tag.meta) == null ? void 0 : _b.quantityDefault);
|
|
5023
5471
|
if (tagQuantity !== void 0) {
|
|
5024
5472
|
return { quantity: tagQuantity, source: { kind: "tag", id: tagId } };
|
|
5025
5473
|
}
|
|
@@ -5122,12 +5570,10 @@ function collectUtilityLineItems(visibleFieldIds, fieldById, selection, selected
|
|
|
5122
5570
|
const item = buildUtilityItemFromMarker(field.id, marker, quantity, value);
|
|
5123
5571
|
if (item) items.push(item);
|
|
5124
5572
|
}
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
if (!selectedOptionIds.length) continue;
|
|
5128
|
-
const optById = new Map(field.options.map((o) => [o.id, o]));
|
|
5573
|
+
const selectedOptionIds = (_c = selectedOptionsByFieldId[field.id]) != null ? _c : [];
|
|
5574
|
+
if (selectedOptionIds.length) {
|
|
5129
5575
|
for (const oid of selectedOptionIds) {
|
|
5130
|
-
const option =
|
|
5576
|
+
const option = findFieldOption(field, oid);
|
|
5131
5577
|
if (!option) continue;
|
|
5132
5578
|
if (((_d = option.pricing_role) != null ? _d : "base") !== "utility") continue;
|
|
5133
5579
|
const optionMarker = readUtilityMarker((_e = option.meta) == null ? void 0 : _e.utility);
|
|
@@ -5243,7 +5689,7 @@ function buildDevWarnings(props, svcMap, originalFallbacks, fieldById, visibleFi
|
|
|
5243
5689
|
|
|
5244
5690
|
// src/utils/build-order-snapshot/index.ts
|
|
5245
5691
|
function buildOrderSnapshot(props, builder, selection, services, settings = {}) {
|
|
5246
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5692
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
5247
5693
|
const mode = (_a = settings.mode) != null ? _a : "prod";
|
|
5248
5694
|
const hostDefaultQty = Number.isFinite((_b = settings.hostDefaultQuantity) != null ? _b : 1) ? settings.hostDefaultQuantity : 1;
|
|
5249
5695
|
const fbSettings = {
|
|
@@ -5256,14 +5702,31 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5256
5702
|
const builtAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5257
5703
|
const tagId = selection.activeTagId;
|
|
5258
5704
|
const selectedButtonKeys = (_d = selection.selectedKeys) != null ? _d : toSelectedOptionKeys(selection.optionSelectionsByFieldId);
|
|
5259
|
-
const visibleFieldIds = builder.visibleFields(tagId, selectedButtonKeys);
|
|
5260
5705
|
const tagById = new Map(((_e = props.filters) != null ? _e : []).map((t) => [t.id, t]));
|
|
5261
5706
|
const fieldById = new Map(((_f = props.fields) != null ? _f : []).map((f) => [f.id, f]));
|
|
5262
|
-
const
|
|
5707
|
+
const resolve = typeof builder.resolveVisibility === "function" ? builder.resolveVisibility.bind(builder) : void 0;
|
|
5708
|
+
let resolvedVisibility = resolve == null ? void 0 : resolve(tagId, selectedButtonKeys);
|
|
5709
|
+
let visibleFieldIds = (_g = resolvedVisibility == null ? void 0 : resolvedVisibility.fieldIds) != null ? _g : builder.visibleFields(tagId, selectedButtonKeys);
|
|
5710
|
+
const filteredSelectedButtonKeys = filterSelectedKeysByVisibility(
|
|
5711
|
+
selectedButtonKeys,
|
|
5712
|
+
visibleFieldIds,
|
|
5713
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId,
|
|
5714
|
+
fieldById
|
|
5715
|
+
);
|
|
5716
|
+
if (resolve && filteredSelectedButtonKeys.join("\0") !== selectedButtonKeys.join("\0")) {
|
|
5717
|
+
resolvedVisibility = resolve(tagId, filteredSelectedButtonKeys);
|
|
5718
|
+
visibleFieldIds = resolvedVisibility.fieldIds;
|
|
5719
|
+
}
|
|
5720
|
+
const effectiveSelection = {
|
|
5721
|
+
...selection,
|
|
5722
|
+
selectedKeys: filteredSelectedButtonKeys
|
|
5723
|
+
};
|
|
5724
|
+
const tagConstraints = (_i = (_h = tagById.get(tagId)) == null ? void 0 : _h.constraints) != null ? _i : void 0;
|
|
5263
5725
|
const selectedOptionsByFieldId = getSelectedOptionsByFieldId(
|
|
5264
|
-
|
|
5726
|
+
effectiveSelection,
|
|
5265
5727
|
fieldById,
|
|
5266
|
-
mode
|
|
5728
|
+
mode,
|
|
5729
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId
|
|
5267
5730
|
);
|
|
5268
5731
|
const selectionFields = visibleFieldIds.map((fid) => fieldById.get(fid)).filter((f) => !!f).map((f) => {
|
|
5269
5732
|
var _a2;
|
|
@@ -5277,21 +5740,21 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5277
5740
|
const { formValues, selections } = buildInputs(
|
|
5278
5741
|
visibleFieldIds,
|
|
5279
5742
|
fieldById,
|
|
5280
|
-
|
|
5743
|
+
effectiveSelection,
|
|
5281
5744
|
selectedOptionsByFieldId
|
|
5282
5745
|
);
|
|
5283
5746
|
const qtyRes = resolveQuantity(
|
|
5284
5747
|
visibleFieldIds,
|
|
5285
5748
|
fieldById,
|
|
5286
5749
|
tagById,
|
|
5287
|
-
|
|
5750
|
+
effectiveSelection,
|
|
5288
5751
|
tagId,
|
|
5289
5752
|
hostDefaultQty
|
|
5290
5753
|
);
|
|
5291
5754
|
const { serviceMap, servicesList } = resolveServices(
|
|
5292
5755
|
tagId,
|
|
5293
5756
|
visibleFieldIds,
|
|
5294
|
-
|
|
5757
|
+
effectiveSelection,
|
|
5295
5758
|
tagById,
|
|
5296
5759
|
fieldById,
|
|
5297
5760
|
services
|
|
@@ -5313,7 +5776,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5313
5776
|
const utilities = collectUtilityLineItems(
|
|
5314
5777
|
visibleFieldIds,
|
|
5315
5778
|
fieldById,
|
|
5316
|
-
|
|
5779
|
+
effectiveSelection,
|
|
5317
5780
|
selectedOptionsByFieldId,
|
|
5318
5781
|
qtyRes.quantity
|
|
5319
5782
|
);
|
|
@@ -5323,7 +5786,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5323
5786
|
prunedFallbacks.original,
|
|
5324
5787
|
fieldById,
|
|
5325
5788
|
visibleFieldIds,
|
|
5326
|
-
|
|
5789
|
+
effectiveSelection
|
|
5327
5790
|
) : void 0;
|
|
5328
5791
|
const meta = {
|
|
5329
5792
|
schema_version: props.schema_version,
|
|
@@ -5336,7 +5799,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5336
5799
|
tagId,
|
|
5337
5800
|
visibleFieldIds,
|
|
5338
5801
|
fieldById,
|
|
5339
|
-
|
|
5802
|
+
effectiveSelection,
|
|
5340
5803
|
selectedOptionsByFieldId
|
|
5341
5804
|
),
|
|
5342
5805
|
policy: toSnapshotPolicy(fbSettings)
|
|
@@ -5348,7 +5811,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5348
5811
|
builtAt,
|
|
5349
5812
|
selection: {
|
|
5350
5813
|
tag: tagId,
|
|
5351
|
-
buttons:
|
|
5814
|
+
buttons: filteredSelectedButtonKeys,
|
|
5352
5815
|
fields: selectionFields
|
|
5353
5816
|
},
|
|
5354
5817
|
inputs: { form: formValues, selections },
|
|
@@ -5366,6 +5829,24 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5366
5829
|
meta
|
|
5367
5830
|
};
|
|
5368
5831
|
}
|
|
5832
|
+
function filterSelectedKeysByVisibility(selectedKeys, visibleFieldIds, optionsByFieldId, fieldById) {
|
|
5833
|
+
if (!optionsByFieldId) return selectedKeys;
|
|
5834
|
+
const visibleFields = new Set(visibleFieldIds);
|
|
5835
|
+
const out = [];
|
|
5836
|
+
for (const rawKey of selectedKeys) {
|
|
5837
|
+
const key = String(rawKey);
|
|
5838
|
+
if (fieldById.has(key)) {
|
|
5839
|
+
if (visibleFields.has(key)) out.push(key);
|
|
5840
|
+
continue;
|
|
5841
|
+
}
|
|
5842
|
+
const owner = findOptionOwnerField(fieldById.values(), key);
|
|
5843
|
+
if (!owner || !visibleFields.has(owner.id)) continue;
|
|
5844
|
+
const allowed = optionsByFieldId[owner.id];
|
|
5845
|
+
if (allowed && !allowed.includes(key)) continue;
|
|
5846
|
+
out.push(key);
|
|
5847
|
+
}
|
|
5848
|
+
return out;
|
|
5849
|
+
}
|
|
5369
5850
|
|
|
5370
5851
|
// src/core/fallback-editor.ts
|
|
5371
5852
|
function createFallbackEditor(options = {}) {
|
|
@@ -5746,16 +6227,24 @@ export {
|
|
|
5746
6227
|
createBuilder,
|
|
5747
6228
|
createFallbackEditor,
|
|
5748
6229
|
createNodeIndex,
|
|
6230
|
+
fieldOptionIdSet,
|
|
6231
|
+
fieldOptionIds,
|
|
6232
|
+
filterFieldOptionsById,
|
|
5749
6233
|
filterServicesForVisibleGroup,
|
|
6234
|
+
findFieldOption,
|
|
6235
|
+
findOptionOwnerField,
|
|
5750
6236
|
getAssignedServiceIds,
|
|
5751
6237
|
getEligibleFallbacks,
|
|
5752
6238
|
getFallbackRegistrationInfo,
|
|
5753
6239
|
isRefExcludedBySelectedKeys,
|
|
5754
6240
|
normalise,
|
|
5755
6241
|
normalizeFieldValidation,
|
|
6242
|
+
optionOwnerMap,
|
|
5756
6243
|
resolveServiceFallback,
|
|
5757
6244
|
validate,
|
|
5758
6245
|
validateAsync,
|
|
5759
|
-
validateRateCoherenceDeep
|
|
6246
|
+
validateRateCoherenceDeep,
|
|
6247
|
+
walkFieldOptions,
|
|
6248
|
+
walkOptions
|
|
5760
6249
|
};
|
|
5761
6250
|
//# sourceMappingURL=index.js.map
|