@timeax/digital-service-engine 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.cjs +680 -159
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +48 -6
- package/dist/core/index.d.ts +48 -6
- package/dist/core/index.js +671 -158
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +2123 -999
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +115 -58
- package/dist/react/index.d.ts +115 -58
- package/dist/react/index.js +2123 -999
- package/dist/react/index.js.map +1 -1
- package/dist/schema/index.d.cts +19 -2
- package/dist/schema/index.d.ts +19 -2
- package/dist/workspace/index.cjs +1291 -372
- package/dist/workspace/index.cjs.map +1 -1
- package/dist/workspace/index.d.cts +176 -5
- package/dist/workspace/index.d.ts +176 -5
- package/dist/workspace/index.js +1291 -372
- package/dist/workspace/index.js.map +1 -1
- package/package.json +1 -1
- package/schema/editor-snapshot.schema.json +38 -0
- package/schema/service-props.schema.json +38 -0
package/dist/core/index.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,24 +5190,44 @@ 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) {
|
|
4749
|
-
|
|
5205
|
+
function getSelectedOptionsByFieldId(selection, fieldById, mode, visibleOptionsByFieldId) {
|
|
5206
|
+
var _a;
|
|
5207
|
+
const collected = {};
|
|
4750
5208
|
for (const visit of buildSelectedNodeVisitOrder(selection, fieldById)) {
|
|
4751
5209
|
if (visit.kind !== "option") continue;
|
|
4752
|
-
if (!
|
|
4753
|
-
|
|
5210
|
+
if (!collected[visit.fieldId]) collected[visit.fieldId] = [];
|
|
5211
|
+
collected[visit.fieldId].push(visit.optionId);
|
|
5212
|
+
}
|
|
5213
|
+
const out = {};
|
|
5214
|
+
for (const [fieldId, optionIds] of Object.entries(collected)) {
|
|
5215
|
+
const field = fieldById.get(fieldId);
|
|
5216
|
+
if (!field) continue;
|
|
5217
|
+
const validOptionIds = fieldOptionIdSet(field);
|
|
5218
|
+
const visibleOptionIds = (visibleOptionsByFieldId == null ? void 0 : visibleOptionsByFieldId[fieldId]) ? new Set(visibleOptionsByFieldId[fieldId]) : void 0;
|
|
5219
|
+
const dedupedValid = [];
|
|
5220
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5221
|
+
for (const optionId of optionIds) {
|
|
5222
|
+
if (!validOptionIds.has(optionId)) continue;
|
|
5223
|
+
if (visibleOptionIds && !visibleOptionIds.has(optionId)) continue;
|
|
5224
|
+
if (seen.has(optionId)) continue;
|
|
5225
|
+
seen.add(optionId);
|
|
5226
|
+
dedupedValid.push(optionId);
|
|
5227
|
+
}
|
|
5228
|
+
const isMulti = ((_a = field.meta) == null ? void 0 : _a.multi) === true;
|
|
5229
|
+
const normalized = mode === "prod" && !isMulti ? dedupedValid.length ? [dedupedValid[dedupedValid.length - 1]] : [] : dedupedValid;
|
|
5230
|
+
if (normalized.length) out[fieldId] = normalized;
|
|
4754
5231
|
}
|
|
4755
5232
|
return out;
|
|
4756
5233
|
}
|
|
@@ -4765,57 +5242,49 @@ function buildSelectedNodeVisitOrder(selection, fieldById) {
|
|
|
4765
5242
|
out.push({ kind: "field", fieldId });
|
|
4766
5243
|
}
|
|
4767
5244
|
function pushOption(fieldId, optionId) {
|
|
4768
|
-
const key = `option:${
|
|
5245
|
+
const key = `option:${optionId}`;
|
|
4769
5246
|
if (seen.has(key)) return;
|
|
4770
5247
|
seen.add(key);
|
|
4771
5248
|
out.push({ kind: "option", fieldId, optionId });
|
|
4772
5249
|
}
|
|
4773
|
-
for (const
|
|
4774
|
-
|
|
5250
|
+
for (const optionId of (_a = selection.optionTraversalOrder) != null ? _a : []) {
|
|
5251
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5252
|
+
if (ownerField) pushOption(ownerField.id, optionId);
|
|
4775
5253
|
}
|
|
4776
5254
|
for (const rawKey of (_b = selection.selectedKeys) != null ? _b : []) {
|
|
4777
5255
|
const key = String(rawKey);
|
|
4778
|
-
if (key.includes("::")) {
|
|
4779
|
-
const [fieldId, optionId] = key.split("::", 2);
|
|
4780
|
-
if (fieldId && optionId) pushOption(fieldId, optionId);
|
|
4781
|
-
continue;
|
|
4782
|
-
}
|
|
4783
5256
|
const field = fieldById.get(key);
|
|
4784
5257
|
if (field) {
|
|
4785
5258
|
pushField(field.id);
|
|
4786
5259
|
continue;
|
|
4787
5260
|
}
|
|
4788
|
-
const ownerField = findOptionOwnerField(
|
|
5261
|
+
const ownerField = findOptionOwnerField(fieldById.values(), key);
|
|
4789
5262
|
if (ownerField) pushOption(ownerField.id, key);
|
|
4790
5263
|
}
|
|
4791
5264
|
for (const [fieldId, optionIds] of Object.entries(
|
|
4792
5265
|
(_c = selection.optionSelectionsByFieldId) != null ? _c : {}
|
|
4793
5266
|
)) {
|
|
4794
|
-
|
|
5267
|
+
const hintedField = fieldById.get(fieldId);
|
|
5268
|
+
if (!hintedField) continue;
|
|
4795
5269
|
for (const optionId of optionIds != null ? optionIds : []) {
|
|
4796
|
-
|
|
5270
|
+
const ownerField = findOptionOwnerField(fieldById.values(), optionId);
|
|
5271
|
+
if ((ownerField == null ? void 0 : ownerField.id) === hintedField.id) {
|
|
5272
|
+
pushOption(ownerField.id, optionId);
|
|
5273
|
+
}
|
|
4797
5274
|
}
|
|
4798
5275
|
}
|
|
4799
5276
|
return out;
|
|
4800
5277
|
}
|
|
4801
|
-
function findOptionOwnerField(optionId, fieldById) {
|
|
4802
|
-
var _a;
|
|
4803
|
-
for (const field of fieldById.values()) {
|
|
4804
|
-
if ((_a = field.options) == null ? void 0 : _a.some((option) => option.id === optionId)) return field;
|
|
4805
|
-
}
|
|
4806
|
-
return void 0;
|
|
4807
|
-
}
|
|
4808
5278
|
|
|
4809
5279
|
// src/utils/build-order-snapshot/services.ts
|
|
4810
5280
|
function isServiceBased(field) {
|
|
4811
|
-
var _a;
|
|
4812
5281
|
if (field.service_id !== void 0 && field.service_id !== null) return true;
|
|
4813
|
-
return
|
|
4814
|
-
(
|
|
4815
|
-
)
|
|
5282
|
+
return walkFieldOptions(field).some(
|
|
5283
|
+
({ option }) => option.service_id !== void 0 && option.service_id !== null
|
|
5284
|
+
);
|
|
4816
5285
|
}
|
|
4817
5286
|
function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById, services) {
|
|
4818
|
-
var _a, _b, _c
|
|
5287
|
+
var _a, _b, _c;
|
|
4819
5288
|
const serviceMap = {};
|
|
4820
5289
|
const visible = new Set(visibleFieldIds);
|
|
4821
5290
|
const selectedBaseServices = [];
|
|
@@ -4842,9 +5311,9 @@ function resolveServices(tagId, visibleFieldIds, selection, tagById, fieldById,
|
|
|
4842
5311
|
}
|
|
4843
5312
|
continue;
|
|
4844
5313
|
}
|
|
4845
|
-
const option = (
|
|
5314
|
+
const option = findFieldOption(field, visit.optionId);
|
|
4846
5315
|
if (!option) continue;
|
|
4847
|
-
const role = (
|
|
5316
|
+
const role = (_c = (_b = option.pricing_role) != null ? _b : field.pricing_role) != null ? _c : "base";
|
|
4848
5317
|
if (role === "utility") continue;
|
|
4849
5318
|
if (option.service_id !== void 0 && option.service_id !== null) {
|
|
4850
5319
|
addSelectedBaseService(option.id, option.service_id);
|
|
@@ -4975,16 +5444,15 @@ function resolveQuantity(visibleFieldIds, fieldById, tagById, selection, tagId,
|
|
|
4975
5444
|
return { quantity: hostDefault, source: { kind: "default", defaultedFromHost: true } };
|
|
4976
5445
|
}
|
|
4977
5446
|
function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selection, tagId) {
|
|
4978
|
-
var _a, _b
|
|
5447
|
+
var _a, _b;
|
|
4979
5448
|
const visible = new Set(visibleFieldIds);
|
|
4980
5449
|
const visits = buildSelectedNodeVisitOrder(selection, fieldById);
|
|
4981
5450
|
for (const visit of visits) {
|
|
4982
5451
|
if (visit.kind !== "option") continue;
|
|
4983
5452
|
if (!visible.has(visit.fieldId)) continue;
|
|
4984
5453
|
const field = fieldById.get(visit.fieldId);
|
|
4985
|
-
|
|
4986
|
-
const
|
|
4987
|
-
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);
|
|
4988
5456
|
if (quantity !== void 0) {
|
|
4989
5457
|
return { quantity, source: { kind: "option", id: option.id } };
|
|
4990
5458
|
}
|
|
@@ -4999,7 +5467,7 @@ function resolveNodeDefaultQuantity(visibleFieldIds, fieldById, tagById, selecti
|
|
|
4999
5467
|
}
|
|
5000
5468
|
}
|
|
5001
5469
|
const tag = tagById.get(tagId);
|
|
5002
|
-
const tagQuantity = readPositiveFiniteNumber((
|
|
5470
|
+
const tagQuantity = readPositiveFiniteNumber((_b = tag == null ? void 0 : tag.meta) == null ? void 0 : _b.quantityDefault);
|
|
5003
5471
|
if (tagQuantity !== void 0) {
|
|
5004
5472
|
return { quantity: tagQuantity, source: { kind: "tag", id: tagId } };
|
|
5005
5473
|
}
|
|
@@ -5102,12 +5570,10 @@ function collectUtilityLineItems(visibleFieldIds, fieldById, selection, selected
|
|
|
5102
5570
|
const item = buildUtilityItemFromMarker(field.id, marker, quantity, value);
|
|
5103
5571
|
if (item) items.push(item);
|
|
5104
5572
|
}
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
if (!selectedOptionIds.length) continue;
|
|
5108
|
-
const optById = new Map(field.options.map((o) => [o.id, o]));
|
|
5573
|
+
const selectedOptionIds = (_c = selectedOptionsByFieldId[field.id]) != null ? _c : [];
|
|
5574
|
+
if (selectedOptionIds.length) {
|
|
5109
5575
|
for (const oid of selectedOptionIds) {
|
|
5110
|
-
const option =
|
|
5576
|
+
const option = findFieldOption(field, oid);
|
|
5111
5577
|
if (!option) continue;
|
|
5112
5578
|
if (((_d = option.pricing_role) != null ? _d : "base") !== "utility") continue;
|
|
5113
5579
|
const optionMarker = readUtilityMarker((_e = option.meta) == null ? void 0 : _e.utility);
|
|
@@ -5223,7 +5689,7 @@ function buildDevWarnings(props, svcMap, originalFallbacks, fieldById, visibleFi
|
|
|
5223
5689
|
|
|
5224
5690
|
// src/utils/build-order-snapshot/index.ts
|
|
5225
5691
|
function buildOrderSnapshot(props, builder, selection, services, settings = {}) {
|
|
5226
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
5692
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
5227
5693
|
const mode = (_a = settings.mode) != null ? _a : "prod";
|
|
5228
5694
|
const hostDefaultQty = Number.isFinite((_b = settings.hostDefaultQuantity) != null ? _b : 1) ? settings.hostDefaultQuantity : 1;
|
|
5229
5695
|
const fbSettings = {
|
|
@@ -5236,11 +5702,32 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5236
5702
|
const builtAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5237
5703
|
const tagId = selection.activeTagId;
|
|
5238
5704
|
const selectedButtonKeys = (_d = selection.selectedKeys) != null ? _d : toSelectedOptionKeys(selection.optionSelectionsByFieldId);
|
|
5239
|
-
const visibleFieldIds = builder.visibleFields(tagId, selectedButtonKeys);
|
|
5240
5705
|
const tagById = new Map(((_e = props.filters) != null ? _e : []).map((t) => [t.id, t]));
|
|
5241
5706
|
const fieldById = new Map(((_f = props.fields) != null ? _f : []).map((f) => [f.id, f]));
|
|
5242
|
-
const
|
|
5243
|
-
|
|
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;
|
|
5725
|
+
const selectedOptionsByFieldId = getSelectedOptionsByFieldId(
|
|
5726
|
+
effectiveSelection,
|
|
5727
|
+
fieldById,
|
|
5728
|
+
mode,
|
|
5729
|
+
resolvedVisibility == null ? void 0 : resolvedVisibility.optionsByFieldId
|
|
5730
|
+
);
|
|
5244
5731
|
const selectionFields = visibleFieldIds.map((fid) => fieldById.get(fid)).filter((f) => !!f).map((f) => {
|
|
5245
5732
|
var _a2;
|
|
5246
5733
|
const optionIds = isOptionBased(f) ? (_a2 = selectedOptionsByFieldId[f.id]) != null ? _a2 : [] : void 0;
|
|
@@ -5253,21 +5740,21 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5253
5740
|
const { formValues, selections } = buildInputs(
|
|
5254
5741
|
visibleFieldIds,
|
|
5255
5742
|
fieldById,
|
|
5256
|
-
|
|
5743
|
+
effectiveSelection,
|
|
5257
5744
|
selectedOptionsByFieldId
|
|
5258
5745
|
);
|
|
5259
5746
|
const qtyRes = resolveQuantity(
|
|
5260
5747
|
visibleFieldIds,
|
|
5261
5748
|
fieldById,
|
|
5262
5749
|
tagById,
|
|
5263
|
-
|
|
5750
|
+
effectiveSelection,
|
|
5264
5751
|
tagId,
|
|
5265
5752
|
hostDefaultQty
|
|
5266
5753
|
);
|
|
5267
5754
|
const { serviceMap, servicesList } = resolveServices(
|
|
5268
5755
|
tagId,
|
|
5269
5756
|
visibleFieldIds,
|
|
5270
|
-
|
|
5757
|
+
effectiveSelection,
|
|
5271
5758
|
tagById,
|
|
5272
5759
|
fieldById,
|
|
5273
5760
|
services
|
|
@@ -5289,7 +5776,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5289
5776
|
const utilities = collectUtilityLineItems(
|
|
5290
5777
|
visibleFieldIds,
|
|
5291
5778
|
fieldById,
|
|
5292
|
-
|
|
5779
|
+
effectiveSelection,
|
|
5293
5780
|
selectedOptionsByFieldId,
|
|
5294
5781
|
qtyRes.quantity
|
|
5295
5782
|
);
|
|
@@ -5299,7 +5786,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5299
5786
|
prunedFallbacks.original,
|
|
5300
5787
|
fieldById,
|
|
5301
5788
|
visibleFieldIds,
|
|
5302
|
-
|
|
5789
|
+
effectiveSelection
|
|
5303
5790
|
) : void 0;
|
|
5304
5791
|
const meta = {
|
|
5305
5792
|
schema_version: props.schema_version,
|
|
@@ -5312,7 +5799,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5312
5799
|
tagId,
|
|
5313
5800
|
visibleFieldIds,
|
|
5314
5801
|
fieldById,
|
|
5315
|
-
|
|
5802
|
+
effectiveSelection,
|
|
5316
5803
|
selectedOptionsByFieldId
|
|
5317
5804
|
),
|
|
5318
5805
|
policy: toSnapshotPolicy(fbSettings)
|
|
@@ -5324,7 +5811,7 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5324
5811
|
builtAt,
|
|
5325
5812
|
selection: {
|
|
5326
5813
|
tag: tagId,
|
|
5327
|
-
buttons:
|
|
5814
|
+
buttons: filteredSelectedButtonKeys,
|
|
5328
5815
|
fields: selectionFields
|
|
5329
5816
|
},
|
|
5330
5817
|
inputs: { form: formValues, selections },
|
|
@@ -5342,6 +5829,24 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
|
|
|
5342
5829
|
meta
|
|
5343
5830
|
};
|
|
5344
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
|
+
}
|
|
5345
5850
|
|
|
5346
5851
|
// src/core/fallback-editor.ts
|
|
5347
5852
|
function createFallbackEditor(options = {}) {
|
|
@@ -5722,16 +6227,24 @@ export {
|
|
|
5722
6227
|
createBuilder,
|
|
5723
6228
|
createFallbackEditor,
|
|
5724
6229
|
createNodeIndex,
|
|
6230
|
+
fieldOptionIdSet,
|
|
6231
|
+
fieldOptionIds,
|
|
6232
|
+
filterFieldOptionsById,
|
|
5725
6233
|
filterServicesForVisibleGroup,
|
|
6234
|
+
findFieldOption,
|
|
6235
|
+
findOptionOwnerField,
|
|
5726
6236
|
getAssignedServiceIds,
|
|
5727
6237
|
getEligibleFallbacks,
|
|
5728
6238
|
getFallbackRegistrationInfo,
|
|
5729
6239
|
isRefExcludedBySelectedKeys,
|
|
5730
6240
|
normalise,
|
|
5731
6241
|
normalizeFieldValidation,
|
|
6242
|
+
optionOwnerMap,
|
|
5732
6243
|
resolveServiceFallback,
|
|
5733
6244
|
validate,
|
|
5734
6245
|
validateAsync,
|
|
5735
|
-
validateRateCoherenceDeep
|
|
6246
|
+
validateRateCoherenceDeep,
|
|
6247
|
+
walkFieldOptions,
|
|
6248
|
+
walkOptions
|
|
5736
6249
|
};
|
|
5737
6250
|
//# sourceMappingURL=index.js.map
|