@repobit/dex-store-elements 1.4.2 → 1.4.4
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 +19 -0
- package/README.md +15 -4
- package/dist/src/actions/action.button.js +4 -11
- package/dist/src/actions/action.button.js.map +1 -1
- package/dist/src/actions/action.input.js +28 -22
- package/dist/src/actions/action.input.js.map +1 -1
- package/dist/src/actions/action.select.js +10 -8
- package/dist/src/actions/action.select.js.map +1 -1
- package/dist/src/actions/index.d.ts +1 -1
- package/dist/src/actions/index.js +45 -49
- package/dist/src/actions/index.js.map +1 -1
- package/dist/src/actions/utilty.d.ts +1 -0
- package/dist/src/actions/utilty.js +59 -29
- package/dist/src/actions/utilty.js.map +1 -1
- package/dist/src/contexts/context.datalayer.js.map +1 -1
- package/dist/src/contexts/context.derived.js.map +1 -1
- package/dist/src/contexts/context.option.js.map +1 -1
- package/dist/src/contexts/context.product.js.map +1 -1
- package/dist/src/contexts/context.state.js.map +1 -1
- package/dist/src/contexts/context.store.js.map +1 -1
- package/dist/src/controllers/collect-controller.d.ts +39 -0
- package/dist/src/controllers/collect-controller.js +161 -0
- package/dist/src/controllers/collect-controller.js.map +1 -0
- package/dist/src/controllers/compute-controller.d.ts +55 -0
- package/dist/src/controllers/compute-controller.js +350 -0
- package/dist/src/controllers/compute-controller.js.map +1 -0
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.d.ts +21 -0
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.js +152 -0
- package/dist/src/controllers/eta-renderer/eta-dom-renderer.js.map +1 -0
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.d.ts +28 -0
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.js +206 -0
- package/dist/src/controllers/eta-renderer/eta-mutation-observer.js.map +1 -0
- package/dist/src/controllers/eta-renderer/eta-renderer.d.ts +21 -0
- package/dist/src/controllers/eta-renderer/eta-renderer.js +77 -0
- package/dist/src/controllers/eta-renderer/eta-renderer.js.map +1 -0
- package/dist/src/controllers/eta-renderer/eta-template-cache.d.ts +21 -0
- package/dist/src/controllers/eta-renderer/eta-template-cache.js +52 -0
- package/dist/src/controllers/eta-renderer/eta-template-cache.js.map +1 -0
- package/dist/src/controllers/eta-renderer/eta-types.d.ts +11 -0
- package/dist/src/controllers/eta-renderer/eta-types.js +1 -0
- package/dist/src/controllers/eta-renderer/eta-types.js.map +1 -0
- package/dist/src/controllers/eta-renderer/index.d.ts +2 -0
- package/dist/src/controllers/eta-renderer/index.js +2 -0
- package/dist/src/controllers/eta-renderer/index.js.map +1 -0
- package/dist/src/controllers/event-pipeline-controller.d.ts +28 -0
- package/dist/src/controllers/event-pipeline-controller.js +72 -0
- package/dist/src/controllers/event-pipeline-controller.js.map +1 -0
- package/dist/src/dsl/compilers/array/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/boolean/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/enum/compiler.js.map +1 -1
- package/dist/src/dsl/compilers/index.js.map +1 -1
- package/dist/src/dsl/utilty.js.map +1 -1
- package/dist/src/events/events.js.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/nodes/node.context.js.map +1 -1
- package/dist/src/nodes/node.option.d.ts +4 -2
- package/dist/src/nodes/node.option.js +56 -56
- package/dist/src/nodes/node.option.js.map +1 -1
- package/dist/src/nodes/node.product.d.ts +4 -3
- package/dist/src/nodes/node.product.js +16 -28
- package/dist/src/nodes/node.product.js.map +1 -1
- package/dist/src/nodes/node.root.js.map +1 -1
- package/dist/src/nodes/node.state.d.ts +18 -70
- package/dist/src/nodes/node.state.js +42 -862
- package/dist/src/nodes/node.state.js.map +1 -1
- package/dist/src/renders/attributes/buyLink.js +12 -8
- package/dist/src/renders/attributes/buyLink.js.map +1 -1
- package/dist/src/renders/attributes/devices.js +10 -10
- package/dist/src/renders/attributes/devices.js.map +1 -1
- package/dist/src/renders/attributes/discount.js +60 -81
- package/dist/src/renders/attributes/discount.js.map +1 -1
- package/dist/src/renders/attributes/hide.js +21 -26
- package/dist/src/renders/attributes/hide.js.map +1 -1
- package/dist/src/renders/attributes/index.js.map +1 -1
- package/dist/src/renders/attributes/price.js +60 -81
- package/dist/src/renders/attributes/price.js.map +1 -1
- package/dist/src/renders/attributes/subscription.js +11 -11
- package/dist/src/renders/attributes/subscription.js.map +1 -1
- package/dist/src/renders/attributes/trialLink.js +5 -4
- package/dist/src/renders/attributes/trialLink.js.map +1 -1
- package/dist/src/renders/attributes/utilty.d.ts +2 -0
- package/dist/src/renders/attributes/utilty.js +5 -0
- package/dist/src/renders/attributes/utilty.js.map +1 -0
- package/dist/src/renders/context.js.map +1 -1
- package/dist/src/renders/format.js.map +1 -1
- package/dist/src/renders/index.d.ts +1 -1
- package/dist/src/renders/index.js +46 -50
- package/dist/src/renders/index.js.map +1 -1
- package/dist/src/renders/observe.js.map +1 -1
- package/dist/src/renders/utility.js +46 -38
- package/dist/src/renders/utility.js.map +1 -1
- package/dist/src/templating/eta.js.map +1 -1
- package/package.json +2 -2
- package/dist/src/contexts/context.event.d.ts +0 -5
- package/dist/src/contexts/context.event.js +0 -3
- package/dist/src/contexts/context.event.js.map +0 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { CollectActionEvent, CollectChildEvent, CollectChildRemovedEvent, CollectOptionEvent, CollectUpdateByDeltaEvent } from "../events/events.js";
|
|
2
|
+
import { Task } from "@lit/task";
|
|
3
|
+
export class CollectController {
|
|
4
|
+
constructor(host, computeAbort, computeRun, notifyParent) {
|
|
5
|
+
this._contextualChildren = new Set();
|
|
6
|
+
this._collectOptionEvent = (e) => {
|
|
7
|
+
if (e.target === this.host)
|
|
8
|
+
return;
|
|
9
|
+
e.stopPropagation();
|
|
10
|
+
this.collectOption(e.detail);
|
|
11
|
+
};
|
|
12
|
+
this._collectActionEvent = (e) => {
|
|
13
|
+
if (e.target === this.host)
|
|
14
|
+
return;
|
|
15
|
+
e.stopPropagation();
|
|
16
|
+
const { name, action } = e.detail;
|
|
17
|
+
if (action === null) {
|
|
18
|
+
this.host._actions.delete(name);
|
|
19
|
+
this.host._partialOptions.delete(name);
|
|
20
|
+
this.host._partialBundleOptions.delete(name);
|
|
21
|
+
}
|
|
22
|
+
else if (!action.id && (action.devices || action.subscription)) {
|
|
23
|
+
this.host._actions.set(name, action);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
if (action.bundle) {
|
|
27
|
+
this.host._partialBundleOptions.set(name, action);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
this.host._partialOptions.set(name, action);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
this._computeAbort();
|
|
34
|
+
this._computeRun();
|
|
35
|
+
this._notifyParent();
|
|
36
|
+
};
|
|
37
|
+
this._collectUpdateByDeltaEvent = (e) => {
|
|
38
|
+
if (e.target === this.host)
|
|
39
|
+
return;
|
|
40
|
+
const { name, update } = e.detail;
|
|
41
|
+
if (update === null) {
|
|
42
|
+
this.host._deltaUpdates.delete(name);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.host._deltaUpdates.set(name, update);
|
|
46
|
+
}
|
|
47
|
+
this._computeAbort();
|
|
48
|
+
this._computeRun();
|
|
49
|
+
this._notifyParent();
|
|
50
|
+
};
|
|
51
|
+
this._onCollectChild = (e) => {
|
|
52
|
+
if (e.target === this.host)
|
|
53
|
+
return;
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
const { child } = e.detail;
|
|
56
|
+
const hostEl = this.host;
|
|
57
|
+
if (child && child !== hostEl) {
|
|
58
|
+
this._contextualChildren.add(child);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
this._onCollectChildRemoved = (e) => {
|
|
62
|
+
if (e.target === this.host)
|
|
63
|
+
return;
|
|
64
|
+
e.stopPropagation();
|
|
65
|
+
const { child } = e.detail;
|
|
66
|
+
const hostEl = this.host;
|
|
67
|
+
if (child && child !== hostEl) {
|
|
68
|
+
this._contextualChildren.delete(child);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
this.host = host;
|
|
72
|
+
this._computeAbort = computeAbort;
|
|
73
|
+
this._computeRun = computeRun;
|
|
74
|
+
this._notifyParent = notifyParent;
|
|
75
|
+
host.addController(this);
|
|
76
|
+
this._toggleTask = new Task(host, {
|
|
77
|
+
task: async ([noCollect]) => {
|
|
78
|
+
const prev = this._prevCollect;
|
|
79
|
+
this._prevCollect = !noCollect;
|
|
80
|
+
if (prev === undefined) {
|
|
81
|
+
if (!noCollect)
|
|
82
|
+
this._notifyParent();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const currentCollect = !noCollect;
|
|
86
|
+
if (currentCollect && !prev) {
|
|
87
|
+
this._notifyParent();
|
|
88
|
+
}
|
|
89
|
+
else if (!currentCollect && prev) {
|
|
90
|
+
this.host.dispatchEvent(new CollectOptionEvent({ name: this.host.storeName, options: null }));
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
args: () => [this.host.noCollect]
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
hostConnected() {
|
|
97
|
+
this.host.addEventListener(CollectChildEvent.eventName, this._onCollectChild);
|
|
98
|
+
this.host.addEventListener(CollectChildRemovedEvent.eventName, this._onCollectChildRemoved);
|
|
99
|
+
this.host.addEventListener(CollectActionEvent.eventName, this._collectActionEvent);
|
|
100
|
+
this.host.addEventListener(CollectUpdateByDeltaEvent.eventName, this._collectUpdateByDeltaEvent);
|
|
101
|
+
this.host.addEventListener(CollectOptionEvent.eventName, this._collectOptionEvent);
|
|
102
|
+
this._announceAsContextualChild();
|
|
103
|
+
}
|
|
104
|
+
hostDisconnected() {
|
|
105
|
+
this.host.removeEventListener(CollectChildEvent.eventName, this._onCollectChild);
|
|
106
|
+
this.host.removeEventListener(CollectChildRemovedEvent.eventName, this._onCollectChildRemoved);
|
|
107
|
+
this.host.removeEventListener(CollectActionEvent.eventName, this._collectActionEvent);
|
|
108
|
+
this.host.removeEventListener(CollectUpdateByDeltaEvent.eventName, this._collectUpdateByDeltaEvent);
|
|
109
|
+
this.host.removeEventListener(CollectOptionEvent.eventName, this._collectOptionEvent);
|
|
110
|
+
this.host._options.clear();
|
|
111
|
+
this.host._actions.clear();
|
|
112
|
+
this.host._partialOptions.clear();
|
|
113
|
+
this.host._partialBundleOptions.clear();
|
|
114
|
+
this.host._deltaUpdates.clear();
|
|
115
|
+
this._contextualChildren.clear();
|
|
116
|
+
}
|
|
117
|
+
get toggleComplete() {
|
|
118
|
+
return this._toggleTask.taskComplete;
|
|
119
|
+
}
|
|
120
|
+
collectOption(detail) {
|
|
121
|
+
if (detail.options === null) {
|
|
122
|
+
this.host._options.delete(detail.name);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.host._options.set(detail.name, detail.options);
|
|
126
|
+
}
|
|
127
|
+
this._computeAbort();
|
|
128
|
+
this._computeRun();
|
|
129
|
+
this._notifyParent();
|
|
130
|
+
}
|
|
131
|
+
announceRemoval() {
|
|
132
|
+
this._announceContextualChildRemoved();
|
|
133
|
+
}
|
|
134
|
+
async waitForChildrenUpdateComplete() {
|
|
135
|
+
try {
|
|
136
|
+
const children = Array.from(this._contextualChildren);
|
|
137
|
+
const waits = children
|
|
138
|
+
.map((c) => c.updateComplete)
|
|
139
|
+
.filter((p) => !!p);
|
|
140
|
+
if (waits.length > 0)
|
|
141
|
+
await Promise.allSettled(waits);
|
|
142
|
+
}
|
|
143
|
+
catch { /* ignore */ }
|
|
144
|
+
}
|
|
145
|
+
getContextualChildren() {
|
|
146
|
+
return Array.from(this._contextualChildren);
|
|
147
|
+
}
|
|
148
|
+
_announceAsContextualChild() {
|
|
149
|
+
this.host.dispatchEvent(new CollectChildEvent({ child: this.host }));
|
|
150
|
+
}
|
|
151
|
+
_announceContextualChildRemoved() {
|
|
152
|
+
this.host.dispatchEvent(new CollectChildRemovedEvent({ child: this.host }));
|
|
153
|
+
}
|
|
154
|
+
hostUpdate() {
|
|
155
|
+
// no-op
|
|
156
|
+
}
|
|
157
|
+
hostUpdated() {
|
|
158
|
+
// no-op
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=collect-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-controller.js","sourceRoot":"","sources":["../../../src/controllers/collect-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CollectAction, CollectOption, CollectUpdateByDelta } from \"@/events/events\";\nimport { CollectActionEvent, CollectChildEvent, CollectChildRemovedEvent, CollectOptionEvent, CollectUpdateByDeltaEvent } from \"@/events/events\";\nimport { Task } from \"@lit/task\";\nimport { ReactiveController, ReactiveControllerHost } from \"lit\";\n\ntype CollectHost = ReactiveControllerHost & {\n storeName : symbol | string;\n noCollect : boolean;\n _options : Map<symbol | string, Promise<unknown[]>>;\n _actions : Map<symbol | string, NonNullable<CollectAction[\"action\"]>>;\n _partialOptions : Map<symbol | string, NonNullable<CollectAction[\"action\"]>>;\n _partialBundleOptions: Map<symbol | string, NonNullable<CollectAction[\"action\"]>>;\n _deltaUpdates : Map<symbol | string, NonNullable<CollectUpdateByDelta[\"update\"]>>;\n dispatchEvent(evt: Event): boolean;\n} & EventTarget;\n\nexport class CollectController implements ReactiveController {\n private host : CollectHost;\n private _computeAbort: () => void;\n private _computeRun : () => void;\n private _notifyParent: () => void;\n private _contextualChildren = new Set<HTMLElement>();\n private _prevCollect?: boolean;\n private _toggleTask : Task<unknown[], void>;\n\n constructor(host: CollectHost, computeAbort: () => void, computeRun: () => void, notifyParent: () => void) {\n this.host = host;\n this._computeAbort = computeAbort;\n this._computeRun = computeRun;\n this._notifyParent = notifyParent;\n host.addController(this);\n\n this._toggleTask = new Task(host, {\n task: async ([noCollect]) => {\n const prev = this._prevCollect;\n this._prevCollect = !noCollect;\n if (prev === undefined) {\n if (!noCollect) this._notifyParent();\n return;\n }\n const currentCollect = !noCollect;\n if (currentCollect && !prev) {\n this._notifyParent();\n } else if (!currentCollect && prev) {\n this.host.dispatchEvent(new CollectOptionEvent({ name: this.host.storeName, options: null }));\n }\n },\n args: () => [this.host.noCollect]\n });\n }\n\n hostConnected() {\n this.host.addEventListener(CollectChildEvent.eventName, this._onCollectChild as EventListener);\n this.host.addEventListener(CollectChildRemovedEvent.eventName, this._onCollectChildRemoved as EventListener);\n this.host.addEventListener(CollectActionEvent.eventName, this._collectActionEvent as EventListener);\n this.host.addEventListener(CollectUpdateByDeltaEvent.eventName, this._collectUpdateByDeltaEvent as EventListener);\n this.host.addEventListener(CollectOptionEvent.eventName, this._collectOptionEvent as EventListener);\n\n this._announceAsContextualChild();\n }\n\n hostDisconnected() {\n this.host.removeEventListener(CollectChildEvent.eventName, this._onCollectChild as EventListener);\n this.host.removeEventListener(CollectChildRemovedEvent.eventName, this._onCollectChildRemoved as EventListener);\n this.host.removeEventListener(CollectActionEvent.eventName, this._collectActionEvent as EventListener);\n this.host.removeEventListener(CollectUpdateByDeltaEvent.eventName, this._collectUpdateByDeltaEvent as EventListener);\n this.host.removeEventListener(CollectOptionEvent.eventName, this._collectOptionEvent as EventListener);\n\n this.host._options.clear();\n this.host._actions.clear();\n this.host._partialOptions.clear();\n this.host._partialBundleOptions.clear();\n this.host._deltaUpdates.clear();\n this._contextualChildren.clear();\n }\n\n get toggleComplete() {\n return this._toggleTask.taskComplete;\n }\n\n collectOption(detail: CollectOption) {\n if (detail.options === null) {\n this.host._options.delete(detail.name);\n } else {\n this.host._options.set(detail.name, detail.options as Promise<unknown[]>);\n }\n\n this._computeAbort();\n this._computeRun();\n this._notifyParent();\n }\n\n announceRemoval() {\n this._announceContextualChildRemoved();\n }\n\n async waitForChildrenUpdateComplete() {\n try {\n const children = Array.from(this._contextualChildren);\n const waits = children\n .map((c) => (c as unknown as { updateComplete?: Promise<void> }).updateComplete)\n .filter((p): p is Promise<void> => !!p);\n if (waits.length > 0) await Promise.allSettled(waits);\n } catch { /* ignore */ }\n }\n\n getContextualChildren(): HTMLElement[] {\n return Array.from(this._contextualChildren);\n }\n\n private _collectOptionEvent = (e: CollectOptionEvent) => {\n if (e.target === this.host) return;\n e.stopPropagation();\n this.collectOption(e.detail);\n };\n\n private _collectActionEvent = (e: CollectActionEvent) => {\n if (e.target === this.host) return;\n e.stopPropagation();\n const { name, action } = e.detail;\n\n if (action === null) {\n this.host._actions.delete(name);\n this.host._partialOptions.delete(name);\n this.host._partialBundleOptions.delete(name);\n } else if (!action.id && (action.devices || action.subscription)) {\n this.host._actions.set(name, action);\n } else {\n if (action.bundle) {\n this.host._partialBundleOptions.set(name, action);\n } else {\n this.host._partialOptions.set(name, action);\n }\n }\n\n this._computeAbort();\n this._computeRun();\n this._notifyParent();\n };\n\n private _collectUpdateByDeltaEvent = (e: CollectUpdateByDeltaEvent) => {\n if (e.target === this.host) return;\n\n const { name, update } = e.detail;\n if (update === null) {\n this.host._deltaUpdates.delete(name);\n } else {\n this.host._deltaUpdates.set(name, update);\n }\n\n this._computeAbort();\n this._computeRun();\n this._notifyParent();\n };\n\n private _onCollectChild = (e: CollectChildEvent) => {\n if (e.target === this.host) return;\n e.stopPropagation();\n const { child } = e.detail;\n const hostEl = this.host as unknown as HTMLElement;\n if (child && child !== hostEl) {\n this._contextualChildren.add(child);\n }\n };\n\n private _onCollectChildRemoved = (e: CollectChildRemovedEvent) => {\n if (e.target === this.host) return;\n e.stopPropagation();\n const { child } = e.detail;\n const hostEl = this.host as unknown as HTMLElement;\n if (child && child !== hostEl) {\n this._contextualChildren.delete(child);\n }\n };\n\n private _announceAsContextualChild() {\n this.host.dispatchEvent(new CollectChildEvent({ child: this.host as unknown as HTMLElement }));\n }\n\n private _announceContextualChildRemoved() {\n this.host.dispatchEvent(new CollectChildRemovedEvent({ child: this.host as unknown as HTMLElement }));\n }\n\n hostUpdate() {\n // no-op\n }\n\n hostUpdated() {\n // no-op\n }\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { stateContextType } from "../contexts/context.state.js";
|
|
2
|
+
import { storeContextType } from "../contexts/context.store.js";
|
|
3
|
+
import { CollectAction, CollectUpdateByDelta } from "../events/events.js";
|
|
4
|
+
import { ProductOption } from "@repobit/dex-store";
|
|
5
|
+
import { ReactiveController, ReactiveControllerHost } from "lit";
|
|
6
|
+
type Options = Map<symbol | string, Promise<ProductOption[]>>;
|
|
7
|
+
type Actions = Map<symbol | string, NonNullable<CollectAction["action"]>>;
|
|
8
|
+
type DeltaUpdate = Map<symbol | string, NonNullable<CollectUpdateByDelta["update"]>>;
|
|
9
|
+
type ComputeHost = ReactiveControllerHost & {
|
|
10
|
+
storeName: symbol | string;
|
|
11
|
+
_store?: storeContextType;
|
|
12
|
+
_options: Options;
|
|
13
|
+
_actions: Actions;
|
|
14
|
+
_deltaUpdates: DeltaUpdate;
|
|
15
|
+
_partialOptions: Actions;
|
|
16
|
+
_partialBundleOptions: Actions;
|
|
17
|
+
state: stateContextType;
|
|
18
|
+
};
|
|
19
|
+
export declare class ComputeController implements ReactiveController {
|
|
20
|
+
private host;
|
|
21
|
+
private _computeTask;
|
|
22
|
+
constructor(host: ComputeHost);
|
|
23
|
+
get value(): ProductOption[] | undefined;
|
|
24
|
+
get taskComplete(): Promise<ProductOption[] | undefined>;
|
|
25
|
+
run(): void;
|
|
26
|
+
abort(): void;
|
|
27
|
+
hostConnected(): void;
|
|
28
|
+
hostDisconnected(): void;
|
|
29
|
+
hostUpdate(): void;
|
|
30
|
+
hostUpdated(): void;
|
|
31
|
+
private _isAbortError;
|
|
32
|
+
private _computeState;
|
|
33
|
+
private _seedOptions;
|
|
34
|
+
private _expandFixedPoint;
|
|
35
|
+
private _applyBundleCombinations;
|
|
36
|
+
private _getOptionKey;
|
|
37
|
+
private _applyPartials;
|
|
38
|
+
private _applyActions;
|
|
39
|
+
private _applyDeltaUpdates;
|
|
40
|
+
private _applyAbsoluteDelta;
|
|
41
|
+
private _applySteppedDelta;
|
|
42
|
+
private _getDimensionValues;
|
|
43
|
+
private _getAbsoluteBounds;
|
|
44
|
+
/**
|
|
45
|
+
* Returns the next delta value for this action, or null when expansion is done.
|
|
46
|
+
*/
|
|
47
|
+
private _computeDelta;
|
|
48
|
+
private _computeContext;
|
|
49
|
+
private _updateMinMax;
|
|
50
|
+
private _createInitialState;
|
|
51
|
+
private _getOptionByDimension;
|
|
52
|
+
private _getOption;
|
|
53
|
+
private _applyBundles;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { Task } from "@lit/task";
|
|
2
|
+
export class ComputeController {
|
|
3
|
+
constructor(host) {
|
|
4
|
+
this.host = host;
|
|
5
|
+
host.addController(this);
|
|
6
|
+
this._computeTask = new Task(host, {
|
|
7
|
+
task: async (_, { signal }) => {
|
|
8
|
+
const isActive = () => {
|
|
9
|
+
if (signal.aborted) {
|
|
10
|
+
throw new DOMException("Task aborted", `AbortError ${this.host.storeName.toString()}`);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
try {
|
|
14
|
+
const computed = await this._computeState(isActive);
|
|
15
|
+
await this._computeContext(computed, isActive);
|
|
16
|
+
return computed;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (this._isAbortError(error)) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
console.error(error);
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
args: () => [this.host._store]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
get value() {
|
|
30
|
+
return this._computeTask.value;
|
|
31
|
+
}
|
|
32
|
+
get taskComplete() {
|
|
33
|
+
return this._computeTask.taskComplete;
|
|
34
|
+
}
|
|
35
|
+
run() {
|
|
36
|
+
this._computeTask.run();
|
|
37
|
+
}
|
|
38
|
+
abort() {
|
|
39
|
+
this._computeTask.abort();
|
|
40
|
+
}
|
|
41
|
+
hostConnected() {
|
|
42
|
+
// no-op
|
|
43
|
+
}
|
|
44
|
+
hostDisconnected() {
|
|
45
|
+
// no-op
|
|
46
|
+
}
|
|
47
|
+
hostUpdate() {
|
|
48
|
+
// no-op
|
|
49
|
+
}
|
|
50
|
+
hostUpdated() {
|
|
51
|
+
// no-op
|
|
52
|
+
}
|
|
53
|
+
_isAbortError(error) {
|
|
54
|
+
return error instanceof DOMException && error.name.includes("AbortError");
|
|
55
|
+
}
|
|
56
|
+
async _computeState(isActive) {
|
|
57
|
+
const computed = new Map();
|
|
58
|
+
const queue = [];
|
|
59
|
+
const enqueue = (option) => {
|
|
60
|
+
if (!option)
|
|
61
|
+
return;
|
|
62
|
+
const key = this._getOptionKey(option);
|
|
63
|
+
if (computed.has(key))
|
|
64
|
+
return;
|
|
65
|
+
computed.set(key, option);
|
|
66
|
+
queue.push(option);
|
|
67
|
+
};
|
|
68
|
+
await this._seedOptions(enqueue, isActive);
|
|
69
|
+
await this._expandFixedPoint(queue, enqueue, isActive);
|
|
70
|
+
await this._applyBundleCombinations(computed, enqueue, isActive);
|
|
71
|
+
return [...computed.values()];
|
|
72
|
+
}
|
|
73
|
+
async _seedOptions(enqueue, isActive) {
|
|
74
|
+
for (const optionsPromise of this.host._options.values()) {
|
|
75
|
+
isActive();
|
|
76
|
+
const options = await optionsPromise;
|
|
77
|
+
for (const option of options) {
|
|
78
|
+
isActive();
|
|
79
|
+
enqueue(option);
|
|
80
|
+
const partials = await this._applyPartials(option, isActive);
|
|
81
|
+
for (const partial of partials) {
|
|
82
|
+
enqueue(partial);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async _expandFixedPoint(queue, enqueue, isActive) {
|
|
88
|
+
while (queue.length > 0) {
|
|
89
|
+
isActive();
|
|
90
|
+
const current = queue.shift();
|
|
91
|
+
const actionResults = await this._applyActions(current, isActive);
|
|
92
|
+
for (const option of actionResults) {
|
|
93
|
+
enqueue(option);
|
|
94
|
+
}
|
|
95
|
+
const deltaResults = await this._applyDeltaUpdates(current, isActive);
|
|
96
|
+
for (const option of deltaResults) {
|
|
97
|
+
enqueue(option);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async _applyBundleCombinations(computed, enqueue, isActive) {
|
|
102
|
+
const bundles = [...this.host._partialBundleOptions.values()];
|
|
103
|
+
for (const option of [...computed.values()]) {
|
|
104
|
+
isActive();
|
|
105
|
+
const bundleResults = await this._applyBundles(option, bundles);
|
|
106
|
+
for (const bundled of bundleResults) {
|
|
107
|
+
enqueue(bundled);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
_getOptionKey(option) {
|
|
112
|
+
const product = option.getProduct();
|
|
113
|
+
const bundle = option.getBundle()
|
|
114
|
+
.map(({ option: bundled }) => this._getOptionKey(bundled))
|
|
115
|
+
.sort()
|
|
116
|
+
.join("|");
|
|
117
|
+
return [
|
|
118
|
+
product.getId(),
|
|
119
|
+
product.getCampaign() || "",
|
|
120
|
+
option.getDevices(),
|
|
121
|
+
option.getSubscription(),
|
|
122
|
+
bundle
|
|
123
|
+
].join("::");
|
|
124
|
+
}
|
|
125
|
+
async _applyPartials(baseOpt, isActive) {
|
|
126
|
+
const results = [];
|
|
127
|
+
for (const partial of this.host._partialOptions.values()) {
|
|
128
|
+
isActive();
|
|
129
|
+
if (!partial.id) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const newProduct = await baseOpt.switchProduct({ id: partial.id, campaign: partial.campaign });
|
|
133
|
+
const newOpt = await newProduct?.getOption({
|
|
134
|
+
devices: partial.devices ?? baseOpt.getDevices(),
|
|
135
|
+
subscription: partial.subscription ?? baseOpt.getSubscription()
|
|
136
|
+
});
|
|
137
|
+
if (newOpt)
|
|
138
|
+
results.push(newOpt);
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
async _applyActions(baseOpt, isActive) {
|
|
143
|
+
const results = [];
|
|
144
|
+
for (const action of this.host._actions.values()) {
|
|
145
|
+
isActive();
|
|
146
|
+
const targetDevices = action.devices ?? baseOpt.getDevices();
|
|
147
|
+
const targetSubscription = action.subscription ?? baseOpt.getSubscription();
|
|
148
|
+
// Skip no-op actions that don't change anything
|
|
149
|
+
if (targetDevices === baseOpt.getDevices() && targetSubscription === baseOpt.getSubscription()) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const newOpt = await baseOpt.getOption({
|
|
153
|
+
devices: targetDevices,
|
|
154
|
+
subscription: targetSubscription
|
|
155
|
+
});
|
|
156
|
+
if (newOpt)
|
|
157
|
+
results.push(newOpt);
|
|
158
|
+
}
|
|
159
|
+
return results;
|
|
160
|
+
}
|
|
161
|
+
async _applyDeltaUpdates(baseOpt, isActive) {
|
|
162
|
+
const results = [];
|
|
163
|
+
for (const action of this.host._deltaUpdates.values()) {
|
|
164
|
+
isActive();
|
|
165
|
+
const updates = action.useAsValue
|
|
166
|
+
? await this._applyAbsoluteDelta(baseOpt, action, isActive)
|
|
167
|
+
: await this._applySteppedDelta(baseOpt, action, isActive);
|
|
168
|
+
for (const option of updates) {
|
|
169
|
+
results.push(option);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return results;
|
|
173
|
+
}
|
|
174
|
+
async _applyAbsoluteDelta(baseOpt, action, isActive) {
|
|
175
|
+
const values = this._getDimensionValues(baseOpt, action.type);
|
|
176
|
+
const results = [];
|
|
177
|
+
const bounds = this._getAbsoluteBounds(action, action.delta);
|
|
178
|
+
for (const value of values) {
|
|
179
|
+
isActive();
|
|
180
|
+
if (value < bounds.min || value > bounds.max)
|
|
181
|
+
continue;
|
|
182
|
+
const option = await this._getOptionByDimension(baseOpt, action.type, value);
|
|
183
|
+
if (option)
|
|
184
|
+
results.push(option);
|
|
185
|
+
}
|
|
186
|
+
return results;
|
|
187
|
+
}
|
|
188
|
+
async _applySteppedDelta(baseOpt, action, isActive) {
|
|
189
|
+
const results = [];
|
|
190
|
+
const values = this._getDimensionValues(baseOpt, action.type);
|
|
191
|
+
let current = action.type === "devices"
|
|
192
|
+
? baseOpt.getDevices()
|
|
193
|
+
: baseOpt.getSubscription();
|
|
194
|
+
while (true) {
|
|
195
|
+
isActive();
|
|
196
|
+
const next = this._computeDelta(values, current, action);
|
|
197
|
+
if (next === null)
|
|
198
|
+
break;
|
|
199
|
+
current = next;
|
|
200
|
+
const option = await this._getOptionByDimension(baseOpt, action.type, current);
|
|
201
|
+
if (option) {
|
|
202
|
+
results.push(option);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return results;
|
|
206
|
+
}
|
|
207
|
+
_getDimensionValues(option, type) {
|
|
208
|
+
const product = option.getProduct();
|
|
209
|
+
return type === "devices"
|
|
210
|
+
? product.getDevices().values
|
|
211
|
+
: product.getSubscriptions().values;
|
|
212
|
+
}
|
|
213
|
+
_getAbsoluteBounds(action, fallback) {
|
|
214
|
+
const fallbackValue = typeof fallback === "number" && !Number.isNaN(fallback)
|
|
215
|
+
? fallback
|
|
216
|
+
: Number.MIN_SAFE_INTEGER;
|
|
217
|
+
const min = action.min ?? fallbackValue;
|
|
218
|
+
const max = action.max ?? fallbackValue;
|
|
219
|
+
return min <= max ? { min, max } : { min: max, max: min };
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Returns the next delta value for this action, or null when expansion is done.
|
|
223
|
+
*/
|
|
224
|
+
_computeDelta(values, current, action) {
|
|
225
|
+
const min = action.min ?? Number.MIN_SAFE_INTEGER;
|
|
226
|
+
const max = action.max ?? Number.MAX_SAFE_INTEGER;
|
|
227
|
+
const lower = Math.min(min, max);
|
|
228
|
+
const upper = Math.max(min, max);
|
|
229
|
+
if (action.delta === "next" || action.delta === "prev") {
|
|
230
|
+
const idx = values.findIndex(v => v === current);
|
|
231
|
+
const step = action.delta === "next" ? 1 : -1;
|
|
232
|
+
const candidate = values.at(idx + step);
|
|
233
|
+
if (candidate === undefined)
|
|
234
|
+
return null;
|
|
235
|
+
if (candidate < lower || candidate > upper)
|
|
236
|
+
return null;
|
|
237
|
+
return candidate === current ? null : candidate;
|
|
238
|
+
}
|
|
239
|
+
if (Number.isNaN(action.delta) || action.delta === 0) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const candidate = current + action.delta;
|
|
243
|
+
if (candidate < lower || candidate > upper)
|
|
244
|
+
return null;
|
|
245
|
+
return candidate === current ? null : candidate;
|
|
246
|
+
}
|
|
247
|
+
async _computeContext(options, isActive) {
|
|
248
|
+
const nextState = this._createInitialState();
|
|
249
|
+
for (const option of options) {
|
|
250
|
+
isActive();
|
|
251
|
+
this._updateMinMax(nextState.price, option.getPrice({ currency: false }), option.getPrice());
|
|
252
|
+
this._updateMinMax(nextState.price.monthly, option.getPrice({ monthly: true, currency: false }), option.getPrice({ monthly: true }));
|
|
253
|
+
this._updateMinMax(nextState.discountedPrice, option.getDiscountedPrice({ currency: false }), option.getDiscountedPrice());
|
|
254
|
+
this._updateMinMax(nextState.discountedPrice.monthly, option.getDiscountedPrice({ monthly: true, currency: false }), option.getDiscountedPrice({ monthly: true }));
|
|
255
|
+
this._updateMinMax(nextState.discount, option.getDiscount({ symbol: false }), option.getDiscount());
|
|
256
|
+
this._updateMinMax(nextState.discount.monthly, option.getDiscount({ monthly: true, symbol: false }), option.getDiscount({ monthly: true }));
|
|
257
|
+
this._updateMinMax(nextState.discount.percentage, option.getDiscount({ percentage: true, symbol: false }), option.getDiscount({ percentage: true }));
|
|
258
|
+
this._updateMinMax(nextState.discount.percentage.monthly, option.getDiscount({ monthly: true, percentage: true, symbol: false }), option.getDiscount({ monthly: true, percentage: true }));
|
|
259
|
+
}
|
|
260
|
+
this.host.state = nextState;
|
|
261
|
+
}
|
|
262
|
+
_updateMinMax(range, value, formatted) {
|
|
263
|
+
if (value < range.min.value) {
|
|
264
|
+
range.min.value = value;
|
|
265
|
+
range.min.fmt = formatted;
|
|
266
|
+
}
|
|
267
|
+
if (value > range.max.value) {
|
|
268
|
+
range.max.value = value;
|
|
269
|
+
range.max.fmt = formatted;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
_createInitialState() {
|
|
273
|
+
const createRange = () => ({
|
|
274
|
+
min: { value: Number.MAX_SAFE_INTEGER, fmt: "" },
|
|
275
|
+
max: { value: Number.MIN_SAFE_INTEGER, fmt: "" }
|
|
276
|
+
});
|
|
277
|
+
return {
|
|
278
|
+
price: {
|
|
279
|
+
...createRange(),
|
|
280
|
+
monthly: createRange()
|
|
281
|
+
},
|
|
282
|
+
discountedPrice: {
|
|
283
|
+
...createRange(),
|
|
284
|
+
monthly: createRange()
|
|
285
|
+
},
|
|
286
|
+
discount: {
|
|
287
|
+
...createRange(),
|
|
288
|
+
monthly: createRange(),
|
|
289
|
+
percentage: {
|
|
290
|
+
...createRange(),
|
|
291
|
+
monthly: createRange()
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
async _getOptionByDimension(baseOpt, type, value) {
|
|
297
|
+
const devices = type === "devices" ? value : baseOpt.getDevices();
|
|
298
|
+
const subscription = type === "subscription" ? value : baseOpt.getSubscription();
|
|
299
|
+
return baseOpt.getOption({ devices, subscription });
|
|
300
|
+
}
|
|
301
|
+
async _getOption({ id, campaign, devices, subscription }, bundle = []) {
|
|
302
|
+
if (id && devices !== undefined && subscription !== undefined) {
|
|
303
|
+
const product = await this.host._store?.getProduct({ id, campaign });
|
|
304
|
+
return await product?.getOption({ devices, subscription, bundle });
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
async _applyBundles(baseOpt, bundles) {
|
|
309
|
+
if (bundles.length === 0) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
const result = [];
|
|
313
|
+
const recurse = async (prefix, start) => {
|
|
314
|
+
for (let i = start; i < bundles.length; i++) {
|
|
315
|
+
const action = bundles[i];
|
|
316
|
+
const bundleOption = await this._getOption({
|
|
317
|
+
id: action.id,
|
|
318
|
+
campaign: action.campaign,
|
|
319
|
+
devices: action.devices ?? baseOpt.getDevices(),
|
|
320
|
+
subscription: action.subscription ?? baseOpt.getSubscription()
|
|
321
|
+
});
|
|
322
|
+
if (!bundleOption) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const next = prefix.concat({
|
|
326
|
+
devicesFixed: action.devices !== undefined,
|
|
327
|
+
subscriptionFixed: action.subscription !== undefined,
|
|
328
|
+
option: bundleOption
|
|
329
|
+
});
|
|
330
|
+
result.push(next);
|
|
331
|
+
await recurse(next, i + 1);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
const bundleOption = async (option, bundlesToApply = []) => {
|
|
335
|
+
for (const bundle of bundlesToApply) {
|
|
336
|
+
const newOpt = await option.toogleBundle(bundle);
|
|
337
|
+
if (newOpt) {
|
|
338
|
+
option = newOpt;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return option;
|
|
345
|
+
};
|
|
346
|
+
await recurse([], 0);
|
|
347
|
+
return Promise.all(result.map(bundlesToApply => bundleOption(baseOpt, bundlesToApply)));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=compute-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compute-controller.js","sourceRoot":"","sources":["../../../src/controllers/compute-controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoBjC,MAAM,OAAO,iBAAiB;IAI5B,YAAY,IAAiB;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAEzB,IAAI,CAAC,YAAY,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE;YACjC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC5B,MAAM,QAAQ,GAAG,GAAG,EAAE;oBACpB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACnB,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,cAAc,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;oBACzF,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;oBACpD,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;oBAC/C,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;wBAC9B,OAAO,EAAE,CAAC;oBACZ,CAAC;oBACD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBACrB,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YACD,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC;IACxC,CAAC;IAED,GAAG;QACD,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED,aAAa;QACX,QAAQ;IACV,CAAC;IAED,gBAAgB;QACd,QAAQ;IACV,CAAC;IAED,UAAU;QACR,QAAQ;IACV,CAAC;IAED,WAAW;QACT,QAAQ;IACV,CAAC;IAEO,aAAa,CAAC,KAAc;QAClC,OAAO,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC5E,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,QAAoB;QAC9C,MAAM,QAAQ,GAAc,IAAI,GAAG,EAAE,CAAC;QACtC,MAAM,KAAK,GAAoB,EAAE,CAAC;QAElC,MAAM,OAAO,GAAG,CAAC,MAAwC,EAAE,EAAE;YAC3D,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO;YAC9B,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,IAAI,CAAC,wBAAwB,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEjE,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,YAAY,CACxB,OAA2D,EAC3D,QAAoB;QAEpB,KAAK,MAAM,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACzD,QAAQ,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC;YACrC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,QAAQ,EAAE,CAAC;gBACX,OAAO,CAAC,MAAM,CAAC,CAAC;gBAChB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAC7D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC7B,KAAsB,EACtB,OAA2D,EAC3D,QAAoB;QAEpB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;YAE/B,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAClE,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;gBACnC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACtE,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;gBAClC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,wBAAwB,CACpC,QAAmB,EACnB,OAA2D,EAC3D,QAAoB;QAEpB,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC5C,QAAQ,EAAE,CAAC;YACX,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAChE,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,MAAqB;QACzC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE;aAC9B,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;aACzD,IAAI,EAAE;aACN,IAAI,CAAC,GAAG,CAAC,CAAC;QACb,OAAO;YACL,OAAO,CAAC,KAAK,EAAE;YACf,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE;YAC3B,MAAM,CAAC,UAAU,EAAE;YACnB,MAAM,CAAC,eAAe,EAAE;YACxB,MAAM;SACP,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,OAAsB,EACtB,QAAoB;QAEpB,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC;YACzD,QAAQ,EAAE,CAAC;YACX,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC/F,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,SAAS,CAAC;gBACzC,OAAO,EAAO,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE;gBACrD,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE;aAChE,CAAC,CAAC;YACH,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,OAAsB,EACtB,QAAoB;QAEpB,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YACjD,QAAQ,EAAE,CAAC;YACX,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YAC7D,MAAM,kBAAkB,GAAG,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5E,gDAAgD;YAChD,IAAI,aAAa,KAAK,OAAO,CAAC,UAAU,EAAE,IAAI,kBAAkB,KAAK,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;gBAC/F,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC;gBACrC,OAAO,EAAO,aAAa;gBAC3B,YAAY,EAAE,kBAAkB;aACjC,CAAC,CAAC;YACH,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC9B,OAAsB,EACtB,QAAoB;QAEpB,MAAM,OAAO,GAAoB,EAAE,CAAC;QAEpC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;YACtD,QAAQ,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU;gBAC/B,CAAC,CAAC,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;gBAC3D,CAAC,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAE7D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,OAAsB,EACtB,MAAqB,EACrB,QAAoB;QAEpB,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAE7D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,QAAQ,EAAE,CAAC;YACX,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG;gBAAE,SAAS;YACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7E,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC9B,OAAsB,EACtB,MAAqB,EACrB,QAAoB;QAEpB,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS;YACrC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE;YACtB,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QAE9B,OAAO,IAAI,EAAE,CAAC;YACZ,QAAQ,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YACzD,IAAI,IAAI,KAAK,IAAI;gBAAE,MAAM;YAEzB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC/E,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,mBAAmB,CACzB,MAAqB,EACrB,IAA2B;QAE3B,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACpC,OAAO,IAAI,KAAK,SAAS;YACvB,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM;YAC7B,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC;IACxC,CAAC;IAEO,kBAAkB,CACxB,MAAqB,EACrB,QAAgC;QAEhC,MAAM,aAAa,GACjB,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YACrD,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC;QAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,aAAa,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,aAAa,CAAC;QACxC,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACK,aAAa,CACnB,MAAgB,EAChB,OAAe,EACf,MAAqB;QAErB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,gBAAgB,CAAC;QAClD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,gBAAgB,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAEjC,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YACvD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;YACxC,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACzC,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,GAAG,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxD,OAAO,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAClD,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC;QACzC,IAAI,SAAS,GAAG,KAAK,IAAI,SAAS,GAAG,KAAK;YAAE,OAAO,IAAI,CAAC;QACxD,OAAO,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,OAAwB,EAAE,QAAoB;QAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAE7C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC;YAEX,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,KAAK,EACf,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EACpC,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,KAAK,CAAC,OAAO,EACvB,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EACnD,MAAM,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CACnC,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,eAAe,EACzB,MAAM,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAC9C,MAAM,CAAC,kBAAkB,EAAE,CAC5B,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,eAAe,CAAC,OAAO,EACjC,MAAM,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAC7D,MAAM,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAC7C,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,QAAQ,EAClB,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EACrC,MAAM,CAAC,WAAW,EAAE,CACrB,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAC1B,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EACpD,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CACtC,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,QAAQ,CAAC,UAAU,EAC7B,MAAM,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EACvD,MAAM,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CACzC,CAAC;YAEF,IAAI,CAAC,aAAa,CAChB,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EACrC,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EACtE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CACxD,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IAC9B,CAAC;IAEO,aAAa,CAAC,KAAa,EAAE,KAAa,EAAE,SAAiB;QACnE,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;YACxB,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC;QAC5B,CAAC;QACD,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;YACxB,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC;QAC5B,CAAC;IACH,CAAC;IAEO,mBAAmB;QACzB,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,CAAC;YACjC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,gBAAgB,EAAE,GAAG,EAAE,EAAE,EAAE;YAChD,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,gBAAgB,EAAE,GAAG,EAAE,EAAE,EAAE;SACjD,CAAC,CAAC;QAEH,OAAO;YACL,KAAK,EAAE;gBACL,GAAG,WAAW,EAAE;gBAChB,OAAO,EAAE,WAAW,EAAE;aACvB;YACD,eAAe,EAAE;gBACf,GAAG,WAAW,EAAE;gBAChB,OAAO,EAAE,WAAW,EAAE;aACvB;YACD,QAAQ,EAAE;gBACR,GAAG,WAAW,EAAE;gBAChB,OAAO,EAAK,WAAW,EAAE;gBACzB,UAAU,EAAE;oBACV,GAAG,WAAW,EAAE;oBAChB,OAAO,EAAE,WAAW,EAAE;iBACvB;aACF;SACF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,qBAAqB,CACjC,OAAsB,EACtB,IAA2B,EAC3B,KAAa;QAEb,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QAClE,MAAM,YAAY,GAAG,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;QACjF,OAAO,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IACtD,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAmB,EAAE,SAAgC,EAAE;QACnH,IAAI,EAAE,IAAI,OAAO,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC9D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACrE,OAAO,MAAM,OAAO,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAAsB,EAAE,OAA0B;QAC5E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAE3C,MAAM,OAAO,GAAG,KAAK,EAAE,MAA6B,EAAE,KAAa,EAAE,EAAE;YACrE,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC1B,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;oBACzC,EAAE,EAAY,MAAM,CAAC,EAAE;oBACvB,QAAQ,EAAM,MAAM,CAAC,QAAQ;oBAC7B,OAAO,EAAO,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE;oBACpD,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,OAAO,CAAC,eAAe,EAAE;iBAC/D,CAAC,CAAC;gBAEH,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClB,SAAS;gBACX,CAAC;gBAED,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;oBACzB,YAAY,EAAO,MAAM,CAAC,OAAO,KAAK,SAAS;oBAC/C,iBAAiB,EAAE,MAAM,CAAC,YAAY,KAAK,SAAS;oBACpD,MAAM,EAAa,YAAY;iBAChC,CAAC,CAAC;gBAEH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClB,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,KAAK,EAAE,MAAqB,EAAE,iBAAwC,EAAE,EAAE,EAAE;YAC/F,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;gBACpC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;gBACjD,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,GAAG,MAAM,CAAC;gBAClB,CAAC;qBAAM,CAAC;oBACN,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QAEF,MAAM,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAErB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC;CACF","sourcesContent":["import { MinMax, stateContextType } from \"@/contexts/context.state\";\nimport { storeContextType } from \"@/contexts/context.store\";\nimport { Action, CollectAction, CollectUpdateByDelta, UpdateByDelta } from \"@/events/events\";\nimport { Task } from \"@lit/task\";\nimport { ProductBundleOption, ProductOption } from \"@repobit/dex-store\";\nimport { ReactiveController, ReactiveControllerHost } from \"lit\";\n\ntype Options = Map<symbol | string, Promise<ProductOption[]>>;\ntype Actions = Map<symbol | string, NonNullable<CollectAction[\"action\"]>>;\ntype DeltaUpdate = Map<symbol | string, NonNullable<CollectUpdateByDelta[\"update\"]>>;\ntype OptionMap = Map<string, ProductOption>;\n\ntype ComputeHost = ReactiveControllerHost & {\n storeName : symbol | string;\n _store? : storeContextType;\n _options : Options;\n _actions : Actions;\n _deltaUpdates : DeltaUpdate;\n _partialOptions : Actions;\n _partialBundleOptions: Actions;\n state : stateContextType;\n};\n\nexport class ComputeController implements ReactiveController {\n private host : ComputeHost;\n private _computeTask: Task<unknown[], ProductOption[] | undefined>;\n\n constructor(host: ComputeHost) {\n this.host = host;\n host.addController(this);\n\n this._computeTask = new Task(host, {\n task: async (_, { signal }) => {\n const isActive = () => {\n if (signal.aborted) {\n throw new DOMException(\"Task aborted\", `AbortError ${this.host.storeName.toString()}`);\n }\n };\n\n try {\n const computed = await this._computeState(isActive);\n await this._computeContext(computed, isActive);\n return computed;\n } catch (error: unknown) {\n if (this._isAbortError(error)) {\n return [];\n }\n console.error(error);\n return [];\n }\n },\n args: () => [this.host._store]\n });\n }\n\n get value() {\n return this._computeTask.value;\n }\n\n get taskComplete() {\n return this._computeTask.taskComplete;\n }\n\n run() {\n this._computeTask.run();\n }\n\n abort() {\n this._computeTask.abort();\n }\n\n hostConnected() {\n // no-op\n }\n\n hostDisconnected() {\n // no-op\n }\n\n hostUpdate() {\n // no-op\n }\n\n hostUpdated() {\n // no-op\n }\n\n private _isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name.includes(\"AbortError\");\n }\n\n private async _computeState(isActive: () => void): Promise<ProductOption[]> {\n const computed: OptionMap = new Map();\n const queue: ProductOption[] = [];\n\n const enqueue = (option: ProductOption | null | undefined) => {\n if (!option) return;\n const key = this._getOptionKey(option);\n if (computed.has(key)) return;\n computed.set(key, option);\n queue.push(option);\n };\n\n await this._seedOptions(enqueue, isActive);\n await this._expandFixedPoint(queue, enqueue, isActive);\n await this._applyBundleCombinations(computed, enqueue, isActive);\n\n return [...computed.values()];\n }\n\n private async _seedOptions(\n enqueue: (option: ProductOption | null | undefined) => void,\n isActive: () => void\n ) {\n for (const optionsPromise of this.host._options.values()) {\n isActive();\n const options = await optionsPromise;\n for (const option of options) {\n isActive();\n enqueue(option);\n const partials = await this._applyPartials(option, isActive);\n for (const partial of partials) {\n enqueue(partial);\n }\n }\n }\n }\n\n private async _expandFixedPoint(\n queue: ProductOption[],\n enqueue: (option: ProductOption | null | undefined) => void,\n isActive: () => void\n ) {\n while (queue.length > 0) {\n isActive();\n const current = queue.shift()!;\n\n const actionResults = await this._applyActions(current, isActive);\n for (const option of actionResults) {\n enqueue(option);\n }\n\n const deltaResults = await this._applyDeltaUpdates(current, isActive);\n for (const option of deltaResults) {\n enqueue(option);\n }\n }\n }\n\n private async _applyBundleCombinations(\n computed: OptionMap,\n enqueue: (option: ProductOption | null | undefined) => void,\n isActive: () => void\n ) {\n const bundles = [...this.host._partialBundleOptions.values()];\n for (const option of [...computed.values()]) {\n isActive();\n const bundleResults = await this._applyBundles(option, bundles);\n for (const bundled of bundleResults) {\n enqueue(bundled);\n }\n }\n }\n\n private _getOptionKey(option: ProductOption): string {\n const product = option.getProduct();\n const bundle = option.getBundle()\n .map(({ option: bundled }) => this._getOptionKey(bundled))\n .sort()\n .join(\"|\");\n return [\n product.getId(),\n product.getCampaign() || \"\",\n option.getDevices(),\n option.getSubscription(),\n bundle\n ].join(\"::\");\n }\n\n private async _applyPartials(\n baseOpt: ProductOption,\n isActive: () => void\n ): Promise<ProductOption[]> {\n const results: ProductOption[] = [];\n for (const partial of this.host._partialOptions.values()) {\n isActive();\n if (!partial.id) {\n continue;\n }\n const newProduct = await baseOpt.switchProduct({ id: partial.id, campaign: partial.campaign });\n const newOpt = await newProduct?.getOption({\n devices : partial.devices ?? baseOpt.getDevices(),\n subscription: partial.subscription ?? baseOpt.getSubscription()\n });\n if (newOpt) results.push(newOpt);\n }\n return results;\n }\n\n private async _applyActions(\n baseOpt: ProductOption,\n isActive: () => void\n ): Promise<ProductOption[]> {\n const results: ProductOption[] = [];\n for (const action of this.host._actions.values()) {\n isActive();\n const targetDevices = action.devices ?? baseOpt.getDevices();\n const targetSubscription = action.subscription ?? baseOpt.getSubscription();\n // Skip no-op actions that don't change anything\n if (targetDevices === baseOpt.getDevices() && targetSubscription === baseOpt.getSubscription()) {\n continue;\n }\n const newOpt = await baseOpt.getOption({\n devices : targetDevices,\n subscription: targetSubscription\n });\n if (newOpt) results.push(newOpt);\n }\n return results;\n }\n\n private async _applyDeltaUpdates(\n baseOpt: ProductOption,\n isActive: () => void\n ): Promise<ProductOption[]> {\n const results: ProductOption[] = [];\n\n for (const action of this.host._deltaUpdates.values()) {\n isActive();\n const updates = action.useAsValue\n ? await this._applyAbsoluteDelta(baseOpt, action, isActive)\n : await this._applySteppedDelta(baseOpt, action, isActive);\n\n for (const option of updates) {\n results.push(option);\n }\n }\n\n return results;\n }\n\n private async _applyAbsoluteDelta(\n baseOpt: ProductOption,\n action: UpdateByDelta,\n isActive: () => void\n ): Promise<ProductOption[]> {\n const values = this._getDimensionValues(baseOpt, action.type);\n const results: ProductOption[] = [];\n const bounds = this._getAbsoluteBounds(action, action.delta);\n\n for (const value of values) {\n isActive();\n if (value < bounds.min || value > bounds.max) continue;\n const option = await this._getOptionByDimension(baseOpt, action.type, value);\n if (option) results.push(option);\n }\n\n return results;\n }\n\n private async _applySteppedDelta(\n baseOpt: ProductOption,\n action: UpdateByDelta,\n isActive: () => void\n ): Promise<ProductOption[]> {\n const results: ProductOption[] = [];\n const values = this._getDimensionValues(baseOpt, action.type);\n let current = action.type === \"devices\"\n ? baseOpt.getDevices()\n : baseOpt.getSubscription();\n\n while (true) {\n isActive();\n const next = this._computeDelta(values, current, action);\n if (next === null) break;\n\n current = next;\n const option = await this._getOptionByDimension(baseOpt, action.type, current);\n if (option) {\n results.push(option);\n }\n }\n\n return results;\n }\n\n private _getDimensionValues(\n option: ProductOption,\n type: UpdateByDelta[\"type\"]\n ): number[] {\n const product = option.getProduct();\n return type === \"devices\"\n ? product.getDevices().values\n : product.getSubscriptions().values;\n }\n\n private _getAbsoluteBounds(\n action: UpdateByDelta,\n fallback: UpdateByDelta[\"delta\"]\n ): { min: number; max: number } {\n const fallbackValue =\n typeof fallback === \"number\" && !Number.isNaN(fallback)\n ? fallback\n : Number.MIN_SAFE_INTEGER;\n const min = action.min ?? fallbackValue;\n const max = action.max ?? fallbackValue;\n return min <= max ? { min, max } : { min: max, max: min };\n }\n\n /**\n * Returns the next delta value for this action, or null when expansion is done.\n */\n private _computeDelta(\n values: number[],\n current: number,\n action: UpdateByDelta\n ): number | null {\n const min = action.min ?? Number.MIN_SAFE_INTEGER;\n const max = action.max ?? Number.MAX_SAFE_INTEGER;\n const lower = Math.min(min, max);\n const upper = Math.max(min, max);\n\n if (action.delta === \"next\" || action.delta === \"prev\") {\n const idx = values.findIndex(v => v === current);\n const step = action.delta === \"next\" ? 1 : -1;\n const candidate = values.at(idx + step);\n if (candidate === undefined) return null;\n if (candidate < lower || candidate > upper) return null;\n return candidate === current ? null : candidate;\n }\n\n if (Number.isNaN(action.delta) || action.delta === 0) {\n return null;\n }\n\n const candidate = current + action.delta;\n if (candidate < lower || candidate > upper) return null;\n return candidate === current ? null : candidate;\n }\n\n private async _computeContext(options: ProductOption[], isActive: () => void) {\n const nextState = this._createInitialState();\n\n for (const option of options) {\n isActive();\n\n this._updateMinMax(\n nextState.price,\n option.getPrice({ currency: false }),\n option.getPrice()\n );\n\n this._updateMinMax(\n nextState.price.monthly,\n option.getPrice({ monthly: true, currency: false }),\n option.getPrice({ monthly: true })\n );\n\n this._updateMinMax(\n nextState.discountedPrice,\n option.getDiscountedPrice({ currency: false }),\n option.getDiscountedPrice()\n );\n\n this._updateMinMax(\n nextState.discountedPrice.monthly,\n option.getDiscountedPrice({ monthly: true, currency: false }),\n option.getDiscountedPrice({ monthly: true })\n );\n\n this._updateMinMax(\n nextState.discount,\n option.getDiscount({ symbol: false }),\n option.getDiscount()\n );\n\n this._updateMinMax(\n nextState.discount.monthly,\n option.getDiscount({ monthly: true, symbol: false }),\n option.getDiscount({ monthly: true })\n );\n\n this._updateMinMax(\n nextState.discount.percentage,\n option.getDiscount({ percentage: true, symbol: false }),\n option.getDiscount({ percentage: true })\n );\n\n this._updateMinMax(\n nextState.discount.percentage.monthly,\n option.getDiscount({ monthly: true, percentage: true, symbol: false }),\n option.getDiscount({ monthly: true, percentage: true })\n );\n }\n\n this.host.state = nextState;\n }\n\n private _updateMinMax(range: MinMax, value: number, formatted: string) {\n if (value < range.min.value) {\n range.min.value = value;\n range.min.fmt = formatted;\n }\n if (value > range.max.value) {\n range.max.value = value;\n range.max.fmt = formatted;\n }\n }\n\n private _createInitialState(): stateContextType {\n const createRange = (): MinMax => ({\n min: { value: Number.MAX_SAFE_INTEGER, fmt: \"\" },\n max: { value: Number.MIN_SAFE_INTEGER, fmt: \"\" }\n });\n\n return {\n price: {\n ...createRange(),\n monthly: createRange()\n },\n discountedPrice: {\n ...createRange(),\n monthly: createRange()\n },\n discount: {\n ...createRange(),\n monthly : createRange(),\n percentage: {\n ...createRange(),\n monthly: createRange()\n }\n }\n };\n }\n\n private async _getOptionByDimension(\n baseOpt: ProductOption,\n type: UpdateByDelta[\"type\"],\n value: number\n ) {\n const devices = type === \"devices\" ? value : baseOpt.getDevices();\n const subscription = type === \"subscription\" ? value : baseOpt.getSubscription();\n return baseOpt.getOption({ devices, subscription });\n }\n\n private async _getOption({ id, campaign, devices, subscription }: Partial<Action>, bundle: ProductBundleOption[] = []) {\n if (id && devices !== undefined && subscription !== undefined) {\n const product = await this.host._store?.getProduct({ id, campaign });\n return await product?.getOption({ devices, subscription, bundle });\n }\n\n return null;\n }\n\n private async _applyBundles(baseOpt: ProductOption, bundles: Partial<Action>[]) {\n if (bundles.length === 0) {\n return [];\n }\n const result: ProductBundleOption[][] = [];\n\n const recurse = async (prefix: ProductBundleOption[], start: number) => {\n for (let i = start; i < bundles.length; i++) {\n const action = bundles[i];\n const bundleOption = await this._getOption({\n id : action.id,\n campaign : action.campaign,\n devices : action.devices ?? baseOpt.getDevices(),\n subscription: action.subscription ?? baseOpt.getSubscription()\n });\n\n if (!bundleOption) {\n continue;\n }\n\n const next = prefix.concat({\n devicesFixed : action.devices !== undefined,\n subscriptionFixed: action.subscription !== undefined,\n option : bundleOption\n });\n\n result.push(next);\n await recurse(next, i + 1);\n }\n };\n\n const bundleOption = async (option: ProductOption, bundlesToApply: ProductBundleOption[] = []) => {\n for (const bundle of bundlesToApply) {\n const newOpt = await option.toogleBundle(bundle);\n if (newOpt) {\n option = newOpt;\n } else {\n return null;\n }\n }\n return option;\n };\n\n await recurse([], 0);\n\n return Promise.all(result.map(bundlesToApply => bundleOption(baseOpt, bundlesToApply)));\n }\n}\n"]}
|