@fgv/ts-res 5.0.1-9 → 5.0.1

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.
Files changed (162) hide show
  1. package/dist/index.browser.js +53 -0
  2. package/dist/index.js +45 -0
  3. package/dist/packlets/bundle/bundleBuilder.js +130 -0
  4. package/dist/packlets/bundle/bundleLoader.js +101 -0
  5. package/dist/packlets/bundle/bundleNormalizer.js +138 -0
  6. package/dist/packlets/bundle/bundleUtils.js +113 -0
  7. package/dist/packlets/bundle/convert.js +75 -0
  8. package/dist/packlets/bundle/index.js +42 -0
  9. package/dist/packlets/bundle/model.js +23 -0
  10. package/dist/packlets/common/conditions.js +47 -0
  11. package/dist/packlets/common/convert.js +172 -0
  12. package/dist/packlets/common/helpers/conditions.js +66 -0
  13. package/dist/packlets/common/helpers/context.js +70 -0
  14. package/dist/packlets/common/helpers/index.js +26 -0
  15. package/dist/packlets/common/helpers/qualifierDefaultValues.js +66 -0
  16. package/dist/packlets/common/helpers/resources.js +93 -0
  17. package/dist/packlets/common/index.js +28 -0
  18. package/dist/packlets/common/resources.js +27 -0
  19. package/dist/packlets/common/validate/conditions.js +544 -0
  20. package/dist/packlets/common/validate/index.js +26 -0
  21. package/dist/packlets/common/validate/regularExpressions.js +84 -0
  22. package/dist/packlets/common/validate/resources.js +209 -0
  23. package/dist/packlets/conditions/condition.js +252 -0
  24. package/dist/packlets/conditions/conditionCollector.js +69 -0
  25. package/dist/packlets/conditions/conditionDecls.js +23 -0
  26. package/dist/packlets/conditions/conditionSet.js +247 -0
  27. package/dist/packlets/conditions/conditionSetCollector.js +89 -0
  28. package/dist/packlets/conditions/conditionSetDecls.js +23 -0
  29. package/dist/packlets/conditions/conditionToken.js +147 -0
  30. package/dist/packlets/conditions/convert/conditionSetDecls.js +51 -0
  31. package/dist/packlets/conditions/convert/decls.js +75 -0
  32. package/dist/packlets/conditions/convert/index.js +24 -0
  33. package/dist/packlets/conditions/index.js +31 -0
  34. package/dist/packlets/config/common.js +78 -0
  35. package/dist/packlets/config/configInitFactory.js +258 -0
  36. package/dist/packlets/config/convert.js +56 -0
  37. package/dist/packlets/config/index.browser.js +34 -0
  38. package/dist/packlets/config/index.js +28 -0
  39. package/dist/packlets/config/json.js +23 -0
  40. package/dist/packlets/config/predefined/default.js +138 -0
  41. package/dist/packlets/config/predefined/extended.js +190 -0
  42. package/dist/packlets/config/predefined/index.js +25 -0
  43. package/dist/packlets/config/systemConfiguration.js +147 -0
  44. package/dist/packlets/context/contextDecls.js +23 -0
  45. package/dist/packlets/context/contextToken.js +202 -0
  46. package/dist/packlets/context/convert/decls.js +91 -0
  47. package/dist/packlets/context/convert/index.js +23 -0
  48. package/dist/packlets/context/index.js +26 -0
  49. package/dist/packlets/decisions/abstractDecision.js +68 -0
  50. package/dist/packlets/decisions/abstractDecisionCollector.js +90 -0
  51. package/dist/packlets/decisions/candidate.js +76 -0
  52. package/dist/packlets/decisions/common.js +23 -0
  53. package/dist/packlets/decisions/concreteDecision.js +111 -0
  54. package/dist/packlets/decisions/decision.js +126 -0
  55. package/dist/packlets/decisions/index.js +28 -0
  56. package/dist/packlets/import/fsItem.js +134 -0
  57. package/dist/packlets/import/importContext.js +129 -0
  58. package/dist/packlets/import/importManager.js +129 -0
  59. package/dist/packlets/import/importable.js +32 -0
  60. package/dist/packlets/import/importers/collectionImporter.js +118 -0
  61. package/dist/packlets/import/importers/fsItemImporter.js +116 -0
  62. package/dist/packlets/import/importers/importer.js +23 -0
  63. package/dist/packlets/import/importers/index.browser.js +29 -0
  64. package/dist/packlets/import/importers/index.js +27 -0
  65. package/dist/packlets/import/importers/jsonImporter.js +94 -0
  66. package/dist/packlets/import/importers/pathImporter.js +84 -0
  67. package/dist/packlets/import/index.browser.js +34 -0
  68. package/dist/packlets/import/index.js +28 -0
  69. package/dist/packlets/qualifier-types/config/convert.js +124 -0
  70. package/dist/packlets/qualifier-types/config/index.js +25 -0
  71. package/dist/packlets/qualifier-types/config/json.js +32 -0
  72. package/dist/packlets/qualifier-types/convert.js +56 -0
  73. package/dist/packlets/qualifier-types/helpers.js +82 -0
  74. package/dist/packlets/qualifier-types/index.js +32 -0
  75. package/dist/packlets/qualifier-types/languageQualifierType.js +142 -0
  76. package/dist/packlets/qualifier-types/literalQualifierType.js +200 -0
  77. package/dist/packlets/qualifier-types/literalValueHierarchy.js +236 -0
  78. package/dist/packlets/qualifier-types/qualifierType.js +184 -0
  79. package/dist/packlets/qualifier-types/qualifierTypeCollector.js +66 -0
  80. package/dist/packlets/qualifier-types/territoryQualifierType.js +200 -0
  81. package/dist/packlets/qualifiers/convert/decls.js +70 -0
  82. package/dist/packlets/qualifiers/convert/index.js +24 -0
  83. package/dist/packlets/qualifiers/convert/qualifier.js +40 -0
  84. package/dist/packlets/qualifiers/index.js +29 -0
  85. package/dist/packlets/qualifiers/qualifier.js +108 -0
  86. package/dist/packlets/qualifiers/qualifierCollector.js +123 -0
  87. package/dist/packlets/qualifiers/qualifierDecl.js +23 -0
  88. package/dist/packlets/qualifiers/qualifierDefaultValueDecls.js +23 -0
  89. package/dist/packlets/qualifiers/qualifierDefaultValueToken.js +175 -0
  90. package/dist/packlets/resource-json/compiled/common.js +23 -0
  91. package/dist/packlets/resource-json/compiled/convert.js +132 -0
  92. package/dist/packlets/resource-json/compiled/index.js +26 -0
  93. package/dist/packlets/resource-json/compiled/json.js +2 -0
  94. package/dist/packlets/resource-json/convert.js +171 -0
  95. package/dist/packlets/resource-json/helpers.js +241 -0
  96. package/dist/packlets/resource-json/index.js +31 -0
  97. package/dist/packlets/resource-json/json.js +36 -0
  98. package/dist/packlets/resource-json/normalized.js +23 -0
  99. package/dist/packlets/resource-json/resourceDeclCollection.js +88 -0
  100. package/dist/packlets/resource-json/resourceDeclContainer.js +23 -0
  101. package/dist/packlets/resource-json/resourceDeclTree.js +94 -0
  102. package/dist/packlets/resource-types/config/convert.js +35 -0
  103. package/dist/packlets/resource-types/config/index.js +25 -0
  104. package/dist/packlets/resource-types/config/json.js +23 -0
  105. package/dist/packlets/resource-types/helpers.js +42 -0
  106. package/dist/packlets/resource-types/index.js +28 -0
  107. package/dist/packlets/resource-types/jsonResourceType.js +66 -0
  108. package/dist/packlets/resource-types/resourceType.js +95 -0
  109. package/dist/packlets/resource-types/resourceTypeCollector.js +61 -0
  110. package/dist/packlets/resources/candidateReducer.js +246 -0
  111. package/dist/packlets/resources/candidateValue.js +92 -0
  112. package/dist/packlets/resources/candidateValueCollector.js +94 -0
  113. package/dist/packlets/resources/common.js +23 -0
  114. package/dist/packlets/resources/deltaGenerator.js +338 -0
  115. package/dist/packlets/resources/index.js +31 -0
  116. package/dist/packlets/resources/resource.js +207 -0
  117. package/dist/packlets/resources/resourceBuilder.js +183 -0
  118. package/dist/packlets/resources/resourceCandidate.js +216 -0
  119. package/dist/packlets/resources/resourceManagerBuilder.js +890 -0
  120. package/dist/packlets/runtime/cacheListener.js +58 -0
  121. package/dist/packlets/runtime/cacheMetrics.js +149 -0
  122. package/dist/packlets/runtime/compiledResourceCollection.js +473 -0
  123. package/dist/packlets/runtime/conditionSetResolutionResult.js +134 -0
  124. package/dist/packlets/runtime/context/contextQualifierProvider.js +29 -0
  125. package/dist/packlets/runtime/context/contextQualifierProviderValidator.js +146 -0
  126. package/dist/packlets/runtime/context/index.js +26 -0
  127. package/dist/packlets/runtime/context/simpleContextQualifierProvider.js +196 -0
  128. package/dist/packlets/runtime/context/validatingSimpleContextQualifierProvider.js +60 -0
  129. package/dist/packlets/runtime/iResourceManager.js +23 -0
  130. package/dist/packlets/runtime/index.js +34 -0
  131. package/dist/packlets/runtime/resource-tree/common.js +23 -0
  132. package/dist/packlets/runtime/resource-tree/index.js +26 -0
  133. package/dist/packlets/runtime/resource-tree/readOnlyResourceTree.js +216 -0
  134. package/dist/packlets/runtime/resource-tree/resourceTreeChildren.js +97 -0
  135. package/dist/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js +161 -0
  136. package/dist/packlets/runtime/resourceResolver.js +481 -0
  137. package/dist/packlets/runtime/resourceTreeResolver.js +220 -0
  138. package/dist/packlets/runtime/validate.js +47 -0
  139. package/dist/packlets/zip-archive/convert.js +100 -0
  140. package/dist/packlets/zip-archive/index.browser.js +54 -0
  141. package/dist/packlets/zip-archive/index.js +47 -0
  142. package/dist/packlets/zip-archive/json.js +23 -0
  143. package/dist/packlets/zip-archive/types.js +36 -0
  144. package/dist/packlets/zip-archive/zipArchiveCreator.js +191 -0
  145. package/dist/packlets/zip-archive/zipArchiveFormat.js +140 -0
  146. package/dist/packlets/zip-archive/zipArchiveLoader.js +282 -0
  147. package/dist/test/data/sample.json +32 -0
  148. package/dist/test/unit/qualifier-types/testQualifierType.js +76 -0
  149. package/dist/test/unit/resource-types/testDerivedResourceType.js +109 -0
  150. package/dist/test/unit/resources/deltaGenerator.helpers.js +282 -0
  151. package/dist/tsdoc-metadata.json +1 -1
  152. package/lib/index.browser.d.ts +24 -0
  153. package/lib/index.browser.js +116 -0
  154. package/lib/packlets/config/index.browser.d.ts +7 -0
  155. package/lib/packlets/config/index.browser.js +74 -0
  156. package/lib/packlets/import/importers/index.browser.d.ts +4 -0
  157. package/lib/packlets/import/importers/index.browser.js +45 -0
  158. package/lib/packlets/import/index.browser.d.ts +7 -0
  159. package/lib/packlets/import/index.browser.js +74 -0
  160. package/lib/packlets/zip-archive/index.browser.d.ts +27 -0
  161. package/lib/packlets/zip-archive/index.browser.js +102 -0
  162. package/package.json +21 -7
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ export * from './decls';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import * as Convert from './convert';
23
+ export * from './contextDecls';
24
+ export * from './contextToken';
25
+ export { Convert };
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,68 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { captureResult } from '@fgv/ts-utils';
23
+ import { Candidate } from './candidate';
24
+ import { Decision } from './decision';
25
+ /**
26
+ * An abstract decision represents a class of decisions with candidates
27
+ * that differ only in value. It is a {@link Decisions.Decision | IDecision<number>}
28
+ * in which the `number` values are sequentially assigned indexes.
29
+ * This allows us to represent each related {@link Decisions.IDecision | decision} as an
30
+ * {@link Decisions.AbstractDecision | abstract decision} and a matching array containing
31
+ * the corresponding value for each candidate. This representation is highly cacheable.
32
+ * @public
33
+ */
34
+ export class AbstractDecision extends Decision {
35
+ /**
36
+ * Constructor for an {@link Decisions.AbstractDecision | AbstractDecision} object.
37
+ * @param params - {@link Decisions.IAbstractDecisionCreateParams | Parameters}
38
+ * used to create the decision.
39
+ * @public
40
+ */
41
+ constructor(params) {
42
+ const candidates = Array.from(params.conditionSets)
43
+ .map((conditionSet, value) => Candidate.createCandidate({ conditionSet, value }).orThrow())
44
+ .sort(Candidate.compare);
45
+ super({ candidates, index: params.index, isAbstract: true });
46
+ }
47
+ /**
48
+ * Creates a new {@link Decisions.AbstractDecision | AbstractDecision} object.
49
+ * @param params - {@link Decisions.IAbstractDecisionCreateParams | Parameters}
50
+ * used to create the decision.
51
+ * @returns `Success` with the new decision if successful, or `Failure` with an
52
+ * error message if not.
53
+ * @public
54
+ */
55
+ static createAbstractDecision(params) {
56
+ return captureResult(() => new AbstractDecision(params));
57
+ }
58
+ /**
59
+ * Converts this abstract decision to a compiled abstract decision representation.
60
+ * @param options - Optional compilation options controlling the output format.
61
+ * @returns A compiled abstract decision object that can be used for serialization or runtime processing.
62
+ * @public
63
+ */
64
+ toCompiled(options) {
65
+ return Object.assign({ conditionSets: this.candidates.map((c) => c.conditionSet.index) }, ((options === null || options === void 0 ? void 0 : options.includeMetadata) === true ? { metadata: { key: this.key } } : {}));
66
+ }
67
+ }
68
+ //# sourceMappingURL=abstractDecision.js.map
@@ -0,0 +1,90 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { captureResult, Collections, fail, succeed, ValidatingCollector } from '@fgv/ts-utils';
23
+ import { AbstractDecision } from './abstractDecision';
24
+ import { Convert as CommonConvert, Validate } from '../common';
25
+ import { ConditionSet } from '../conditions';
26
+ /**
27
+ * A `ValidatingCollector` for {@link Decisions.AbstractDecision | AbstractDecisions}.
28
+ * @public
29
+ */
30
+ export class AbstractDecisionCollector extends ValidatingCollector {
31
+ /**
32
+ * The empty decision (no condition sets) for this collector.
33
+ */
34
+ get emptyDecision() {
35
+ return this.getAt(AbstractDecisionCollector.EmptyDecisionIndex).orThrow();
36
+ }
37
+ /**
38
+ * The default-only decision (one condition set with no conditions) for this collector.
39
+ */
40
+ get defaultOnlyDecision() {
41
+ return this.getAt(AbstractDecisionCollector.DefaultOnlyDecisionIndex).orThrow();
42
+ }
43
+ /**
44
+ * Creates a new instance of {@link Decisions.AbstractDecisionCollector | AbstractDecisionCollector}.
45
+ */
46
+ constructor(params) {
47
+ super({
48
+ converters: new Collections.KeyValueConverters({
49
+ key: CommonConvert.decisionKey,
50
+ value: (from) => this._toAbstractDecision(from)
51
+ })
52
+ });
53
+ this.conditionSets = params.conditionSets;
54
+ this.add(AbstractDecision.createAbstractDecision({ conditionSets: [] }).orThrow()).orThrow();
55
+ const cs = this.conditionSets.validating.get('').orThrow();
56
+ this.add(AbstractDecision.createAbstractDecision({ conditionSets: [cs] }).orThrow()).orThrow();
57
+ }
58
+ /**
59
+ * Creates a new instance of {@link Decisions.AbstractDecisionCollector | AbstractDecisionCollector}.
60
+ * @returns `Success` with the new instance, or `Failure` with an error if the instance could not be created.
61
+ */
62
+ static create(params) {
63
+ return captureResult(() => new AbstractDecisionCollector(params));
64
+ }
65
+ _toAbstractDecision(from) {
66
+ /* c8 ignore next 3 - functional code path tested but coverage intermittently missed */
67
+ if (from instanceof AbstractDecision) {
68
+ return succeed(from);
69
+ }
70
+ if (this._isConditionSetArray(from)) {
71
+ return AbstractDecision.createAbstractDecision({
72
+ conditionSets: from
73
+ });
74
+ }
75
+ /* c8 ignore next 2 - functional code path tested but coverage intermittently missed */
76
+ return fail('invalid value: not an abstract decision or condition sets');
77
+ }
78
+ _isConditionSetArray(from) {
79
+ return Array.isArray(from) && from.every((e) => e instanceof ConditionSet);
80
+ }
81
+ }
82
+ /**
83
+ * The index for the empty decision.
84
+ */
85
+ AbstractDecisionCollector.EmptyDecisionIndex = Validate.toDecisionIndex(0).orThrow();
86
+ /**
87
+ * The index for the default-only decision.
88
+ */
89
+ AbstractDecisionCollector.DefaultOnlyDecisionIndex = Validate.toDecisionIndex(1).orThrow();
90
+ //# sourceMappingURL=abstractDecisionCollector.js.map
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { ConditionSet } from '../conditions';
23
+ import { captureResult } from '@fgv/ts-utils';
24
+ /**
25
+ * Simple implementation of {@link Decisions.ICandidate | ICandidate} with
26
+ * helper methods for sorting and presentation.
27
+ * @public
28
+ */
29
+ export class Candidate {
30
+ /**
31
+ * Key of the condition set for this candidate.
32
+ */
33
+ get key() {
34
+ return this.conditionSet.key;
35
+ }
36
+ /**
37
+ * Construct a new {@link Decisions.Candidate | Candidate}.
38
+ * @param params - The {@link Decisions.ICandidate | parameters} to use to create the
39
+ * new candidate.
40
+ */
41
+ constructor(params) {
42
+ var _a;
43
+ this.conditionSet = params.conditionSet;
44
+ this.value = params.value;
45
+ this.isPartial = params.isPartial === true;
46
+ this.mergeMethod = (_a = params.mergeMethod) !== null && _a !== void 0 ? _a : 'augment';
47
+ }
48
+ /**
49
+ * Create a new {@link Decisions.Candidate | candidate}.
50
+ * @param params - The {@link Decisions.ICandidate | parameters} to use to create the
51
+ * new candidate.
52
+ * @returns `Success` with the new candidate if successful, or `Failure` if the
53
+ * candidate could not be created.
54
+ */
55
+ static createCandidate(params) {
56
+ return captureResult(() => new Candidate(params));
57
+ }
58
+ /**
59
+ * Compare two {@link Decisions.ICandidate | candidates} for sorting purposes.
60
+ * @param c1 - The first candidate to compare.
61
+ * @param c2 - The second candidate to compare.
62
+ * @returns A negative number if c1 should come before c2, a positive number if c1 should
63
+ * come after c2, or zero if they are equivalent.
64
+ */
65
+ static compare(c1, c2) {
66
+ return ConditionSet.compare(c1.conditionSet, c2.conditionSet);
67
+ }
68
+ /**
69
+ * Returns a string representation of the {@link Decisions.Candidate | candidate}.
70
+ * @returns A string representation of this candidate.
71
+ */
72
+ toString() {
73
+ return `${this.key}: ${JSON.stringify(this.value)}`;
74
+ }
75
+ }
76
+ //# sourceMappingURL=candidate.js.map
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ export {};
23
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1,111 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { Candidate } from './candidate';
23
+ import { captureResult, Collections, mapResults, fail, succeed } from '@fgv/ts-utils';
24
+ import { ConditionSet } from '../conditions';
25
+ import { Convert as CommonConvert } from '../common';
26
+ import { Decision } from './decision';
27
+ /**
28
+ * A {@link Decisions.ConcreteDecision | concrete decision} is a {@link Decisions.IDecision | decision}
29
+ * implemented as a reference to a common {@link Decisions.AbstractDecision | abstract decision} and a list of
30
+ * values that correspond to the candidates in the abstract decision. This allows us to represent a large
31
+ * number of related decisions with a single abstract decision and a list of values.
32
+ * @public
33
+ */
34
+ export class ConcreteDecision {
35
+ /**
36
+ * Unique global key for this decision, derived from the condition set and
37
+ * candidate values.
38
+ */
39
+ get key() {
40
+ return this._collectible.key;
41
+ }
42
+ /**
43
+ * Unique global index for this decision.
44
+ */
45
+ get index() {
46
+ return this._collectible.index;
47
+ }
48
+ /**
49
+ * Constructor for a {@link Decisions.ConcreteDecision | ConcreteDecision} object.
50
+ * @param params - {@link Decisions.IConcreteDecisionConstructorParams | Parameters}
51
+ * used to create the decision.
52
+ * @public
53
+ */
54
+ constructor(params) {
55
+ this.baseDecision = params.baseDecision;
56
+ this.values = params.values;
57
+ this.candidates = this.baseDecision.candidates.map((candidate) => {
58
+ const value = this.values[candidate.value];
59
+ return Candidate.createCandidate({ conditionSet: candidate.conditionSet, value }).orThrow();
60
+ });
61
+ this._collectible = new Collections.Collectible({
62
+ key: Decision.getKey(this.candidates),
63
+ index: params.index,
64
+ indexConverter: CommonConvert.decisionIndex
65
+ });
66
+ }
67
+ /**
68
+ * Creates a new {@link Decisions.ConcreteDecision | ConcreteDecision} object.
69
+ * @param params - {@link Decisions.IConcreteDecisionCreateParams | Parameters}
70
+ * used to create the decision.
71
+ * @returns `Success` with the new decision if successful, or `Failure` with an
72
+ * error message if not.
73
+ * @public
74
+ */
75
+ static create(params) {
76
+ const conditionSets = params.candidates
77
+ .map((candidate) => candidate.conditionSet)
78
+ .sort(ConditionSet.compare)
79
+ .reverse();
80
+ const getBase = params.decisions.validating.getOrAdd(conditionSets);
81
+ /* c8 ignore next 3 - defense in depth against internal error hard to repro */
82
+ if (getBase.isFailure()) {
83
+ return fail(getBase.message);
84
+ }
85
+ const baseDecision = getBase.value;
86
+ return mapResults(params.candidates.map((candidate, index) => {
87
+ /* c8 ignore next 5 - defense in depth against internal error hard to repro */
88
+ if (candidate.conditionSet.key !== baseDecision.candidates[index].conditionSet.key) {
89
+ return fail(`${candidate.conditionSet.key}: Candidate does not match base decision ${candidate.conditionSet.key}`);
90
+ }
91
+ return succeed(candidate.value);
92
+ })).onSuccess((values) => {
93
+ /* c8 ignore next 5 - defense in depth against invalid index conversion */
94
+ if (params.index) {
95
+ return CommonConvert.decisionIndex.convert(params.index).onSuccess((index) => {
96
+ return captureResult(() => new ConcreteDecision({ baseDecision, values, index }));
97
+ });
98
+ }
99
+ return captureResult(() => new ConcreteDecision({ baseDecision, values }));
100
+ });
101
+ }
102
+ /**
103
+ * Sets the index for this decision. Once set, index is immutable.
104
+ * @param index - The index to set.
105
+ * @returns `Success` with the new index if successful, or `Failure` with an error message if not.
106
+ */
107
+ setIndex(index) {
108
+ return this._collectible.setIndex(index);
109
+ }
110
+ }
111
+ //# sourceMappingURL=concreteDecision.js.map
@@ -0,0 +1,126 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ import { captureResult, Collections, Hash } from '@fgv/ts-utils';
23
+ import { Convert as CommonConvert } from '../common';
24
+ import { Candidate } from './candidate';
25
+ import { ConditionSet } from '../conditions';
26
+ /**
27
+ * Simple collectible implementation of {@link Decisions.IDecision | IDecision}.
28
+ * @public
29
+ */
30
+ export class Decision {
31
+ /**
32
+ * Unique global key for this decision, derived from the contents
33
+ * of the decision.
34
+ */
35
+ get key() {
36
+ return this._collectible.key;
37
+ }
38
+ /**
39
+ * Unique global index for this decision.
40
+ */
41
+ get index() {
42
+ return this._collectible.index;
43
+ }
44
+ /**
45
+ * Constructor for a {@link Decisions.Decision | Decision} object.
46
+ * @param params - {@link Decisions.IDecisionConstructorParams | Parameters} used to create the decision.
47
+ * @public
48
+ */
49
+ constructor(params) {
50
+ this.candidates = Array.from(params.candidates)
51
+ .map((c) => Candidate.createCandidate(c).orThrow())
52
+ .sort(Candidate.compare)
53
+ .reverse();
54
+ /* c8 ignore next 3 - coverage having a rough time */
55
+ const key = params.isAbstract
56
+ ? Decision.getAbstractKey(this.candidates.map((c) => c.conditionSet))
57
+ : Decision.getKey(this.candidates);
58
+ this._collectible = new Collections.Collectible({
59
+ key,
60
+ index: params.index,
61
+ indexConverter: CommonConvert.decisionIndex
62
+ });
63
+ }
64
+ /**
65
+ * Creates a new {@link Decisions.Decision | Decision} object.
66
+ * @param params - {@link Decisions.IDecisionCreateParams | Parameters} used to create the decision.
67
+ * @returns `Success` with the new decision if successful, or `Failure` with an error message if not.
68
+ * @public
69
+ */
70
+ static createDecision(params) {
71
+ return captureResult(() => new Decision(Object.assign(Object.assign({}, params), { isAbstract: false })));
72
+ }
73
+ /**
74
+ * Sets the index for this decision. Once set, index is immutable.
75
+ * @param index - The index to set.
76
+ * @returns `Success` with the new index if successful, or `Failure` with an error message if not.
77
+ * @public
78
+ */
79
+ setIndex(index) {
80
+ return this._collectible.setIndex(index);
81
+ }
82
+ /**
83
+ * Helper function to return a stable key for a the condition sets that
84
+ * make up a {@link Decisions.Decision | decision}. The abstract
85
+ * key is a `+`-separated list of the hashes of the sorted condition sets
86
+ * that make up the decision.
87
+ * @param conditionSets - The condition sets to use to create the key.
88
+ * @returns A key derived from the condition set hashes.
89
+ * @public
90
+ */
91
+ static getAbstractKey(conditionSets) {
92
+ return CommonConvert.decisionKey
93
+ .convert(Array.from(conditionSets)
94
+ .sort(ConditionSet.compare)
95
+ .reverse()
96
+ .map((c) => c.toHash())
97
+ .join('+'))
98
+ .orThrow();
99
+ }
100
+ /**
101
+ * Helper function to return a stable key for a set of condition sets.
102
+ * @param conditionSets - The condition sets to use to create the key.
103
+ * @returns A key derived from the condition set hashes.
104
+ * @public
105
+ */
106
+ static getKey(candidates) {
107
+ if (candidates.length === 0) {
108
+ /* c8 ignore next 2 - functional code path tested but coverage intermittently missed */
109
+ return Decision.EmptyDecisionKey;
110
+ }
111
+ const abstractKey = Decision.getAbstractKey(candidates.map((c) => c.conditionSet));
112
+ const valueKey = Hash.Crc32Normalizer.crc32Hash(candidates.map((c) => JSON.stringify(c.value)));
113
+ return CommonConvert.decisionKey.convert(`${abstractKey}|${valueKey}`).orThrow();
114
+ }
115
+ }
116
+ /**
117
+ * Key for the empty decision (no condition sets).
118
+ */
119
+ Decision.EmptyDecisionKey = CommonConvert.decisionKey.convert('').orThrow();
120
+ /**
121
+ * Key for the default-only decision (single condition set with no conditions).
122
+ */
123
+ Decision.DefaultOnlyDecisionKey = CommonConvert.decisionKey
124
+ .convert('00000000')
125
+ .orThrow();
126
+ //# sourceMappingURL=decision.js.map
@@ -0,0 +1,28 @@
1
+ /*
2
+ * Copyright (c) 2025 Erik Fortune
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+ export * from './common';
23
+ export * from './candidate';
24
+ export * from './decision';
25
+ export * from './abstractDecision';
26
+ export * from './abstractDecisionCollector';
27
+ export * from './concreteDecision';
28
+ //# sourceMappingURL=index.js.map