@repobit/dex-store-elements 1.7.2 → 2.0.0
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/CHANGELOG.md +5 -905
- package/README.md +9 -7
- package/dist/src/actions/action.adapter.d.ts +36 -0
- package/dist/src/actions/action.adapter.js +183 -0
- package/dist/src/actions/action.adapter.js.map +1 -0
- package/dist/src/actions/action.attributes.d.ts +15 -0
- package/dist/src/actions/action.attributes.js +137 -0
- package/dist/src/actions/action.attributes.js.map +1 -0
- package/dist/src/actions/action.registry.d.ts +4 -0
- package/dist/src/actions/action.registry.js +119 -0
- package/dist/src/actions/action.registry.js.map +1 -0
- package/dist/src/actions/index.d.ts +3 -2
- package/dist/src/actions/index.js +3 -80
- package/dist/src/actions/index.js.map +1 -1
- package/dist/src/compute/compute.expand.d.ts +70 -0
- package/dist/src/compute/compute.expand.js +319 -0
- package/dist/src/compute/compute.expand.js.map +1 -0
- package/dist/src/compute/compute.scan.d.ts +54 -0
- package/dist/src/compute/compute.scan.js +160 -0
- package/dist/src/compute/compute.scan.js.map +1 -0
- package/dist/src/compute/option-resolver.d.ts +31 -0
- package/dist/src/compute/option-resolver.js +147 -0
- package/dist/src/compute/option-resolver.js.map +1 -0
- package/dist/src/contexts/context.compute.d.ts +12 -0
- package/dist/src/contexts/context.compute.js +4 -0
- package/dist/src/contexts/context.compute.js.map +1 -0
- package/dist/src/contexts/context.scope.d.ts +139 -0
- package/dist/src/contexts/context.scope.js +48 -0
- package/dist/src/contexts/context.scope.js.map +1 -0
- package/dist/src/controllers/controller.action-resolve.d.ts +110 -0
- package/dist/src/controllers/controller.action-resolve.js +203 -0
- package/dist/src/controllers/controller.action-resolve.js.map +1 -0
- package/dist/src/controllers/controller.action-topology.d.ts +59 -0
- package/dist/src/controllers/controller.action-topology.js +130 -0
- package/dist/src/controllers/controller.action-topology.js.map +1 -0
- package/dist/src/controllers/controller.compute.d.ts +72 -0
- package/dist/src/controllers/controller.compute.js +110 -0
- package/dist/src/controllers/controller.compute.js.map +1 -0
- package/dist/src/controllers/controller.resolve.d.ts +78 -0
- package/dist/src/controllers/controller.resolve.js +205 -0
- package/dist/src/controllers/controller.resolve.js.map +1 -0
- package/dist/src/core/action-topology.d.ts +62 -0
- package/dist/src/core/action-topology.js +67 -0
- package/dist/src/core/action-topology.js.map +1 -0
- package/dist/src/core/actions.d.ts +64 -0
- package/dist/src/core/actions.js +47 -0
- package/dist/src/core/actions.js.map +1 -0
- package/dist/src/core/node.element.d.ts +179 -0
- package/dist/src/core/node.element.js +573 -0
- package/dist/src/core/node.element.js.map +1 -0
- package/dist/src/core/node.scope.d.ts +374 -0
- package/dist/src/core/node.scope.js +558 -0
- package/dist/src/core/node.scope.js.map +1 -0
- package/dist/src/core/option-update.d.ts +11 -0
- package/dist/src/core/option-update.js +59 -0
- package/dist/src/core/option-update.js.map +1 -0
- package/dist/src/dsl/compilers/array/compiler.js +13 -14
- package/dist/src/dsl/compilers/array/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/boolean/compiler.d.ts +1 -1
- package/dist/src/dsl/compilers/boolean/compiler.js +14 -27
- package/dist/src/dsl/compilers/boolean/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/enum/compiler.js +7 -10
- package/dist/src/dsl/compilers/enum/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/index.d.ts +1 -1
- package/dist/src/dsl/compilers/index.js +5 -5
- package/dist/src/dsl/compilers/index.js.map +1 -1
- package/dist/src/dsl/utilty.d.ts +0 -4
- package/dist/src/dsl/utilty.js +3 -30
- package/dist/src/dsl/utilty.js.map +1 -1
- package/dist/src/eta/batch.d.ts +123 -0
- package/dist/src/eta/batch.js +162 -0
- package/dist/src/eta/batch.js.map +1 -0
- package/dist/src/eta/batcher.d.ts +184 -0
- package/dist/src/eta/batcher.js +335 -0
- package/dist/src/eta/batcher.js.map +1 -0
- package/dist/src/eta/cache.d.ts +36 -0
- package/dist/src/eta/cache.js +56 -0
- package/dist/src/eta/cache.js.map +1 -0
- package/dist/src/eta/controller.d.ts +608 -0
- package/dist/src/eta/controller.js +1036 -0
- package/dist/src/eta/controller.js.map +1 -0
- package/dist/src/eta/factory.d.ts +74 -0
- package/dist/src/eta/factory.js +121 -0
- package/dist/src/eta/factory.js.map +1 -0
- package/dist/src/eta/idle.d.ts +39 -0
- package/dist/src/eta/idle.js +52 -0
- package/dist/src/eta/idle.js.map +1 -0
- package/dist/src/eta/index.d.ts +52 -0
- package/dist/src/eta/index.js +13 -0
- package/dist/src/eta/index.js.map +1 -0
- package/dist/src/eta/observer.d.ts +263 -0
- package/dist/src/eta/observer.js +263 -0
- package/dist/src/eta/observer.js.map +1 -0
- package/dist/src/eta/operations.d.ts +41 -0
- package/dist/src/eta/operations.js +59 -0
- package/dist/src/eta/operations.js.map +1 -0
- package/dist/src/eta/source-registry.d.ts +198 -0
- package/dist/src/eta/source-registry.js +267 -0
- package/dist/src/eta/source-registry.js.map +1 -0
- package/dist/src/eta/template-index.d.ts +285 -0
- package/dist/src/eta/template-index.js +642 -0
- package/dist/src/eta/template-index.js.map +1 -0
- package/dist/src/eta/types.d.ts +529 -0
- package/dist/src/eta/types.js +2 -0
- package/dist/src/eta/types.js.map +1 -0
- package/dist/src/index.d.ts +21 -9
- package/dist/src/index.js +22 -11
- package/dist/src/index.js.map +1 -1
- package/dist/src/nodes/node.context.d.ts +5 -3
- package/dist/src/nodes/node.context.js +48 -3
- package/dist/src/nodes/node.context.js.map +1 -1
- package/dist/src/nodes/node.option.d.ts +11 -31
- package/dist/src/nodes/node.option.js +158 -222
- package/dist/src/nodes/node.option.js.map +1 -1
- package/dist/src/nodes/node.product.d.ts +7 -11
- package/dist/src/nodes/node.product.js +85 -64
- package/dist/src/nodes/node.product.js.map +1 -1
- package/dist/src/renders/attributes/buyLink.d.ts +2 -2
- package/dist/src/renders/attributes/buyLink.js +14 -11
- package/dist/src/renders/attributes/buyLink.js.map +1 -1
- package/dist/src/renders/attributes/devices.d.ts +2 -2
- package/dist/src/renders/attributes/devices.js +9 -19
- package/dist/src/renders/attributes/devices.js.map +1 -1
- package/dist/src/renders/attributes/discount.d.ts +2 -2
- package/dist/src/renders/attributes/discount.js +56 -44
- package/dist/src/renders/attributes/discount.js.map +1 -1
- package/dist/src/renders/attributes/hide.d.ts +2 -2
- package/dist/src/renders/attributes/hide.js +49 -14
- package/dist/src/renders/attributes/hide.js.map +1 -1
- package/dist/src/renders/attributes/index.d.ts +3 -3
- package/dist/src/renders/attributes/index.js +2 -4
- package/dist/src/renders/attributes/index.js.map +1 -1
- package/dist/src/renders/attributes/price.d.ts +2 -2
- package/dist/src/renders/attributes/price.js +30 -44
- package/dist/src/renders/attributes/price.js.map +1 -1
- package/dist/src/renders/attributes/subscription.d.ts +2 -2
- package/dist/src/renders/attributes/subscription.js +14 -20
- package/dist/src/renders/attributes/subscription.js.map +1 -1
- package/dist/src/renders/attributes/utilty.d.ts +2 -0
- package/dist/src/renders/attributes/utilty.js +17 -4
- package/dist/src/renders/attributes/utilty.js.map +1 -1
- package/dist/src/renders/context.d.ts +122 -10
- package/dist/src/renders/context.js +140 -80
- package/dist/src/renders/context.js.map +1 -1
- package/dist/src/renders/format.js +2 -2
- package/dist/src/renders/format.js.map +1 -1
- package/dist/src/renders/index.d.ts +6 -2
- package/dist/src/renders/index.js +67 -29
- package/dist/src/renders/index.js.map +1 -1
- package/dist/src/renders/observe.d.ts +1 -4
- package/dist/src/renders/observe.js +10 -24
- package/dist/src/renders/observe.js.map +1 -1
- package/dist/src/renders/render.wrapper.d.ts +37 -0
- package/dist/src/renders/render.wrapper.js +147 -0
- package/dist/src/renders/render.wrapper.js.map +1 -0
- package/dist/src/templating/eta.js +1 -4
- package/dist/src/templating/eta.js.map +1 -1
- package/package.json +4 -5
- package/dist/src/actions/action.button.d.ts +0 -2
- package/dist/src/actions/action.button.js +0 -8
- package/dist/src/actions/action.button.js.map +0 -1
- package/dist/src/actions/action.input.d.ts +0 -2
- package/dist/src/actions/action.input.js +0 -43
- package/dist/src/actions/action.input.js.map +0 -1
- package/dist/src/actions/action.select.d.ts +0 -2
- package/dist/src/actions/action.select.js +0 -14
- package/dist/src/actions/action.select.js.map +0 -1
- package/dist/src/actions/utilty.d.ts +0 -16
- package/dist/src/actions/utilty.js +0 -149
- package/dist/src/actions/utilty.js.map +0 -1
- package/dist/src/contexts/context.datalayer.d.ts +0 -9
- package/dist/src/contexts/context.datalayer.js +0 -3
- package/dist/src/contexts/context.datalayer.js.map +0 -1
- package/dist/src/contexts/context.derived.d.ts +0 -12
- package/dist/src/contexts/context.derived.js +0 -3
- package/dist/src/contexts/context.derived.js.map +0 -1
- package/dist/src/contexts/context.option.d.ts +0 -5
- package/dist/src/contexts/context.option.js +0 -3
- package/dist/src/contexts/context.option.js.map +0 -1
- package/dist/src/contexts/context.product.d.ts +0 -5
- package/dist/src/contexts/context.product.js +0 -3
- package/dist/src/contexts/context.product.js.map +0 -1
- package/dist/src/contexts/context.state.d.ts +0 -28
- package/dist/src/contexts/context.state.js +0 -3
- package/dist/src/contexts/context.state.js.map +0 -1
- package/dist/src/contexts/context.store.d.ts +0 -5
- package/dist/src/contexts/context.store.js +0 -3
- package/dist/src/contexts/context.store.js.map +0 -1
- package/dist/src/controllers/collect-controller.d.ts +0 -39
- package/dist/src/controllers/collect-controller.js +0 -161
- package/dist/src/controllers/collect-controller.js.map +0 -1
- package/dist/src/controllers/compute-controller.d.ts +0 -55
- package/dist/src/controllers/compute-controller.js +0 -350
- package/dist/src/controllers/compute-controller.js.map +0 -1
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.d.ts +0 -25
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.js +0 -192
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.js.map +0 -1
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.d.ts +0 -28
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.js +0 -206
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.js.map +0 -1
- package/dist/src/controllers/eta-renderer/eta-renderer.d.ts +0 -21
- package/dist/src/controllers/eta-renderer/eta-renderer.js +0 -77
- package/dist/src/controllers/eta-renderer/eta-renderer.js.map +0 -1
- package/dist/src/controllers/eta-renderer/eta-template-cache.d.ts +0 -24
- package/dist/src/controllers/eta-renderer/eta-template-cache.js +0 -61
- package/dist/src/controllers/eta-renderer/eta-template-cache.js.map +0 -1
- package/dist/src/controllers/eta-renderer/eta-types.d.ts +0 -11
- package/dist/src/controllers/eta-renderer/eta-types.js +0 -1
- package/dist/src/controllers/eta-renderer/eta-types.js.map +0 -1
- package/dist/src/controllers/eta-renderer/index.d.ts +0 -2
- package/dist/src/controllers/eta-renderer/index.js +0 -2
- package/dist/src/controllers/eta-renderer/index.js.map +0 -1
- package/dist/src/controllers/event-pipeline-controller.d.ts +0 -28
- package/dist/src/controllers/event-pipeline-controller.js +0 -72
- package/dist/src/controllers/event-pipeline-controller.js.map +0 -1
- package/dist/src/events/events.d.ts +0 -75
- package/dist/src/events/events.js +0 -78
- package/dist/src/events/events.js.map +0 -1
- package/dist/src/nodes/node.root.d.ts +0 -16
- package/dist/src/nodes/node.root.js +0 -49
- package/dist/src/nodes/node.root.js.map +0 -1
- package/dist/src/nodes/node.state.d.ts +0 -88
- package/dist/src/nodes/node.state.js +0 -330
- package/dist/src/nodes/node.state.js.map +0 -1
- package/dist/src/renders/utility.d.ts +0 -32
- package/dist/src/renders/utility.js +0 -191
- package/dist/src/renders/utility.js.map +0 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// src/compute/compute.scan.ts
|
|
2
|
+
import { isActionElement, readBdActionCommand, readInputValueCommand } from '../actions/action.attributes.js';
|
|
3
|
+
export const DATA_DEVICES_DOMAIN = 'data-store-devices';
|
|
4
|
+
export const DATA_SUBSCRIPTION_DOMAIN = 'data-store-subscription';
|
|
5
|
+
export const EMPTY_COMPUTE_SCAN = Object.freeze({
|
|
6
|
+
staticCommands: Object.freeze([]),
|
|
7
|
+
domains: Object.freeze([])
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Stable fingerprint of the declared seeds. Used as a compute task arg so the
|
|
11
|
+
* controller only reruns when the declared seed set actually changes, not on
|
|
12
|
+
* every host update.
|
|
13
|
+
*/
|
|
14
|
+
export function seedDeclarationsKey(seeds) {
|
|
15
|
+
return seeds
|
|
16
|
+
.map((seed) => [
|
|
17
|
+
seed.productId,
|
|
18
|
+
seed.campaign ?? '',
|
|
19
|
+
seed.bundle ? '1' : '0',
|
|
20
|
+
seed.devices,
|
|
21
|
+
seed.subscription
|
|
22
|
+
].join('|'))
|
|
23
|
+
.sort()
|
|
24
|
+
.join(';');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Turn the action elements owned by a compute boundary into static commands and
|
|
28
|
+
* dynamic domains. Reuses the same parser as the runtime action layer; the only
|
|
29
|
+
* difference is breadth: a select contributes all of its option children here,
|
|
30
|
+
* not just the selected one.
|
|
31
|
+
*/
|
|
32
|
+
export function scanActionElements(elements) {
|
|
33
|
+
const staticCommands = [];
|
|
34
|
+
const domains = [];
|
|
35
|
+
for (const element of elements) {
|
|
36
|
+
const scan = collectActionElementCompute(element);
|
|
37
|
+
staticCommands.push(...scan.staticCommands);
|
|
38
|
+
domains.push(...scan.domains);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
staticCommands,
|
|
42
|
+
domains
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function collectActionElementCompute(element) {
|
|
46
|
+
const domain = readComputeDomain(element);
|
|
47
|
+
if (domain) {
|
|
48
|
+
return {
|
|
49
|
+
staticCommands: [],
|
|
50
|
+
domains: [domain]
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (element instanceof HTMLSelectElement) {
|
|
54
|
+
const staticCommands = [];
|
|
55
|
+
collectSelectCommands(element, staticCommands);
|
|
56
|
+
return {
|
|
57
|
+
staticCommands,
|
|
58
|
+
domains: []
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const command = element instanceof HTMLInputElement
|
|
62
|
+
? readInputActionCommand(element)
|
|
63
|
+
: readBdActionCommand(element);
|
|
64
|
+
if (!command) {
|
|
65
|
+
return EMPTY_COMPUTE_SCAN;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
staticCommands: [command],
|
|
69
|
+
domains: []
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function mergeComputeScans(scans) {
|
|
73
|
+
const staticCommands = [];
|
|
74
|
+
const domains = [];
|
|
75
|
+
for (const scan of scans) {
|
|
76
|
+
staticCommands.push(...scan.staticCommands);
|
|
77
|
+
domains.push(...scan.domains);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
staticCommands,
|
|
81
|
+
domains
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* A select / control is a dynamic domain only when it is actionable AND tagged
|
|
86
|
+
* as a devices or subscription dimension. A plain `data-store-devices` span just
|
|
87
|
+
* renders the current value and contributes nothing to compute.
|
|
88
|
+
*/
|
|
89
|
+
export function readComputeDomain(element) {
|
|
90
|
+
if (!isActionElement(element)) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
if (element instanceof HTMLInputElement &&
|
|
94
|
+
(element.type === 'number' ||
|
|
95
|
+
element.type === 'text')) {
|
|
96
|
+
return readInputComputeDomain(element);
|
|
97
|
+
}
|
|
98
|
+
if (element.hasAttribute(DATA_DEVICES_DOMAIN)) {
|
|
99
|
+
return {
|
|
100
|
+
type: 'devices'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (element.hasAttribute(DATA_SUBSCRIPTION_DOMAIN)) {
|
|
104
|
+
return {
|
|
105
|
+
type: 'subscription'
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
function readInputComputeDomain(input) {
|
|
111
|
+
const command = readBdActionCommand(input);
|
|
112
|
+
if (command?.kind !== 'update-by-delta') {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
type: command.update.type,
|
|
117
|
+
min: toOptionalNumber(input.min) ?? command.update.min,
|
|
118
|
+
max: toOptionalNumber(input.max) ?? command.update.max
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function readInputActionCommand(input) {
|
|
122
|
+
switch (input.type) {
|
|
123
|
+
case 'number':
|
|
124
|
+
case 'text':
|
|
125
|
+
return readInputValueCommand(input);
|
|
126
|
+
default:
|
|
127
|
+
return readBdActionCommand(input);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function collectSelectCommands(select, out) {
|
|
131
|
+
let collected = false;
|
|
132
|
+
for (const option of Array.from(select.options)) {
|
|
133
|
+
const command = readBdActionCommand(option);
|
|
134
|
+
if (command) {
|
|
135
|
+
out.push(command);
|
|
136
|
+
collected = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (collected) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const command = readBdActionCommand(select);
|
|
143
|
+
if (command?.kind === 'set-action') {
|
|
144
|
+
out.push(command);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function toOptionalNumber(value) {
|
|
148
|
+
if (value === undefined) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
const trimmed = value.trim();
|
|
152
|
+
if (!trimmed) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
const parsed = Number(trimmed);
|
|
156
|
+
return Number.isNaN(parsed)
|
|
157
|
+
? undefined
|
|
158
|
+
: parsed;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=compute.scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute.scan.js","sourceRoot":"","sources":["../../../src/compute/compute.scan.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AAGxC,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAA6B,CAAC;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,yBAAkC,CAAC;AAmC3E,MAAM,CAAC,MAAM,kBAAkB,GAAkB,MAAM,CAAC,MAAM,CAAC;IAC7D,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACjC,OAAO,EAAS,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;CAClC,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAmC;IAEnC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ;QACE,IAAI,CAAC,SAAS;QACd,IAAI,CAAC,QAAQ,IAAI,EAAE;QACnB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;QACvB,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,YAAY;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ;SACA,IAAI,EAAE;SACN,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA+B;IAE/B,MAAM,cAAc,GAAsB,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAElD,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,OAAO;QACL,cAAc;QACd,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,OAAoB;IAEpB,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE1C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO;YACL,cAAc,EAAE,EAAE;YAClB,OAAO,EAAS,CAAC,MAAM,CAAC;SACzB,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,YAAY,iBAAiB,EAAE,CAAC;QACzC,MAAM,cAAc,GAAsB,EAAE,CAAC;QAE7C,qBAAqB,CACnB,OAAO,EACP,cAAc,CACf,CAAC;QAEF,OAAO;YACL,cAAc;YACd,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GACX,OAAO,YAAY,gBAAgB;QACjC,CAAC,CAAC,sBAAsB,CAAC,OAAO,CAAC;QACjC,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,cAAc,EAAE,CAAC,OAAO,CAAC;QACzB,OAAO,EAAS,EAAE;KACnB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAA8B;IAE9B,MAAM,cAAc,GAAsB,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,OAAO;QACL,cAAc;QACd,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAoB;IAEpB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IACE,OAAO,YAAY,gBAAgB;QACnC,CACE,OAAO,CAAC,IAAI,KAAK,QAAQ;YACzB,OAAO,CAAC,IAAI,KAAK,MAAM,CACxB,EACD,CAAC;QACD,OAAO,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC9C,OAAO;YACL,IAAI,EAAE,SAAS;SAChB,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,CAAC,wBAAwB,CAAC,EAAE,CAAC;QACnD,OAAO;YACL,IAAI,EAAE,cAAc;SACrB,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAuB;IAEvB,MAAM,OAAO,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAE3C,IAAI,OAAO,EAAE,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI;QACzB,GAAG,EAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG;QACvD,GAAG,EAAG,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAuB;IAEvB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACT,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAEtC;YACE,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAC5B,MAAyB,EACzB,GAAsB;IAEtB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAE5C,IAAI,OAAO,EAAE,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE5C,IAAI,OAAO,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;QACnC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CACvB,KAAyB;IAEzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAE/B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;QACzB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,MAAM,CAAC;AACb,CAAC","sourcesContent":["// src/compute/compute.scan.ts\n\nimport {\n isActionElement,\n readBdActionCommand,\n readInputValueCommand\n} from '@/actions/action.attributes.js';\nimport type { BdActionCommand } from '@/core/actions.js';\n\nexport const DATA_DEVICES_DOMAIN = 'data-store-devices' as const;\nexport const DATA_SUBSCRIPTION_DOMAIN = 'data-store-subscription' as const;\n\nexport type BdActionDomainKind = 'devices' | 'subscription';\n\nexport type BdActionDomain = Readonly<{\n type: BdActionDomainKind;\n min?: number;\n max?: number;\n}>;\n\n/**\n * A declarative seed scenario used by standalone compute helpers. Live node\n * compute uses resolved ProductOption seeds collected from option nodes.\n */\nexport type BdSeedDeclaration = Readonly<{\n productId : string;\n campaign? : string;\n bundle : boolean;\n devices : number;\n subscription: number;\n}>;\n\n/**\n * Result of scanning the action elements owned by a compute boundary.\n *\n * - staticCommands: concrete jumps (button says product-b, option says\n * subscription=24, select option children, etc).\n * - domains: controls that represent a devices / subscription space of\n * whatever product a scenario lands on. Inputs may bound that space by min/max.\n */\nexport type BdComputeScan = Readonly<{\n staticCommands: readonly BdActionCommand[];\n domains : readonly BdActionDomain[];\n}>;\n\nexport const EMPTY_COMPUTE_SCAN: BdComputeScan = Object.freeze({\n staticCommands: Object.freeze([]),\n domains : Object.freeze([])\n});\n\n/**\n * Stable fingerprint of the declared seeds. Used as a compute task arg so the\n * controller only reruns when the declared seed set actually changes, not on\n * every host update.\n */\nexport function seedDeclarationsKey(\n seeds: readonly BdSeedDeclaration[]\n): string {\n return seeds\n .map((seed) =>\n [\n seed.productId,\n seed.campaign ?? '',\n seed.bundle ? '1' : '0',\n seed.devices,\n seed.subscription\n ].join('|')\n )\n .sort()\n .join(';');\n}\n\n/**\n * Turn the action elements owned by a compute boundary into static commands and\n * dynamic domains. Reuses the same parser as the runtime action layer; the only\n * difference is breadth: a select contributes all of its option children here,\n * not just the selected one.\n */\nexport function scanActionElements(\n elements: Iterable<HTMLElement>\n): BdComputeScan {\n const staticCommands: BdActionCommand[] = [];\n const domains: BdActionDomain[] = [];\n\n for (const element of elements) {\n const scan = collectActionElementCompute(element);\n\n staticCommands.push(...scan.staticCommands);\n domains.push(...scan.domains);\n }\n\n return {\n staticCommands,\n domains\n };\n}\n\nexport function collectActionElementCompute(\n element: HTMLElement\n): BdComputeScan {\n const domain = readComputeDomain(element);\n\n if (domain) {\n return {\n staticCommands: [],\n domains : [domain]\n };\n }\n\n if (element instanceof HTMLSelectElement) {\n const staticCommands: BdActionCommand[] = [];\n\n collectSelectCommands(\n element,\n staticCommands\n );\n\n return {\n staticCommands,\n domains: []\n };\n }\n\n const command =\n element instanceof HTMLInputElement\n ? readInputActionCommand(element)\n : readBdActionCommand(element);\n\n if (!command) {\n return EMPTY_COMPUTE_SCAN;\n }\n\n return {\n staticCommands: [command],\n domains : []\n };\n}\n\nexport function mergeComputeScans(\n scans: Iterable<BdComputeScan>\n): BdComputeScan {\n const staticCommands: BdActionCommand[] = [];\n const domains: BdActionDomain[] = [];\n\n for (const scan of scans) {\n staticCommands.push(...scan.staticCommands);\n domains.push(...scan.domains);\n }\n\n return {\n staticCommands,\n domains\n };\n}\n\n/**\n * A select / control is a dynamic domain only when it is actionable AND tagged\n * as a devices or subscription dimension. A plain `data-store-devices` span just\n * renders the current value and contributes nothing to compute.\n */\nexport function readComputeDomain(\n element: HTMLElement\n): BdActionDomain | undefined {\n if (!isActionElement(element)) {\n return undefined;\n }\n\n if (\n element instanceof HTMLInputElement &&\n (\n element.type === 'number' ||\n element.type === 'text'\n )\n ) {\n return readInputComputeDomain(element);\n }\n\n if (element.hasAttribute(DATA_DEVICES_DOMAIN)) {\n return {\n type: 'devices'\n };\n }\n\n if (element.hasAttribute(DATA_SUBSCRIPTION_DOMAIN)) {\n return {\n type: 'subscription'\n };\n }\n\n return undefined;\n}\n\nfunction readInputComputeDomain(\n input: HTMLInputElement\n): BdActionDomain | undefined {\n const command = readBdActionCommand(input);\n\n if (command?.kind !== 'update-by-delta') {\n return undefined;\n }\n\n return {\n type: command.update.type,\n min : toOptionalNumber(input.min) ?? command.update.min,\n max : toOptionalNumber(input.max) ?? command.update.max\n };\n}\n\nfunction readInputActionCommand(\n input: HTMLInputElement\n): BdActionCommand | undefined {\n switch (input.type) {\n case 'number':\n case 'text':\n return readInputValueCommand(input);\n\n default:\n return readBdActionCommand(input);\n }\n}\n\nfunction collectSelectCommands(\n select: HTMLSelectElement,\n out: BdActionCommand[]\n): void {\n let collected = false;\n\n for (const option of Array.from(select.options)) {\n const command = readBdActionCommand(option);\n\n if (command) {\n out.push(command);\n collected = true;\n }\n }\n\n if (collected) {\n return;\n }\n\n const command = readBdActionCommand(select);\n\n if (command?.kind === 'set-action') {\n out.push(command);\n }\n}\n\nfunction toOptionalNumber(\n value: string | undefined\n): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n if (!trimmed) {\n return undefined;\n }\n\n const parsed = Number(trimmed);\n\n return Number.isNaN(parsed)\n ? undefined\n : parsed;\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BdActionCommand } from '../core/actions.js';
|
|
2
|
+
import type { Product, ProductOption, Store } from '@repobit/dex-store';
|
|
3
|
+
/**
|
|
4
|
+
* A single reachable point in the product/option space: a resolved product and
|
|
5
|
+
* one of its resolved options. Both the runtime OptionNode and the dry-run
|
|
6
|
+
* compute layer reduce over these.
|
|
7
|
+
*/
|
|
8
|
+
export type BdOptionScenario = Readonly<{
|
|
9
|
+
product: Product;
|
|
10
|
+
option: ProductOption;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Stable identity for a scenario, used to deduplicate the fixed-point search so
|
|
14
|
+
* it terminates. Includes the product, the option dimensions, and any bundle
|
|
15
|
+
* members (a bundle changes price even when dimensions match).
|
|
16
|
+
*/
|
|
17
|
+
export declare function scenarioKey(scenario: BdOptionScenario): string;
|
|
18
|
+
/**
|
|
19
|
+
* Apply one action command to a scenario as a pure dry-run and return the
|
|
20
|
+
* resulting scenario, or undefined when the command does not lead anywhere
|
|
21
|
+
* reachable (missing product/option, missing store for a cross-product jump).
|
|
22
|
+
*
|
|
23
|
+
* This mirrors the runtime semantics split across ProductNode (id / campaign /
|
|
24
|
+
* bundle) and OptionNode (devices / subscription), collapsed into a single
|
|
25
|
+
* step because compute operates on flat commands rather than the node tree.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveScenarioCommand(params: Readonly<{
|
|
28
|
+
store?: Store;
|
|
29
|
+
scenario: BdOptionScenario;
|
|
30
|
+
command: BdActionCommand;
|
|
31
|
+
}>): Promise<BdOptionScenario | undefined>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// src/compute/option-resolver.ts
|
|
2
|
+
import { applyOptionUpdate } from '../core/option-update.js';
|
|
3
|
+
/**
|
|
4
|
+
* Stable identity for a scenario, used to deduplicate the fixed-point search so
|
|
5
|
+
* it terminates. Includes the product, the option dimensions, and any bundle
|
|
6
|
+
* members (a bundle changes price even when dimensions match).
|
|
7
|
+
*/
|
|
8
|
+
export function scenarioKey(scenario) {
|
|
9
|
+
return productOptionKey(scenario.option);
|
|
10
|
+
}
|
|
11
|
+
function productOptionKey(option) {
|
|
12
|
+
const product = option.getProduct();
|
|
13
|
+
const bundleKey = option
|
|
14
|
+
.getBundle()
|
|
15
|
+
.map((member) => [
|
|
16
|
+
member.devicesFixed ? '1' : '0',
|
|
17
|
+
member.subscriptionFixed ? '1' : '0',
|
|
18
|
+
productOptionKey(member.option)
|
|
19
|
+
].join(':'))
|
|
20
|
+
.sort()
|
|
21
|
+
.join(',');
|
|
22
|
+
return [
|
|
23
|
+
product.getId(),
|
|
24
|
+
product.getCampaign() ?? '',
|
|
25
|
+
option.getDevices(),
|
|
26
|
+
option.getSubscription(),
|
|
27
|
+
bundleKey
|
|
28
|
+
].join('|');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Apply one action command to a scenario as a pure dry-run and return the
|
|
32
|
+
* resulting scenario, or undefined when the command does not lead anywhere
|
|
33
|
+
* reachable (missing product/option, missing store for a cross-product jump).
|
|
34
|
+
*
|
|
35
|
+
* This mirrors the runtime semantics split across ProductNode (id / campaign /
|
|
36
|
+
* bundle) and OptionNode (devices / subscription), collapsed into a single
|
|
37
|
+
* step because compute operates on flat commands rather than the node tree.
|
|
38
|
+
*/
|
|
39
|
+
export async function resolveScenarioCommand(params) {
|
|
40
|
+
if (params.command.kind === 'set-action') {
|
|
41
|
+
return await resolveSetActionScenario(params.store, params.scenario, params.command.action);
|
|
42
|
+
}
|
|
43
|
+
return await resolveDeltaScenario(params.scenario, params.command.update);
|
|
44
|
+
}
|
|
45
|
+
async function resolveSetActionScenario(store, scenario, action) {
|
|
46
|
+
const targetProduct = await resolveTargetProduct(store, scenario.product, action);
|
|
47
|
+
if (!targetProduct) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const devices = action.devices ?? scenario.option.getDevices();
|
|
51
|
+
const subscription = action.subscription ?? scenario.option.getSubscription();
|
|
52
|
+
if (action.bundle && action.id) {
|
|
53
|
+
return await resolveBundleScenario({
|
|
54
|
+
store,
|
|
55
|
+
scenario,
|
|
56
|
+
targetProduct,
|
|
57
|
+
action,
|
|
58
|
+
devices,
|
|
59
|
+
subscription
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const option = await targetProduct.getOption({
|
|
63
|
+
devices,
|
|
64
|
+
subscription
|
|
65
|
+
});
|
|
66
|
+
if (!option) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
product: targetProduct,
|
|
71
|
+
option
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function resolveTargetProduct(store, currentProduct, action) {
|
|
75
|
+
if (action.id) {
|
|
76
|
+
if (!store) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return await store.getProduct({
|
|
80
|
+
id: action.id,
|
|
81
|
+
campaign: action.campaign
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (action.campaign !== undefined &&
|
|
85
|
+
action.campaign !== currentProduct.getCampaign()) {
|
|
86
|
+
if (!store) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return (await store.getProduct({
|
|
90
|
+
id: currentProduct.getId(),
|
|
91
|
+
campaign: action.campaign
|
|
92
|
+
})) ?? currentProduct;
|
|
93
|
+
}
|
|
94
|
+
return currentProduct;
|
|
95
|
+
}
|
|
96
|
+
async function resolveBundleScenario(params) {
|
|
97
|
+
const { store, scenario, action } = params;
|
|
98
|
+
if (!store || !action.id) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
const bundleProduct = await store.getProduct({
|
|
102
|
+
id: action.id,
|
|
103
|
+
campaign: action.campaign
|
|
104
|
+
});
|
|
105
|
+
if (!bundleProduct) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
const bundleOption = await bundleProduct.getOption({
|
|
109
|
+
devices: action.devices ?? scenario.option.getDevices(),
|
|
110
|
+
subscription: action.subscription ?? scenario.option.getSubscription()
|
|
111
|
+
});
|
|
112
|
+
if (!bundleOption) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const bundled = await scenario.option.toogleBundle({
|
|
116
|
+
option: bundleOption,
|
|
117
|
+
devicesFixed: action.devices !== undefined,
|
|
118
|
+
subscriptionFixed: action.subscription !== undefined
|
|
119
|
+
});
|
|
120
|
+
if (!bundled) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
product: bundled.getProduct(),
|
|
125
|
+
option: bundled
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async function resolveDeltaScenario(scenario, update) {
|
|
129
|
+
const devices = applyOptionUpdate('devices', scenario.option.getDevices(), update, scenario.product);
|
|
130
|
+
const subscription = applyOptionUpdate('subscription', scenario.option.getSubscription(), update, scenario.product);
|
|
131
|
+
if (typeof devices !== 'number' ||
|
|
132
|
+
typeof subscription !== 'number') {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const option = await scenario.product.getOption({
|
|
136
|
+
devices,
|
|
137
|
+
subscription
|
|
138
|
+
});
|
|
139
|
+
if (!option) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
product: scenario.product,
|
|
144
|
+
option
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=option-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"option-resolver.js","sourceRoot":"","sources":["../../../src/compute/option-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["// src/compute/option-resolver.ts\n\nimport type {\n Action,\n BdActionCommand,\n UpdateByDelta\n} from '@/core/actions.js';\nimport { applyOptionUpdate } from '@/core/option-update.js';\nimport type {\n Product,\n ProductOption,\n Store\n} from '@repobit/dex-store';\n\n/**\n * A single reachable point in the product/option space: a resolved product and\n * one of its resolved options. Both the runtime OptionNode and the dry-run\n * compute layer reduce over these.\n */\nexport type BdOptionScenario = Readonly<{\n product: Product;\n option : ProductOption;\n}>;\n\n/**\n * Stable identity for a scenario, used to deduplicate the fixed-point search so\n * it terminates. Includes the product, the option dimensions, and any bundle\n * members (a bundle changes price even when dimensions match).\n */\nexport function scenarioKey(\n scenario: BdOptionScenario\n): string {\n return productOptionKey(scenario.option);\n}\n\nfunction productOptionKey(\n option: ProductOption\n): string {\n const product = option.getProduct();\n const bundleKey =\n option\n .getBundle()\n .map((member) =>\n [\n member.devicesFixed ? '1' : '0',\n member.subscriptionFixed ? '1' : '0',\n productOptionKey(member.option)\n ].join(':')\n )\n .sort()\n .join(',');\n\n return [\n product.getId(),\n product.getCampaign() ?? '',\n option.getDevices(),\n option.getSubscription(),\n bundleKey\n ].join('|');\n}\n\n/**\n * Apply one action command to a scenario as a pure dry-run and return the\n * resulting scenario, or undefined when the command does not lead anywhere\n * reachable (missing product/option, missing store for a cross-product jump).\n *\n * This mirrors the runtime semantics split across ProductNode (id / campaign /\n * bundle) and OptionNode (devices / subscription), collapsed into a single\n * step because compute operates on flat commands rather than the node tree.\n */\nexport async function resolveScenarioCommand(\n params: Readonly<{\n store? : Store;\n scenario: BdOptionScenario;\n command : BdActionCommand;\n }>\n): Promise<BdOptionScenario | undefined> {\n if (params.command.kind === 'set-action') {\n return await resolveSetActionScenario(\n params.store,\n params.scenario,\n params.command.action\n );\n }\n\n return await resolveDeltaScenario(\n params.scenario,\n params.command.update\n );\n}\n\nasync function resolveSetActionScenario(\n store: Store | undefined,\n scenario: BdOptionScenario,\n action: Action\n): Promise<BdOptionScenario | undefined> {\n const targetProduct =\n await resolveTargetProduct(\n store,\n scenario.product,\n action\n );\n\n if (!targetProduct) {\n return undefined;\n }\n\n const devices =\n action.devices ?? scenario.option.getDevices();\n\n const subscription =\n action.subscription ?? scenario.option.getSubscription();\n\n if (action.bundle && action.id) {\n return await resolveBundleScenario({\n store,\n scenario,\n targetProduct,\n action,\n devices,\n subscription\n });\n }\n\n const option =\n await targetProduct.getOption({\n devices,\n subscription\n });\n\n if (!option) {\n return undefined;\n }\n\n return {\n product: targetProduct,\n option\n };\n}\n\nasync function resolveTargetProduct(\n store: Store | undefined,\n currentProduct: Product,\n action: Action\n): Promise<Product | undefined> {\n if (action.id) {\n if (!store) {\n return undefined;\n }\n\n return await store.getProduct({\n id : action.id,\n campaign: action.campaign\n });\n }\n\n if (\n action.campaign !== undefined &&\n action.campaign !== currentProduct.getCampaign()\n ) {\n if (!store) {\n return undefined;\n }\n\n return (\n await store.getProduct({\n id : currentProduct.getId(),\n campaign: action.campaign\n })\n ) ?? currentProduct;\n }\n\n return currentProduct;\n}\n\nasync function resolveBundleScenario(\n params: Readonly<{\n store? : Store;\n scenario : BdOptionScenario;\n targetProduct: Product;\n action : Action;\n devices : number;\n subscription : number;\n }>\n): Promise<BdOptionScenario | undefined> {\n const { store, scenario, action } = params;\n\n if (!store || !action.id) {\n return undefined;\n }\n\n const bundleProduct =\n await store.getProduct({\n id : action.id,\n campaign: action.campaign\n });\n\n if (!bundleProduct) {\n return undefined;\n }\n\n const bundleOption =\n await bundleProduct.getOption({\n devices : action.devices ?? scenario.option.getDevices(),\n subscription: action.subscription ?? scenario.option.getSubscription()\n });\n\n if (!bundleOption) {\n return undefined;\n }\n\n const bundled =\n await scenario.option.toogleBundle({\n option : bundleOption,\n devicesFixed : action.devices !== undefined,\n subscriptionFixed: action.subscription !== undefined\n });\n\n if (!bundled) {\n return undefined;\n }\n\n return {\n product: bundled.getProduct(),\n option : bundled\n };\n}\n\nasync function resolveDeltaScenario(\n scenario: BdOptionScenario,\n update: UpdateByDelta\n): Promise<BdOptionScenario | undefined> {\n const devices =\n applyOptionUpdate(\n 'devices',\n scenario.option.getDevices(),\n update,\n scenario.product\n );\n\n const subscription =\n applyOptionUpdate(\n 'subscription',\n scenario.option.getSubscription(),\n update,\n scenario.product\n );\n\n if (\n typeof devices !== 'number' ||\n typeof subscription !== 'number'\n ) {\n return undefined;\n }\n\n const option =\n await scenario.product.getOption({\n devices,\n subscription\n });\n\n if (!option) {\n return undefined;\n }\n\n return {\n product: scenario.product,\n option\n };\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const bdComputeContext: {
|
|
2
|
+
__context__: Readonly<{
|
|
3
|
+
min: number;
|
|
4
|
+
max: number;
|
|
5
|
+
minFormatted: string;
|
|
6
|
+
maxFormatted: string;
|
|
7
|
+
scenarios: number;
|
|
8
|
+
price: import("../compute/compute.expand.js").BdComputeMonthlyRange;
|
|
9
|
+
discountedPrice: import("../compute/compute.expand.js").BdComputeMonthlyRange;
|
|
10
|
+
discount: import("../compute/compute.expand.js").BdComputeDiscountRange;
|
|
11
|
+
}> | undefined;
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.compute.js","sourceRoot":"","sources":["../../../src/contexts/context.compute.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,CAAC,MAAM,gBAAgB,GAC3B,aAAa,CACX,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CACjC,CAAC","sourcesContent":["// src/contexts/context.compute.ts\n\nimport { createContext } from '@lit/context';\n\nimport type { BdComputeResult } from '@/compute/compute.expand.js';\n\nexport const bdComputeContext =\n createContext<BdComputeResult | undefined>(\n Symbol.for('bd-compute-context')\n );"]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { BdComputeResult } from '../compute/compute.expand.js';
|
|
2
|
+
import type { BdTransition } from '../core/actions.js';
|
|
3
|
+
import type { EtaMutationBatchSchedule } from '../eta/types.js';
|
|
4
|
+
import type { Product, ProductOption, Store } from '@repobit/dex-store';
|
|
5
|
+
/**
|
|
6
|
+
* Shape that `derived(scope, compute)` callbacks receive.
|
|
7
|
+
*
|
|
8
|
+
* The four fields mirror `BdScopedTemplateContext`. A `derived`
|
|
9
|
+
* factory reads from this input and returns a new object whose
|
|
10
|
+
* properties are exposed to templates under the `derived` key.
|
|
11
|
+
*/
|
|
12
|
+
export type BdScopeDerivationInput = Readonly<{
|
|
13
|
+
store: Store | undefined;
|
|
14
|
+
product: Product | undefined;
|
|
15
|
+
option: ProductOption | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Result shape of a `derived` factory.
|
|
19
|
+
*
|
|
20
|
+
* Returned object is shallow-merged into the Eta context under
|
|
21
|
+
* the `derived` key, so templates can write `<%= it.derived.foo %>`
|
|
22
|
+
* instead of pulling each derived value into the top-level scope.
|
|
23
|
+
*
|
|
24
|
+
* The default is `unknown` to allow flexible per-scope shapes; a
|
|
25
|
+
* concrete node can narrow it locally via a typed wrapper.
|
|
26
|
+
*/
|
|
27
|
+
export type BdScopeDerived = Readonly<Record<string, unknown>>;
|
|
28
|
+
/**
|
|
29
|
+
* Pure function that derives additional Eta template context
|
|
30
|
+
* from the current scope and compute result.
|
|
31
|
+
*
|
|
32
|
+
* The function MUST be pure — it is invoked synchronously inside
|
|
33
|
+
* `EtaTemplateController`'s `context` callback on every render.
|
|
34
|
+
* The same `store` / `product` / `option` identity arguments
|
|
35
|
+
* produce the same output (by reference) so the `@lit/task` args
|
|
36
|
+
* tuple can short-circuit re-renders.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* const scope: BdScope = {
|
|
42
|
+
* ...createBdStoreScope(store),
|
|
43
|
+
* derived: ({ store, product, option }) => ({
|
|
44
|
+
* hasProduct: Boolean(product),
|
|
45
|
+
* canBuy : Boolean(store && product && option)
|
|
46
|
+
* })
|
|
47
|
+
* };
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export type BdScopeDeriveFn = (scope: BdScopeDerivationInput) => BdScopeDerived;
|
|
51
|
+
/**
|
|
52
|
+
* Snapshot delivered to `BdScope.onScopeChange` callbacks.
|
|
53
|
+
*
|
|
54
|
+
* Intentionally narrow — the hook fires when the published
|
|
55
|
+
* scope of a `BdScopedElement` changes, but consumers should
|
|
56
|
+
* only need the fields that drive template rendering. Adding a
|
|
57
|
+
* new field here is a public surface change (every consumer can
|
|
58
|
+
* read it), so prefer extending `BdScope` and rebinding this
|
|
59
|
+
* snapshot rather than spreading the full scope.
|
|
60
|
+
*
|
|
61
|
+
* `state` carries the current compute result for the scope;
|
|
62
|
+
* `undefined` when compute is disabled or has not run yet.
|
|
63
|
+
*/
|
|
64
|
+
export type BdScopeChangeSnapshot = Readonly<{
|
|
65
|
+
store: Store | undefined;
|
|
66
|
+
product: Product | undefined;
|
|
67
|
+
option: ProductOption | undefined;
|
|
68
|
+
state: BdComputeResult | undefined;
|
|
69
|
+
}>;
|
|
70
|
+
/**
|
|
71
|
+
* Callback fired when the published scope of a
|
|
72
|
+
* `BdScopedElement` changes.
|
|
73
|
+
*
|
|
74
|
+
* Invoked from `BdScopedElement.publishScope(...)` when the
|
|
75
|
+
* normalized published scope reference actually changes, and
|
|
76
|
+
* from `BdScopedElement.clearScope()` with all-undefined fields
|
|
77
|
+
* when the scope is cleared. The hook receives the new
|
|
78
|
+
* snapshot — it does NOT need to read the scope itself.
|
|
79
|
+
*
|
|
80
|
+
* The hook is stored on the published scope (`BdScope.onScopeChange`)
|
|
81
|
+
* so it cascades to descendants via `parentScope.onScopeChange`.
|
|
82
|
+
* Descendants may override the inherited hook by supplying
|
|
83
|
+
* their own `onScopeChange` property.
|
|
84
|
+
*/
|
|
85
|
+
export type BdScopeChangeFn = (snapshot: BdScopeChangeSnapshot) => void;
|
|
86
|
+
export type BdDataLayerEvent = 'all' | 'info' | 'comparison' | (string & {});
|
|
87
|
+
export type BdDataLayerPayload = Readonly<{
|
|
88
|
+
option: ProductOption;
|
|
89
|
+
event: BdDataLayerEvent;
|
|
90
|
+
}>;
|
|
91
|
+
export type BdDataLayerFn = (payload: BdDataLayerPayload) => void;
|
|
92
|
+
export type BdScope = Readonly<Partial<{
|
|
93
|
+
store: Store;
|
|
94
|
+
product: Product;
|
|
95
|
+
option: ProductOption;
|
|
96
|
+
transition: BdTransition;
|
|
97
|
+
computeDisabled: boolean;
|
|
98
|
+
etaDisabled: boolean;
|
|
99
|
+
derived: BdScopeDeriveFn;
|
|
100
|
+
mutationBatchSchedule: EtaMutationBatchSchedule;
|
|
101
|
+
onScopeChange: BdScopeChangeFn;
|
|
102
|
+
dataLayer: BdDataLayerFn;
|
|
103
|
+
}>>;
|
|
104
|
+
/**
|
|
105
|
+
* Result of running `scope.derived(scope)` — exposed by helpers
|
|
106
|
+
* that want to apply the derivation outside the Eta context
|
|
107
|
+
* builder (e.g. tests, diagnostics).
|
|
108
|
+
*/
|
|
109
|
+
export type BdDerivedResult = BdScopeDerived;
|
|
110
|
+
export declare function createBdStoreScope(store: Store, transition?: BdTransition): BdScope;
|
|
111
|
+
export declare function extendBdContextScope(parentScope: BdScope, transition?: BdTransition): BdScope;
|
|
112
|
+
export declare function extendBdProductScope(parentScope: BdScope, product: Product, transition?: BdTransition): BdScope;
|
|
113
|
+
export declare function extendBdOptionScope(parentScope: BdScope, option: ProductOption, transition?: BdTransition): BdScope;
|
|
114
|
+
/**
|
|
115
|
+
* Invokes `scope.derived` when present, otherwise returns
|
|
116
|
+
* `undefined`.
|
|
117
|
+
*
|
|
118
|
+
* Exposed so non-Eta consumers (tests, diagnostics, future
|
|
119
|
+
* controllers) can reuse the same derivation rule without going
|
|
120
|
+
* through `EtaTemplateController`. Returning `undefined` when no
|
|
121
|
+
* `derived` is configured keeps the caller in charge of deciding
|
|
122
|
+
* what to do with the absence (omit the `derived` key vs.
|
|
123
|
+
* publish an empty object).
|
|
124
|
+
*/
|
|
125
|
+
export declare function runBdScopeDerived(scope: BdScope | undefined): BdDerivedResult | undefined;
|
|
126
|
+
export declare const bdScopeContext: {
|
|
127
|
+
__context__: Readonly<Partial<{
|
|
128
|
+
store: Store;
|
|
129
|
+
product: Product;
|
|
130
|
+
option: ProductOption;
|
|
131
|
+
transition: BdTransition;
|
|
132
|
+
computeDisabled: boolean;
|
|
133
|
+
etaDisabled: boolean;
|
|
134
|
+
derived: BdScopeDeriveFn;
|
|
135
|
+
mutationBatchSchedule: EtaMutationBatchSchedule;
|
|
136
|
+
onScopeChange: BdScopeChangeFn;
|
|
137
|
+
dataLayer: BdDataLayerFn;
|
|
138
|
+
}>> | undefined;
|
|
139
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createContext } from '@lit/context';
|
|
2
|
+
export function createBdStoreScope(store, transition) {
|
|
3
|
+
return {
|
|
4
|
+
store,
|
|
5
|
+
transition
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function extendBdContextScope(parentScope, transition) {
|
|
9
|
+
return {
|
|
10
|
+
...parentScope,
|
|
11
|
+
transition
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function extendBdProductScope(parentScope, product, transition) {
|
|
15
|
+
return {
|
|
16
|
+
...parentScope,
|
|
17
|
+
product,
|
|
18
|
+
option: undefined,
|
|
19
|
+
transition
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function extendBdOptionScope(parentScope, option, transition) {
|
|
23
|
+
return {
|
|
24
|
+
...parentScope,
|
|
25
|
+
option,
|
|
26
|
+
transition
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Invokes `scope.derived` when present, otherwise returns
|
|
31
|
+
* `undefined`.
|
|
32
|
+
*
|
|
33
|
+
* Exposed so non-Eta consumers (tests, diagnostics, future
|
|
34
|
+
* controllers) can reuse the same derivation rule without going
|
|
35
|
+
* through `EtaTemplateController`. Returning `undefined` when no
|
|
36
|
+
* `derived` is configured keeps the caller in charge of deciding
|
|
37
|
+
* what to do with the absence (omit the `derived` key vs.
|
|
38
|
+
* publish an empty object).
|
|
39
|
+
*/
|
|
40
|
+
export function runBdScopeDerived(scope) {
|
|
41
|
+
return scope?.derived?.({
|
|
42
|
+
store: scope.store,
|
|
43
|
+
product: scope.product,
|
|
44
|
+
option: scope.option
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export const bdScopeContext = createContext(Symbol.for('bd:scope'));
|
|
48
|
+
//# sourceMappingURL=context.scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.scope.js","sourceRoot":"","sources":["../../../src/contexts/context.scope.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgI7C,MAAM,UAAU,kBAAkB,CAChC,KAAY,EACZ,UAAyB;IAEzB,OAAO;QACL,KAAK;QACL,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,OAAgB,EAChB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,OAAO;QACP,MAAM,EAAE,SAAS;QACjB,UAAU;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,WAAoB,EACpB,MAAqB,EACrB,UAAyB;IAEzB,OAAO;QACL,GAAG,WAAW;QACd,MAAM;QACN,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA0B;IAE1B,OAAO,KAAK,EAAE,OAAO,EAAE,CAAC;QACtB,KAAK,EAAI,KAAK,CAAC,KAAK;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAG,KAAK,CAAC,MAAM;KACtB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GACzB,aAAa,CACX,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CACvB,CAAC","sourcesContent":["import type { BdComputeResult } from '@/compute/compute.expand.js';\nimport type { BdTransition } from '@/core/actions.js';\nimport type { EtaMutationBatchSchedule } from '@/eta/types.js';\nimport { createContext } from '@lit/context';\nimport type { Product, ProductOption, Store } from '@repobit/dex-store';\n\n/**\n * Shape that `derived(scope, compute)` callbacks receive.\n *\n * The four fields mirror `BdScopedTemplateContext`. A `derived`\n * factory reads from this input and returns a new object whose\n * properties are exposed to templates under the `derived` key.\n */\nexport type BdScopeDerivationInput = Readonly<{\n store : Store | undefined;\n product: Product | undefined;\n option : ProductOption | undefined;\n}>;\n\n/**\n * Result shape of a `derived` factory.\n *\n * Returned object is shallow-merged into the Eta context under\n * the `derived` key, so templates can write `<%= it.derived.foo %>`\n * instead of pulling each derived value into the top-level scope.\n *\n * The default is `unknown` to allow flexible per-scope shapes; a\n * concrete node can narrow it locally via a typed wrapper.\n */\nexport type BdScopeDerived = Readonly<Record<string, unknown>>;\n\n/**\n * Pure function that derives additional Eta template context\n * from the current scope and compute result.\n *\n * The function MUST be pure — it is invoked synchronously inside\n * `EtaTemplateController`'s `context` callback on every render.\n * The same `store` / `product` / `option` identity arguments\n * produce the same output (by reference) so the `@lit/task` args\n * tuple can short-circuit re-renders.\n *\n * @example\n *\n * ```ts\n * const scope: BdScope = {\n * ...createBdStoreScope(store),\n * derived: ({ store, product, option }) => ({\n * hasProduct: Boolean(product),\n * canBuy : Boolean(store && product && option)\n * })\n * };\n * ```\n */\nexport type BdScopeDeriveFn = (\n scope : BdScopeDerivationInput\n) => BdScopeDerived;\n\n/**\n * Snapshot delivered to `BdScope.onScopeChange` callbacks.\n *\n * Intentionally narrow — the hook fires when the published\n * scope of a `BdScopedElement` changes, but consumers should\n * only need the fields that drive template rendering. Adding a\n * new field here is a public surface change (every consumer can\n * read it), so prefer extending `BdScope` and rebinding this\n * snapshot rather than spreading the full scope.\n *\n * `state` carries the current compute result for the scope;\n * `undefined` when compute is disabled or has not run yet.\n */\nexport type BdScopeChangeSnapshot = Readonly<{\n store : Store | undefined;\n product: Product | undefined;\n option : ProductOption | undefined;\n state : BdComputeResult | undefined;\n}>;\n\n/**\n * Callback fired when the published scope of a\n * `BdScopedElement` changes.\n *\n * Invoked from `BdScopedElement.publishScope(...)` when the\n * normalized published scope reference actually changes, and\n * from `BdScopedElement.clearScope()` with all-undefined fields\n * when the scope is cleared. The hook receives the new\n * snapshot — it does NOT need to read the scope itself.\n *\n * The hook is stored on the published scope (`BdScope.onScopeChange`)\n * so it cascades to descendants via `parentScope.onScopeChange`.\n * Descendants may override the inherited hook by supplying\n * their own `onScopeChange` property.\n */\nexport type BdScopeChangeFn = (\n snapshot: BdScopeChangeSnapshot\n) => void;\n\nexport type BdDataLayerEvent =\n | 'all'\n | 'info'\n | 'comparison'\n | (string & {});\n\nexport type BdDataLayerPayload = Readonly<{\n option: ProductOption;\n event : BdDataLayerEvent;\n}>;\n\nexport type BdDataLayerFn = (\n payload: BdDataLayerPayload\n) => void;\n\nexport type BdScope = Readonly<Partial<{\n store : Store;\n product : Product;\n option : ProductOption;\n transition : BdTransition;\n computeDisabled : boolean;\n etaDisabled : boolean;\n derived : BdScopeDeriveFn;\n mutationBatchSchedule: EtaMutationBatchSchedule;\n onScopeChange : BdScopeChangeFn;\n dataLayer : BdDataLayerFn;\n}>>\n\n/**\n * Result of running `scope.derived(scope)` — exposed by helpers\n * that want to apply the derivation outside the Eta context\n * builder (e.g. tests, diagnostics).\n */\nexport type BdDerivedResult = BdScopeDerived;\n\nexport function createBdStoreScope(\n store: Store,\n transition?: BdTransition\n): BdScope {\n return {\n store,\n transition\n };\n}\n\nexport function extendBdContextScope(\n parentScope: BdScope,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n transition\n };\n}\n\nexport function extendBdProductScope(\n parentScope: BdScope,\n product: Product,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n product,\n option: undefined,\n transition\n };\n}\n\nexport function extendBdOptionScope(\n parentScope: BdScope,\n option: ProductOption,\n transition?: BdTransition\n): BdScope {\n return {\n ...parentScope,\n option,\n transition\n };\n}\n\n/**\n * Invokes `scope.derived` when present, otherwise returns\n * `undefined`.\n *\n * Exposed so non-Eta consumers (tests, diagnostics, future\n * controllers) can reuse the same derivation rule without going\n * through `EtaTemplateController`. Returning `undefined` when no\n * `derived` is configured keeps the caller in charge of deciding\n * what to do with the absence (omit the `derived` key vs.\n * publish an empty object).\n */\nexport function runBdScopeDerived(\n scope: BdScope | undefined\n): BdDerivedResult | undefined {\n return scope?.derived?.({\n store : scope.store,\n product: scope.product,\n option : scope.option\n });\n}\n\nexport const bdScopeContext =\n createContext<BdScope | undefined>(\n Symbol.for('bd:scope')\n );\n"]}
|