@elqora/dgp-core 1.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/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # DGP Core
2
+
3
+ DGP Core is the framework-neutral interpreter for canonical Digital Goods Protocol product definitions. It resolves product context, visibility, relationships, selected-trigger effects, service bindings, capabilities, and fallback registrations into deterministic query results.
4
+
5
+ DGP Core does not render interfaces, implement editorial workflows, or execute fulfillment. DGP Ordering handles customer orchestration, DGP Workspace supplies reusable editorial infrastructure, and the DGP SDK defines backend execution.
6
+
7
+ ## Responsibilities
8
+
9
+ - Deterministic product indexing
10
+ - Cycle-safe graph, lineage, and relationship traversal
11
+ - Context and visibility resolution
12
+ - Recursive option traversal and selected-trigger effect resolution
13
+ - Service binding and capability resolution
14
+ - Node-first, then global fallback-candidate resolution
15
+ - A composed, reusable product interpreter
16
+
17
+ Core accepts canonical v1 definitions as-is. It does not repair or normalize legacy documents, validate publication coherence, mutate customer values, execute expressions, calculate utilities, or select an operational fallback service. Those concerns belong to their owning packages or the backend handler.
18
+
19
+ ## Install
20
+
21
+ Node.js 22 or newer is required.
22
+
23
+ ```sh
24
+ npm install @elqora/dgp-core @elqora/dgp-spec
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```ts
30
+ import { createProductInterpreter } from "@elqora/dgp-core";
31
+
32
+ const product = createProductInterpreter(definition);
33
+ const context = product.resolveContext("checkout", selectedTriggerIds);
34
+
35
+ context?.visibility.fieldIds;
36
+ context?.capabilities.values;
37
+ ```
38
+
39
+ Public functions are pure with respect to the supplied definition. Returned collections are newly allocated unless explicitly documented as canonical source nodes.
40
+
41
+ ## Interpretation rules
42
+
43
+ - Filter lineage is returned root-first and traversal terminates safely if a malformed cycle is encountered.
44
+ - Fields bound to the active filter or an ancestor are visible. Only the active filter's direct `includes` and `excludes` apply.
45
+ - Selected field-button and option triggers apply only when their owning field belongs to the active lineage.
46
+ - A nearer trigger overrides an ancestor trigger; at equal depth, exclusion wins.
47
+ - `order_for_tags` pins visible fields first without introducing hidden fields.
48
+ - Ancestor capability requirements take precedence over conflicting descendant declarations, and their origin filter is reported without modifying the document.
49
+ - Option effects may reveal a field and narrow its recursively indexed options. Value effects are returned as declarations for Ordering to apply.
50
+ - Fallback registrations are listed node-first and then by the primary service's global list, with duplicates and self-references removed. Backend policy still decides operational eligibility.
51
+
52
+ ## Development
53
+
54
+ ```sh
55
+ npm install
56
+ npm run lint
57
+ npm run typecheck
58
+ npm test
59
+ npm run check:boundaries
60
+ npm run build
61
+ npm run check
62
+ ```
63
+
64
+ `npm run check` is the repository completion command. It runs linting, strict type checking, tests, dependency/source boundary checks, and the distributable build. Build output in `dist/` is generated and is not committed.
65
+
66
+ ## Ecosystem
67
+
68
+ - [DGP Spec](https://github.com/elqora/dgp-spec) owns canonical contracts.
69
+ - [DGP Validation](https://github.com/elqora/dgp-validation) validates definitions for ingestion and publication.
70
+ - [DGP Ordering](https://github.com/elqora/dgp-ordering) orchestrates customer ordering flows.
71
+ - [DGP Ordering Form Palette](https://github.com/elqora/dgp-ordering-form-palette) provides the optional Form Palette integration.
72
+ - [DGP Workspace](https://github.com/elqora/dgp-workspace) provides reusable editorial infrastructure.
73
+ - [DGP Studio](https://github.com/elqora/dgp-studio) provides visual authoring, testing, and publication UX.
74
+ - [DGP SDK](https://github.com/elqora/dgp-sdk) defines backend handler and fulfillment contracts.
75
+ - [Digital Service Engine](https://github.com/timeax/digital-service-engine) is the legacy migration source and behavioral reference.
76
+
77
+ ## Status
78
+
79
+ The initial DGP v1 interpretation slice is implemented against `@elqora/dgp-spec` 1.x.
80
+
81
+ ## License
82
+
83
+ GPL-3.0-only.
@@ -0,0 +1,13 @@
1
+ import type { CapabilityRequirements, HandlerService, ProductDefinition, ServiceId } from "@elqora/dgp-spec";
2
+ import { type ProductIndex } from "./indexer.js";
3
+ export interface ResolvedCapabilities {
4
+ values: Readonly<Record<string, boolean>>;
5
+ origins: Readonly<Record<string, string>>;
6
+ }
7
+ export declare function resolveCapabilities(index: ProductIndex, filterId: string): ResolvedCapabilities;
8
+ export declare function resolveDefinitionCapabilities(definition: ProductDefinition, filterId: string): ResolvedCapabilities;
9
+ export declare function serviceCapabilityEnabled(service: HandlerService, capabilityId: string): boolean;
10
+ export declare function serviceSatisfiesCapabilities(service: HandlerService, requirements: CapabilityRequirements): boolean;
11
+ export declare function matchingServicesForFilter(index: ProductIndex, filterId: string, services: readonly HandlerService[]): HandlerService[];
12
+ export declare function findService(services: readonly HandlerService[], serviceId: ServiceId): HandlerService | undefined;
13
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,SAAS,EACV,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAa/F;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,iBAAiB,EAC7B,QAAQ,EAAE,MAAM,GACf,oBAAoB,CAEtB;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAE/F;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,cAAc,EACvB,YAAY,EAAE,sBAAsB,GACnC,OAAO,CAIT;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,cAAc,EAAE,GAClC,cAAc,EAAE,CAKlB;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,SAAS,EAAE,SAAS,GACnB,cAAc,GAAG,SAAS,CAE5B"}
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ import { createProductIndex } from "./indexer.js";
3
+ export function resolveCapabilities(index, filterId) {
4
+ const values = {};
5
+ const origins = {};
6
+ for (const filter of index.filterLineage(filterId)) {
7
+ for (const [capabilityId, required] of Object.entries(filter.capabilities ?? {})) {
8
+ if (Object.hasOwn(values, capabilityId))
9
+ continue;
10
+ values[capabilityId] = required;
11
+ origins[capabilityId] = filter.id;
12
+ }
13
+ }
14
+ return { values, origins };
15
+ }
16
+ export function resolveDefinitionCapabilities(definition, filterId) {
17
+ return resolveCapabilities(createProductIndex(definition), filterId);
18
+ }
19
+ export function serviceCapabilityEnabled(service, capabilityId) {
20
+ return service.capabilities[capabilityId]?.enabled === true;
21
+ }
22
+ export function serviceSatisfiesCapabilities(service, requirements) {
23
+ return Object.entries(requirements).every(([capabilityId, required]) => serviceCapabilityEnabled(service, capabilityId) === required);
24
+ }
25
+ export function matchingServicesForFilter(index, filterId, services) {
26
+ const requirements = resolveCapabilities(index, filterId).values;
27
+ return services.filter((service) => service.state === "enabled" && serviceSatisfiesCapabilities(service, requirements));
28
+ }
29
+ export function findService(services, serviceId) {
30
+ return services.find((service) => String(service.id) === String(serviceId));
31
+ }
32
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,wCAAwC;AASxC,OAAO,EAAE,kBAAkB,EAAqB,MAAM,cAAc,CAAC;AAOrE,MAAM,UAAU,mBAAmB,CAAC,KAAmB,EAAE,QAAgB;IACvE,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,MAAM,OAAO,GAA2B,EAAE,CAAC;IAE3C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;YACjF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;gBAAE,SAAS;YAClD,MAAM,CAAC,YAAY,CAAC,GAAG,QAAQ,CAAC;YAChC,OAAO,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,UAA6B,EAC7B,QAAgB;IAEhB,OAAO,mBAAmB,CAAC,kBAAkB,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAAuB,EAAE,YAAoB;IACpF,OAAO,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAuB,EACvB,YAAoC;IAEpC,OAAO,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,EAAE,CACrE,wBAAwB,CAAC,OAAO,EAAE,YAAY,CAAC,KAAK,QAAQ,CAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,KAAmB,EACnB,QAAgB,EAChB,QAAmC;IAEnC,MAAM,YAAY,GAAG,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC;IACjE,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,4BAA4B,CAAC,OAAO,EAAE,YAAY,CAAC,CAChG,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,QAAmC,EACnC,SAAoB;IAEpB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ProductField, ProductFilter } from "@elqora/dgp-spec";
2
+ import type { ProductIndex } from "./indexer.js";
3
+ export interface ResolvedFilterContext {
4
+ filter: ProductFilter;
5
+ lineage: ProductFilter[];
6
+ lineageDepths: ReadonlyMap<string, number>;
7
+ }
8
+ export declare function resolveFilterContext(index: ProductIndex, filterId: string): ResolvedFilterContext | undefined;
9
+ export declare function fieldOwnerDepth(field: ProductField, lineageDepths: ReadonlyMap<string, number>): number | undefined;
10
+ export declare function triggerOwnerDepth(index: ProductIndex, triggerId: string, lineageDepths: ReadonlyMap<string, number>): number | undefined;
11
+ export declare function relevantSelectedTriggers(index: ProductIndex, filterId: string, selectedTriggerIds: Iterable<string>): string[];
12
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,GACf,qBAAqB,GAAG,SAAS,CAYnC;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,YAAY,EACnB,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,MAAM,GAAG,SAAS,CAOpB;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GACnC,MAAM,EAAE,CAQV"}
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ export function resolveFilterContext(index, filterId) {
3
+ const filter = index.getFilter(filterId);
4
+ if (filter === undefined)
5
+ return undefined;
6
+ const lineage = index.filterLineage(filterId);
7
+ const lineageDepths = new Map();
8
+ for (let indexFromSelf = lineage.length - 1; indexFromSelf >= 0; indexFromSelf -= 1) {
9
+ const item = lineage[indexFromSelf];
10
+ if (item !== undefined)
11
+ lineageDepths.set(item.id, lineage.length - 1 - indexFromSelf);
12
+ }
13
+ return { filter, lineage, lineageDepths };
14
+ }
15
+ export function fieldOwnerDepth(field, lineageDepths) {
16
+ const bindIds = field.bind_id === undefined
17
+ ? []
18
+ : Array.isArray(field.bind_id)
19
+ ? field.bind_id
20
+ : [field.bind_id];
21
+ let closest;
22
+ for (const bindId of bindIds) {
23
+ const depth = lineageDepths.get(bindId);
24
+ if (depth !== undefined && (closest === undefined || depth < closest))
25
+ closest = depth;
26
+ }
27
+ return closest;
28
+ }
29
+ export function triggerOwnerDepth(index, triggerId, lineageDepths) {
30
+ const node = index.getNode(triggerId);
31
+ if (node.kind === "field") {
32
+ return node.field.button === true ? fieldOwnerDepth(node.field, lineageDepths) : undefined;
33
+ }
34
+ if (node.kind === "option")
35
+ return fieldOwnerDepth(node.field, lineageDepths);
36
+ return undefined;
37
+ }
38
+ export function relevantSelectedTriggers(index, filterId, selectedTriggerIds) {
39
+ const context = resolveFilterContext(index, filterId);
40
+ if (context === undefined)
41
+ return [];
42
+ const relevant = [];
43
+ for (const triggerId of selectedTriggerIds) {
44
+ if (triggerOwnerDepth(index, triggerId, context.lineageDepths) !== undefined)
45
+ relevant.push(triggerId);
46
+ }
47
+ return relevant;
48
+ }
49
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAYxC,MAAM,UAAU,oBAAoB,CAClC,KAAmB,EACnB,QAAgB;IAEhB,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAE3C,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,KAAK,IAAI,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,CAAC;QACpF,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS;YAAE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,KAAmB,EACnB,aAA0C;IAE1C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,KAAK,SAAS;QACzC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YAC5B,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtB,IAAI,OAA2B,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,GAAG,OAAO,CAAC;YAAE,OAAO,GAAG,KAAK,CAAC;IACzF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,KAAmB,EACnB,SAAiB,EACjB,aAA0C;IAE1C,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7F,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC9E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,KAAmB,EACnB,QAAgB,EAChB,kBAAoC;IAEpC,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACtD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;QAC3C,IAAI,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzG,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { FieldValueEffect, ProductDefinition } from "@elqora/dgp-spec";
2
+ import { type ProductIndex } from "./indexer.js";
3
+ export interface ResolvedValueEffect {
4
+ triggerId: string;
5
+ targetFieldId: string;
6
+ effect: FieldValueEffect;
7
+ }
8
+ export declare function resolveValueEffectsWithIndex(definition: ProductDefinition, index: ProductIndex, filterId: string, selectedTriggerIds: Iterable<string>): ResolvedValueEffect[];
9
+ export declare function resolveValueEffects(definition: ProductDefinition, filterId: string, selectedTriggerIds: Iterable<string>): ResolvedValueEffect[];
10
+ //# sourceMappingURL=effects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,iBAAiB,EAC7B,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GACnC,mBAAmB,EAAE,CAUvB;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,iBAAiB,EAC7B,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GACnC,mBAAmB,EAAE,CAOvB"}
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ import { relevantSelectedTriggers } from "./context.js";
3
+ import { createProductIndex } from "./indexer.js";
4
+ export function resolveValueEffectsWithIndex(definition, index, filterId, selectedTriggerIds) {
5
+ const effects = [];
6
+ for (const triggerId of relevantSelectedTriggers(index, filterId, selectedTriggerIds)) {
7
+ for (const [targetFieldId, effect] of Object.entries(definition.value_effects_for_triggers[triggerId] ?? {})) {
8
+ effects.push({ triggerId, targetFieldId, effect });
9
+ }
10
+ }
11
+ return effects;
12
+ }
13
+ export function resolveValueEffects(definition, filterId, selectedTriggerIds) {
14
+ return resolveValueEffectsWithIndex(definition, createProductIndex(definition), filterId, selectedTriggerIds);
15
+ }
16
+ //# sourceMappingURL=effects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effects.js","sourceRoot":"","sources":["../src/effects.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAIxC,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAqB,MAAM,cAAc,CAAC;AAQrE,MAAM,UAAU,4BAA4B,CAC1C,UAA6B,EAC7B,KAAmB,EACnB,QAAgB,EAChB,kBAAoC;IAEpC,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,KAAK,MAAM,SAAS,IAAI,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC,EAAE,CAAC;QACtF,KAAK,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAClD,UAAU,CAAC,0BAA0B,CAAC,SAAS,CAAC,IAAI,EAAE,CACvD,EAAE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,UAA6B,EAC7B,QAAgB,EAChB,kBAAoC;IAEpC,OAAO,4BAA4B,CACjC,UAAU,EACV,kBAAkB,CAAC,UAAU,CAAC,EAC9B,QAAQ,EACR,kBAAkB,CACnB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ export * from "./capabilities.js";
2
+ export * from "./context.js";
3
+ export * from "./effects.js";
4
+ export * from "./indexer.js";
5
+ export * from "./interpreter.js";
6
+ export * from "./options.js";
7
+ export * from "./services.js";
8
+ export * from "./visibility.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ export * from "./capabilities.js";
3
+ export * from "./context.js";
4
+ export * from "./effects.js";
5
+ export * from "./indexer.js";
6
+ export * from "./interpreter.js";
7
+ export * from "./options.js";
8
+ export * from "./services.js";
9
+ export * from "./visibility.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAExC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { FieldOption, ProductDefinition, ProductField, ProductFilter } from "@elqora/dgp-spec";
2
+ export type ProductNodeKind = "filter" | "field" | "option" | "unknown";
3
+ export type FilterRelation = "self" | "ancestor" | "descendant" | "unrelated";
4
+ export type IndexedProductNode = {
5
+ kind: "filter";
6
+ id: string;
7
+ filter: ProductFilter;
8
+ } | {
9
+ kind: "field";
10
+ id: string;
11
+ field: ProductField;
12
+ } | {
13
+ kind: "option";
14
+ id: string;
15
+ option: FieldOption;
16
+ field: ProductField;
17
+ } | {
18
+ kind: "unknown";
19
+ id: string;
20
+ };
21
+ export interface ProductIndex {
22
+ readonly definition: ProductDefinition;
23
+ getNode(id: string): IndexedProductNode;
24
+ getFilter(id: string): ProductFilter | undefined;
25
+ getField(id: string): ProductField | undefined;
26
+ getOption(id: string): FieldOption | undefined;
27
+ getOptionOwner(id: string): ProductField | undefined;
28
+ filterLineage(id: string): ProductFilter[];
29
+ filterChildren(id: string): ProductFilter[];
30
+ filterDescendants(id: string): ProductFilter[];
31
+ relationBetweenFilters(baseId: string, otherId: string): FilterRelation;
32
+ fieldBindIds(fieldOrId: ProductField | string): string[];
33
+ nodeFilterIds(nodeId: string): string[];
34
+ isFieldBoundWithin(fieldOrId: ProductField | string, filterId: string): boolean;
35
+ }
36
+ export declare function createProductIndex(definition: ProductDefinition): ProductIndex;
37
+ //# sourceMappingURL=indexer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.d.ts","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAIpG,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAE9E,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACxC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC/C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IAC/C,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IACrD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAC3C,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAC5C,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/C,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAAC;IACxE,YAAY,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;IACzD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxC,kBAAkB,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CACjF;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,GAAG,YAAY,CA8G9E"}
@@ -0,0 +1,119 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ import { walkFieldOptions } from "./options.js";
3
+ export function createProductIndex(definition) {
4
+ const filters = new Map();
5
+ const fields = new Map();
6
+ const options = new Map();
7
+ const children = new Map();
8
+ for (const filter of definition.filters) {
9
+ if (!filters.has(filter.id))
10
+ filters.set(filter.id, filter);
11
+ }
12
+ for (const field of definition.fields) {
13
+ if (!fields.has(field.id))
14
+ fields.set(field.id, field);
15
+ for (const visit of walkFieldOptions(field)) {
16
+ if (!options.has(visit.optionId)) {
17
+ options.set(visit.optionId, { option: visit.option, field });
18
+ }
19
+ }
20
+ }
21
+ for (const filter of definition.filters) {
22
+ if (filter.bind_id === undefined || !filters.has(filter.bind_id))
23
+ continue;
24
+ const siblings = children.get(filter.bind_id) ?? [];
25
+ siblings.push(filter);
26
+ children.set(filter.bind_id, siblings);
27
+ }
28
+ function getFilter(id) {
29
+ return filters.get(id);
30
+ }
31
+ function getField(id) {
32
+ return fields.get(id);
33
+ }
34
+ function filterLineage(id) {
35
+ const reversed = [];
36
+ const seen = new Set();
37
+ let current = filters.get(id);
38
+ while (current !== undefined && !seen.has(current.id)) {
39
+ reversed.push(current);
40
+ seen.add(current.id);
41
+ current = current.bind_id === undefined ? undefined : filters.get(current.bind_id);
42
+ }
43
+ return reversed.reverse();
44
+ }
45
+ function fieldBindIds(fieldOrId) {
46
+ const field = typeof fieldOrId === "string" ? fields.get(fieldOrId) : fieldOrId;
47
+ if (field?.bind_id === undefined)
48
+ return [];
49
+ return Array.isArray(field.bind_id) ? [...field.bind_id] : [field.bind_id];
50
+ }
51
+ function nodeFilterIds(nodeId) {
52
+ const filter = filters.get(nodeId);
53
+ if (filter !== undefined)
54
+ return [filter.id];
55
+ const field = fields.get(nodeId);
56
+ if (field !== undefined)
57
+ return fieldBindIds(field);
58
+ const option = options.get(nodeId);
59
+ return option === undefined ? [] : fieldBindIds(option.field);
60
+ }
61
+ function filterDescendants(id) {
62
+ const result = [];
63
+ const visited = new Set([id]);
64
+ const queue = [...(children.get(id) ?? [])];
65
+ while (queue.length > 0) {
66
+ const filter = queue.shift();
67
+ if (filter === undefined || visited.has(filter.id))
68
+ continue;
69
+ visited.add(filter.id);
70
+ result.push(filter);
71
+ queue.push(...(children.get(filter.id) ?? []));
72
+ }
73
+ return result;
74
+ }
75
+ return {
76
+ definition,
77
+ getNode(id) {
78
+ const filter = filters.get(id);
79
+ if (filter !== undefined)
80
+ return { kind: "filter", id, filter };
81
+ const field = fields.get(id);
82
+ if (field !== undefined)
83
+ return { kind: "field", id, field };
84
+ const option = options.get(id);
85
+ if (option !== undefined)
86
+ return { kind: "option", id, ...option };
87
+ return { kind: "unknown", id };
88
+ },
89
+ getFilter,
90
+ getField,
91
+ getOption(id) {
92
+ return options.get(id)?.option;
93
+ },
94
+ getOptionOwner(id) {
95
+ return options.get(id)?.field;
96
+ },
97
+ filterLineage,
98
+ filterChildren(id) {
99
+ return [...(children.get(id) ?? [])];
100
+ },
101
+ filterDescendants,
102
+ relationBetweenFilters(baseId, otherId) {
103
+ if (baseId === otherId && filters.has(baseId))
104
+ return "self";
105
+ if (filterLineage(baseId).some((filter) => filter.id === otherId))
106
+ return "ancestor";
107
+ if (filterLineage(otherId).some((filter) => filter.id === baseId))
108
+ return "descendant";
109
+ return "unrelated";
110
+ },
111
+ fieldBindIds,
112
+ nodeFilterIds,
113
+ isFieldBoundWithin(fieldOrId, filterId) {
114
+ const lineage = new Set(filterLineage(filterId).map((filter) => filter.id));
115
+ return fieldBindIds(fieldOrId).some((id) => lineage.has(id));
116
+ },
117
+ };
118
+ }
119
+ //# sourceMappingURL=indexer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { HandlerService, ProductDefinition, ServiceId } from "@elqora/dgp-spec";
2
+ import { type ResolvedCapabilities } from "./capabilities.js";
3
+ import { type ResolvedFilterContext } from "./context.js";
4
+ import { type ResolvedValueEffect } from "./effects.js";
5
+ import { type ProductIndex } from "./indexer.js";
6
+ import { type ResolvedServiceBindings } from "./services.js";
7
+ import { type ResolvedVisibility } from "./visibility.js";
8
+ export interface ResolvedProductContext {
9
+ filter: ResolvedFilterContext;
10
+ capabilities: ResolvedCapabilities;
11
+ visibility: ResolvedVisibility;
12
+ valueEffects: ResolvedValueEffect[];
13
+ }
14
+ export interface ProductInterpreter {
15
+ readonly definition: ProductDefinition;
16
+ readonly index: ProductIndex;
17
+ resolveFilter(filterId: string): ResolvedFilterContext | undefined;
18
+ resolveCapabilities(filterId: string): ResolvedCapabilities;
19
+ resolveVisibility(filterId: string, selectedTriggerIds?: Iterable<string>): ResolvedVisibility;
20
+ resolveValueEffects(filterId: string, selectedTriggerIds: Iterable<string>): ResolvedValueEffect[];
21
+ resolveContext(filterId: string, selectedTriggerIds?: Iterable<string>): ResolvedProductContext | undefined;
22
+ serviceBindingForNode(nodeId: string): ServiceId | undefined;
23
+ resolveServiceBindings(): ResolvedServiceBindings;
24
+ resolveFallbackCandidates(primaryServiceId: ServiceId, nodeId?: string): ServiceId[];
25
+ fallbackCandidatesForNode(nodeId: string): ServiceId[];
26
+ matchingServicesForFilter(filterId: string, services: readonly HandlerService[]): HandlerService[];
27
+ }
28
+ export declare function createProductInterpreter(definition: ProductDefinition): ProductInterpreter;
29
+ //# sourceMappingURL=interpreter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../src/interpreter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAErF,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAgC,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAKL,KAAK,uBAAuB,EAC7B,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,YAAY,EAAE,oBAAoB,CAAC;IACnC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,YAAY,EAAE,mBAAmB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAAC;IACnE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAC5D,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC;IAC/F,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,mBAAmB,EAAE,CAAC;IACnG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,sBAAsB,GAAG,SAAS,CAAC;IAC5G,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAC7D,sBAAsB,IAAI,uBAAuB,CAAC;IAClD,yBAAyB,CAAC,gBAAgB,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC;IACrF,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC;IACvD,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,cAAc,EAAE,CAAC;CACpG;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,iBAAiB,GAAG,kBAAkB,CA2C1F"}
@@ -0,0 +1,53 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ import { matchingServicesForFilter, resolveCapabilities, } from "./capabilities.js";
3
+ import { resolveFilterContext } from "./context.js";
4
+ import { resolveValueEffectsWithIndex } from "./effects.js";
5
+ import { createProductIndex } from "./indexer.js";
6
+ import { fallbackCandidatesForNode, resolveFallbackCandidates, resolveServiceBindingsWithIndex, serviceBindingForNode, } from "./services.js";
7
+ import { resolveVisibilityWithIndex, } from "./visibility.js";
8
+ export function createProductInterpreter(definition) {
9
+ const index = createProductIndex(definition);
10
+ return {
11
+ definition,
12
+ index,
13
+ resolveFilter(filterId) {
14
+ return resolveFilterContext(index, filterId);
15
+ },
16
+ resolveCapabilities(filterId) {
17
+ return resolveCapabilities(index, filterId);
18
+ },
19
+ resolveVisibility(filterId, selectedTriggerIds = []) {
20
+ return resolveVisibilityWithIndex(definition, index, filterId, selectedTriggerIds);
21
+ },
22
+ resolveValueEffects(filterId, selectedTriggerIds) {
23
+ return resolveValueEffectsWithIndex(definition, index, filterId, selectedTriggerIds);
24
+ },
25
+ resolveContext(filterId, selectedTriggerIds = []) {
26
+ const filter = resolveFilterContext(index, filterId);
27
+ if (filter === undefined)
28
+ return undefined;
29
+ return {
30
+ filter,
31
+ capabilities: resolveCapabilities(index, filterId),
32
+ visibility: resolveVisibilityWithIndex(definition, index, filterId, selectedTriggerIds),
33
+ valueEffects: resolveValueEffectsWithIndex(definition, index, filterId, selectedTriggerIds),
34
+ };
35
+ },
36
+ serviceBindingForNode(nodeId) {
37
+ return serviceBindingForNode(index, nodeId);
38
+ },
39
+ resolveServiceBindings() {
40
+ return resolveServiceBindingsWithIndex(definition, index);
41
+ },
42
+ resolveFallbackCandidates(primaryServiceId, nodeId) {
43
+ return resolveFallbackCandidates(definition, primaryServiceId, nodeId);
44
+ },
45
+ fallbackCandidatesForNode(nodeId) {
46
+ return fallbackCandidatesForNode(definition, index, nodeId);
47
+ },
48
+ matchingServicesForFilter(filterId, services) {
49
+ return matchingServicesForFilter(index, filterId, services);
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=interpreter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.js","sourceRoot":"","sources":["../src/interpreter.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAIxC,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GAEpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAA8B,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,4BAA4B,EAA4B,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAqB,MAAM,cAAc,CAAC;AACrE,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,+BAA+B,EAC/B,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,GAE3B,MAAM,iBAAiB,CAAC;AAwBzB,MAAM,UAAU,wBAAwB,CAAC,UAA6B;IACpE,MAAM,KAAK,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAC7C,OAAO;QACL,UAAU;QACV,KAAK;QACL,aAAa,CAAC,QAAQ;YACpB,OAAO,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC/C,CAAC;QACD,mBAAmB,CAAC,QAAQ;YAC1B,OAAO,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC9C,CAAC;QACD,iBAAiB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE;YACjD,OAAO,0BAA0B,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACrF,CAAC;QACD,mBAAmB,CAAC,QAAQ,EAAE,kBAAkB;YAC9C,OAAO,4BAA4B,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACvF,CAAC;QACD,cAAc,CAAC,QAAQ,EAAE,kBAAkB,GAAG,EAAE;YAC9C,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACrD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC3C,OAAO;gBACL,MAAM;gBACN,YAAY,EAAE,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAClD,UAAU,EAAE,0BAA0B,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC;gBACvF,YAAY,EAAE,4BAA4B,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,CAAC;aAC5F,CAAC;QACJ,CAAC;QACD,qBAAqB,CAAC,MAAM;YAC1B,OAAO,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QACD,sBAAsB;YACpB,OAAO,+BAA+B,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC;QACD,yBAAyB,CAAC,gBAAgB,EAAE,MAAM;YAChD,OAAO,yBAAyB,CAAC,UAAU,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;QACzE,CAAC;QACD,yBAAyB,CAAC,MAAM;YAC9B,OAAO,yBAAyB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9D,CAAC;QACD,yBAAyB,CAAC,QAAQ,EAAE,QAAQ;YAC1C,OAAO,yBAAyB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { FieldOption, ProductDefinition, ProductField } from "@elqora/dgp-spec";
2
+ export interface OptionVisit {
3
+ field: ProductField;
4
+ fieldId: string;
5
+ option: FieldOption;
6
+ optionId: string;
7
+ depth: number;
8
+ parentId?: string;
9
+ }
10
+ export declare function walkFieldOptions(field: ProductField): OptionVisit[];
11
+ export declare function walkOptions(definition: ProductDefinition): OptionVisit[];
12
+ export declare function fieldOptionIds(field: ProductField): string[];
13
+ export declare function findFieldOption(field: ProductField | undefined, optionId: string): FieldOption | undefined;
14
+ export declare function filterFieldOptionsById(options: readonly FieldOption[] | undefined, allowed: ReadonlySet<string>): FieldOption[] | undefined;
15
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAmBnE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,iBAAiB,GAAG,WAAW,EAAE,CAExE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,EAAE,CAE5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAI1G;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,EAC3C,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,WAAW,EAAE,GAAG,SAAS,CAiB3B"}
@@ -0,0 +1,48 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ export function walkFieldOptions(field) {
3
+ const visits = [];
4
+ function visit(options, depth, parentId) {
5
+ for (const option of options ?? []) {
6
+ visits.push({
7
+ field,
8
+ fieldId: field.id,
9
+ option,
10
+ optionId: option.id,
11
+ depth,
12
+ ...(parentId === undefined ? {} : { parentId }),
13
+ });
14
+ visit(option.children, depth + 1, option.id);
15
+ }
16
+ }
17
+ visit(field.options, 0);
18
+ return visits;
19
+ }
20
+ export function walkOptions(definition) {
21
+ return definition.fields.flatMap((field) => walkFieldOptions(field));
22
+ }
23
+ export function fieldOptionIds(field) {
24
+ return walkFieldOptions(field).map((visit) => visit.optionId);
25
+ }
26
+ export function findFieldOption(field, optionId) {
27
+ return field === undefined
28
+ ? undefined
29
+ : walkFieldOptions(field).find((visit) => visit.optionId === optionId)?.option;
30
+ }
31
+ export function filterFieldOptionsById(options, allowed) {
32
+ if (options === undefined) {
33
+ return undefined;
34
+ }
35
+ const result = [];
36
+ for (const option of options) {
37
+ const children = filterFieldOptionsById(option.children, allowed);
38
+ if (!allowed.has(option.id) && (children === undefined || children.length === 0)) {
39
+ continue;
40
+ }
41
+ result.push({
42
+ ...option,
43
+ ...(children === undefined ? {} : { children }),
44
+ });
45
+ }
46
+ return result;
47
+ }
48
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAaxC,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,SAAS,KAAK,CAAC,OAA2C,EAAE,KAAa,EAAE,QAAiB;QAC1F,KAAK,MAAM,MAAM,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK;gBACL,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,MAAM;gBACN,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACnB,KAAK;gBACL,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;aAChD,CAAC,CAAC;YACH,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAA6B;IACvD,OAAO,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA+B,EAAE,QAAgB;IAC/E,OAAO,KAAK,KAAK,SAAS;QACxB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,EAAE,MAAM,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAA2C,EAC3C,OAA4B;IAE5B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YACjF,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC;YACV,GAAG,MAAM;YACT,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;SAChD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}