@fgv/ts-res 5.0.0-21 → 5.0.0-23

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 (197) hide show
  1. package/README.md +794 -137
  2. package/dist/ts-res.d.ts +506 -33
  3. package/lib/packlets/common/convert.d.ts +10 -0
  4. package/lib/packlets/common/convert.js +11 -1
  5. package/lib/packlets/common/resources.d.ts +40 -1
  6. package/lib/packlets/common/validate/regularExpressions.d.ts +4 -0
  7. package/lib/packlets/common/validate/regularExpressions.js +5 -1
  8. package/lib/packlets/common/validate/resources.d.ts +35 -1
  9. package/lib/packlets/common/validate/resources.js +54 -0
  10. package/lib/packlets/config/convert.js +1 -1
  11. package/lib/packlets/config/json.d.ts +1 -1
  12. package/lib/packlets/qualifier-types/config/convert.d.ts +22 -1
  13. package/lib/packlets/qualifier-types/config/convert.js +67 -2
  14. package/lib/packlets/qualifier-types/config/json.d.ts +11 -2
  15. package/lib/packlets/qualifier-types/helpers.d.ts +1 -2
  16. package/lib/packlets/qualifier-types/languageQualifierType.d.ts +27 -1
  17. package/lib/packlets/qualifier-types/languageQualifierType.js +75 -0
  18. package/lib/packlets/qualifier-types/literalQualifierType.d.ts +30 -4
  19. package/lib/packlets/qualifier-types/literalQualifierType.js +77 -0
  20. package/lib/packlets/qualifier-types/literalValueHierarchy.d.ts +6 -10
  21. package/lib/packlets/qualifier-types/literalValueHierarchy.js +10 -0
  22. package/lib/packlets/qualifier-types/qualifierType.d.ts +28 -0
  23. package/lib/packlets/qualifier-types/territoryQualifierType.d.ts +28 -4
  24. package/lib/packlets/qualifier-types/territoryQualifierType.js +77 -0
  25. package/lib/packlets/resource-json/compiled/convert.js +2 -1
  26. package/lib/packlets/resource-json/compiled/json.d.ts +6 -2
  27. package/lib/packlets/resource-types/config/convert.js +3 -1
  28. package/lib/packlets/resource-types/config/json.d.ts +2 -0
  29. package/lib/packlets/resource-types/jsonResourceType.d.ts +10 -6
  30. package/lib/packlets/resource-types/jsonResourceType.js +7 -10
  31. package/lib/packlets/resource-types/resourceType.d.ts +20 -8
  32. package/lib/packlets/resource-types/resourceType.js +20 -16
  33. package/lib/packlets/resources/candidateValue.d.ts +92 -0
  34. package/lib/packlets/resources/candidateValue.js +128 -0
  35. package/lib/packlets/resources/candidateValueCollector.d.ts +55 -0
  36. package/lib/packlets/resources/candidateValueCollector.js +96 -0
  37. package/lib/packlets/resources/index.d.ts +2 -0
  38. package/lib/packlets/resources/index.js +2 -0
  39. package/lib/packlets/resources/resource.js +2 -2
  40. package/lib/packlets/resources/resourceBuilder.d.ts +6 -0
  41. package/lib/packlets/resources/resourceBuilder.js +3 -1
  42. package/lib/packlets/resources/resourceCandidate.d.ts +10 -1
  43. package/lib/packlets/resources/resourceCandidate.js +11 -5
  44. package/lib/packlets/resources/resourceManagerBuilder.d.ts +7 -0
  45. package/lib/packlets/resources/resourceManagerBuilder.js +13 -6
  46. package/lib/packlets/runtime/compiledResourceCollection.d.ts +20 -8
  47. package/lib/packlets/runtime/compiledResourceCollection.js +25 -4
  48. package/lib/packlets/runtime/resource-tree/common.d.ts +1 -1
  49. package/lib/packlets/runtime/resourceResolver.d.ts +39 -1
  50. package/lib/packlets/runtime/resourceResolver.js +45 -28
  51. package/lib/test/unit/qualifier-types/testQualifierType.d.ts +4 -0
  52. package/lib/test/unit/qualifier-types/testQualifierType.js +24 -0
  53. package/lib/test/unit/resource-types/derivedResourceType.test.d.ts +2 -0
  54. package/lib/test/unit/resource-types/testDerivedResourceType.d.ts +79 -0
  55. package/lib/test/unit/resource-types/testDerivedResourceType.js +113 -0
  56. package/lib/test/unit/resources/candidateValue.test.d.ts +2 -0
  57. package/lib/test/unit/resources/candidateValueCollector.test.d.ts +2 -0
  58. package/lib/test/unit/runtime/resourceResolver.coverage.test.d.ts +2 -0
  59. package/lib/test/unit/runtime/resourceResolver.newFeatures.test.d.ts +2 -0
  60. package/package.json +7 -7
  61. package/src/index.ts +0 -75
  62. package/src/packlets/bundle/bundleBuilder.ts +0 -159
  63. package/src/packlets/bundle/bundleLoader.ts +0 -157
  64. package/src/packlets/bundle/bundleNormalizer.ts +0 -173
  65. package/src/packlets/bundle/bundleUtils.ts +0 -142
  66. package/src/packlets/bundle/convert.ts +0 -87
  67. package/src/packlets/bundle/index.ts +0 -52
  68. package/src/packlets/bundle/model.ts +0 -138
  69. package/src/packlets/common/conditions.ts +0 -226
  70. package/src/packlets/common/convert.ts +0 -184
  71. package/src/packlets/common/helpers/conditions.ts +0 -84
  72. package/src/packlets/common/helpers/context.ts +0 -88
  73. package/src/packlets/common/helpers/index.ts +0 -26
  74. package/src/packlets/common/helpers/qualifierDefaultValues.ts +0 -91
  75. package/src/packlets/common/helpers/resources.ts +0 -96
  76. package/src/packlets/common/index.ts +0 -30
  77. package/src/packlets/common/resources.ts +0 -78
  78. package/src/packlets/common/validate/conditions.ts +0 -595
  79. package/src/packlets/common/validate/index.ts +0 -27
  80. package/src/packlets/common/validate/regularExpressions.ts +0 -92
  81. package/src/packlets/common/validate/resources.ts +0 -170
  82. package/src/packlets/conditions/condition.ts +0 -351
  83. package/src/packlets/conditions/conditionCollector.ts +0 -103
  84. package/src/packlets/conditions/conditionDecls.ts +0 -50
  85. package/src/packlets/conditions/conditionSet.ts +0 -318
  86. package/src/packlets/conditions/conditionSetCollector.ts +0 -127
  87. package/src/packlets/conditions/conditionSetDecls.ts +0 -41
  88. package/src/packlets/conditions/conditionToken.ts +0 -180
  89. package/src/packlets/conditions/convert/conditionSetDecls.ts +0 -72
  90. package/src/packlets/conditions/convert/decls.ts +0 -95
  91. package/src/packlets/conditions/convert/index.ts +0 -24
  92. package/src/packlets/conditions/index.ts +0 -33
  93. package/src/packlets/config/common.ts +0 -107
  94. package/src/packlets/config/configInitFactory.ts +0 -142
  95. package/src/packlets/config/convert.ts +0 -61
  96. package/src/packlets/config/index.ts +0 -30
  97. package/src/packlets/config/json.ts +0 -43
  98. package/src/packlets/config/predefined/default.ts +0 -150
  99. package/src/packlets/config/predefined/extended.ts +0 -198
  100. package/src/packlets/config/predefined/index.ts +0 -26
  101. package/src/packlets/config/systemConfiguration.ts +0 -217
  102. package/src/packlets/context/contextDecls.ts +0 -76
  103. package/src/packlets/context/contextToken.ts +0 -252
  104. package/src/packlets/context/convert/decls.ts +0 -126
  105. package/src/packlets/context/convert/index.ts +0 -23
  106. package/src/packlets/context/index.ts +0 -27
  107. package/src/packlets/decisions/abstractDecision.ts +0 -87
  108. package/src/packlets/decisions/abstractDecisionCollector.ts +0 -122
  109. package/src/packlets/decisions/candidate.ts +0 -101
  110. package/src/packlets/decisions/common.ts +0 -37
  111. package/src/packlets/decisions/concreteDecision.ts +0 -157
  112. package/src/packlets/decisions/decision.ts +0 -172
  113. package/src/packlets/decisions/index.ts +0 -28
  114. package/src/packlets/import/fsItem.ts +0 -212
  115. package/src/packlets/import/importContext.ts +0 -183
  116. package/src/packlets/import/importManager.ts +0 -187
  117. package/src/packlets/import/importable.ts +0 -107
  118. package/src/packlets/import/importers/collectionImporter.ts +0 -153
  119. package/src/packlets/import/importers/fsItemImporter.ts +0 -154
  120. package/src/packlets/import/importers/importer.ts +0 -58
  121. package/src/packlets/import/importers/index.ts +0 -27
  122. package/src/packlets/import/importers/jsonImporter.ts +0 -133
  123. package/src/packlets/import/importers/pathImporter.ts +0 -134
  124. package/src/packlets/import/index.ts +0 -29
  125. package/src/packlets/qualifier-types/config/convert.ts +0 -108
  126. package/src/packlets/qualifier-types/config/index.ts +0 -27
  127. package/src/packlets/qualifier-types/config/json.ts +0 -126
  128. package/src/packlets/qualifier-types/convert.ts +0 -77
  129. package/src/packlets/qualifier-types/helpers.ts +0 -94
  130. package/src/packlets/qualifier-types/index.ts +0 -34
  131. package/src/packlets/qualifier-types/languageQualifierType.ts +0 -143
  132. package/src/packlets/qualifier-types/literalQualifierType.ts +0 -244
  133. package/src/packlets/qualifier-types/literalValueHierarchy.ts +0 -332
  134. package/src/packlets/qualifier-types/qualifierType.ts +0 -360
  135. package/src/packlets/qualifier-types/qualifierTypeCollector.ts +0 -102
  136. package/src/packlets/qualifier-types/territoryQualifierType.ts +0 -255
  137. package/src/packlets/qualifiers/convert/decls.ts +0 -90
  138. package/src/packlets/qualifiers/convert/index.ts +0 -24
  139. package/src/packlets/qualifiers/convert/qualifier.ts +0 -55
  140. package/src/packlets/qualifiers/index.ts +0 -31
  141. package/src/packlets/qualifiers/qualifier.ts +0 -169
  142. package/src/packlets/qualifiers/qualifierCollector.ts +0 -194
  143. package/src/packlets/qualifiers/qualifierDecl.ts +0 -80
  144. package/src/packlets/qualifiers/qualifierDefaultValueDecls.ts +0 -57
  145. package/src/packlets/qualifiers/qualifierDefaultValueToken.ts +0 -230
  146. package/src/packlets/resource-json/compiled/common.ts +0 -35
  147. package/src/packlets/resource-json/compiled/convert.ts +0 -143
  148. package/src/packlets/resource-json/compiled/index.ts +0 -27
  149. package/src/packlets/resource-json/compiled/json.ts +0 -239
  150. package/src/packlets/resource-json/convert.ts +0 -236
  151. package/src/packlets/resource-json/helpers.ts +0 -284
  152. package/src/packlets/resource-json/index.ts +0 -33
  153. package/src/packlets/resource-json/json.ts +0 -295
  154. package/src/packlets/resource-json/normalized.ts +0 -211
  155. package/src/packlets/resource-json/resourceDeclCollection.ts +0 -117
  156. package/src/packlets/resource-json/resourceDeclContainer.ts +0 -48
  157. package/src/packlets/resource-json/resourceDeclTree.ts +0 -116
  158. package/src/packlets/resource-types/config/convert.ts +0 -36
  159. package/src/packlets/resource-types/config/index.ts +0 -27
  160. package/src/packlets/resource-types/config/json.ts +0 -30
  161. package/src/packlets/resource-types/helpers.ts +0 -44
  162. package/src/packlets/resource-types/index.ts +0 -30
  163. package/src/packlets/resource-types/jsonResourceType.ts +0 -104
  164. package/src/packlets/resource-types/resourceType.ts +0 -259
  165. package/src/packlets/resource-types/resourceTypeCollector.ts +0 -79
  166. package/src/packlets/resources/candidateReducer.ts +0 -331
  167. package/src/packlets/resources/common.ts +0 -114
  168. package/src/packlets/resources/index.ts +0 -28
  169. package/src/packlets/resources/resource.ts +0 -307
  170. package/src/packlets/resources/resourceBuilder.ts +0 -269
  171. package/src/packlets/resources/resourceCandidate.ts +0 -333
  172. package/src/packlets/resources/resourceManagerBuilder.ts +0 -1169
  173. package/src/packlets/runtime/cacheListener.ts +0 -113
  174. package/src/packlets/runtime/cacheMetrics.ts +0 -206
  175. package/src/packlets/runtime/compiledResourceCollection.ts +0 -607
  176. package/src/packlets/runtime/conditionSetResolutionResult.ts +0 -160
  177. package/src/packlets/runtime/context/contextQualifierProvider.ts +0 -117
  178. package/src/packlets/runtime/context/contextQualifierProviderValidator.ts +0 -281
  179. package/src/packlets/runtime/context/index.ts +0 -26
  180. package/src/packlets/runtime/context/simpleContextQualifierProvider.ts +0 -225
  181. package/src/packlets/runtime/context/validatingSimpleContextQualifierProvider.ts +0 -96
  182. package/src/packlets/runtime/iResourceManager.ts +0 -130
  183. package/src/packlets/runtime/index.ts +0 -35
  184. package/src/packlets/runtime/resource-tree/common.ts +0 -126
  185. package/src/packlets/runtime/resource-tree/index.ts +0 -26
  186. package/src/packlets/runtime/resource-tree/readOnlyResourceTree.ts +0 -342
  187. package/src/packlets/runtime/resource-tree/resourceTreeChildren.ts +0 -125
  188. package/src/packlets/runtime/resource-tree/resourceTreeChildrenValidator.ts +0 -187
  189. package/src/packlets/runtime/resourceResolver.ts +0 -626
  190. package/src/packlets/runtime/validate.ts +0 -63
  191. package/src/packlets/zip-archive/convert.ts +0 -121
  192. package/src/packlets/zip-archive/index.ts +0 -76
  193. package/src/packlets/zip-archive/json.ts +0 -91
  194. package/src/packlets/zip-archive/types.ts +0 -140
  195. package/src/packlets/zip-archive/zipArchiveCreator.ts +0 -229
  196. package/src/packlets/zip-archive/zipArchiveFormat.ts +0 -158
  197. package/src/packlets/zip-archive/zipArchiveLoader.ts +0 -370
@@ -63,6 +63,7 @@ const common_1 = require("../common");
63
63
  const runtime_1 = require("../runtime");
64
64
  const resourceBuilder_1 = require("./resourceBuilder");
65
65
  const resource_1 = require("./resource");
66
+ const candidateValueCollector_1 = require("./candidateValueCollector");
66
67
  const ResourceJson = __importStar(require("../resource-json"));
67
68
  const Context = __importStar(require("../context"));
68
69
  const Config = __importStar(require("../config"));
@@ -79,6 +80,7 @@ class ResourceManagerBuilder {
79
80
  * The {@link QualifierTypes.ReadOnlyQualifierTypeCollector | qualifier types} used by this resource manager.
80
81
  */
81
82
  get qualifierTypes() {
83
+ /* c8 ignore next 1 - functional code tested but coverage intermittently missed */
82
84
  return this.qualifiers.qualifierTypes;
83
85
  }
84
86
  /**
@@ -149,6 +151,7 @@ class ResourceManagerBuilder {
149
151
  this._conditions = conditions_1.ConditionCollector.create({ qualifiers: params.qualifiers }).orThrow();
150
152
  this._conditionSets = conditions_1.ConditionSetCollector.create({ conditions: this._conditions }).orThrow();
151
153
  this._decisions = decisions_1.AbstractDecisionCollector.create({ conditionSets: this._conditionSets }).orThrow();
154
+ this._candidateValues = candidateValueCollector_1.CandidateValueCollector.create().orThrow();
152
155
  this._resources = new ts_utils_1.ValidatingResultMap({
153
156
  converters: new ts_utils_1.Collections.KeyValueConverters({
154
157
  key: common_1.Convert.resourceId,
@@ -234,7 +237,8 @@ class ResourceManagerBuilder {
234
237
  id,
235
238
  resourceTypes: this.resourceTypes,
236
239
  conditionSets: this._conditionSets,
237
- decisions: this._decisions
240
+ decisions: this._decisions,
241
+ candidateValues: this._candidateValues
238
242
  }));
239
243
  /* c8 ignore next 6 - defense in depth against internal error */
240
244
  if (builderResult.isFailure()) {
@@ -259,7 +263,8 @@ class ResourceManagerBuilder {
259
263
  typeName: decl.resourceTypeName,
260
264
  resourceTypes: this.resourceTypes,
261
265
  conditionSets: this._conditionSets,
262
- decisions: this._decisions
266
+ decisions: this._decisions,
267
+ candidateValues: this._candidateValues
263
268
  }));
264
269
  /* c8 ignore next 3 - defense in depth against internal error */
265
270
  if (getOrAddMessage !== undefined) {
@@ -494,6 +499,7 @@ class ResourceManagerBuilder {
494
499
  conditions: Array.from(this._conditions.values()).map((c) => c.toCompiled(options)),
495
500
  conditionSets: Array.from(this._conditionSets.values()).map((cs) => cs.toCompiled(options)),
496
501
  decisions: Array.from(this._decisions.values()).map((d) => d.toCompiled(options)),
502
+ candidateValues: this._candidateValues.getValuesByIndex(),
497
503
  resources: Array.from(this._builtResources.values()).map((r) => r.toCompiled(options))
498
504
  };
499
505
  // Apply validation through the converter
@@ -848,7 +854,7 @@ class ResourceManagerBuilder {
848
854
  const decision = decisionResult.value;
849
855
  const resourceType = resourceTypeResult.value;
850
856
  // Create candidates from the decision's condition sets
851
- ResourceManagerBuilder._createCandidatesFromDecision(compiledResource, decision, resourceType, builder).aggregateError(errors);
857
+ ResourceManagerBuilder._createCandidatesFromDecision(compiledResource, decision, resourceType, builder, compiledCollection.candidateValues).aggregateError(errors);
852
858
  }
853
859
  return errors.returnOrReport((0, ts_utils_1.succeed)(true));
854
860
  }
@@ -858,10 +864,11 @@ class ResourceManagerBuilder {
858
864
  * @param decision - The decision containing condition sets.
859
865
  * @param resourceType - The resource type for the candidates.
860
866
  * @param builder - The builder to add candidates to.
867
+ * @param candidateValues - Array of candidate values indexed by valueIndex.
861
868
  * @returns `Success` if all candidates were added successfully, `Failure` otherwise.
862
869
  * @internal
863
870
  */
864
- static _createCandidatesFromDecision(compiledResource, decision, resourceType, builder) {
871
+ static _createCandidatesFromDecision(compiledResource, decision, resourceType, builder, candidateValues) {
865
872
  var _a;
866
873
  const errors = new ts_utils_1.MessageAggregator();
867
874
  // Match each candidate to its corresponding condition set
@@ -880,9 +887,9 @@ class ResourceManagerBuilder {
880
887
  conditions = undefined;
881
888
  }
882
889
  }
883
- // Convert json value to JsonObject, handling undefined case
890
+ // Get json value from candidateValues array using valueIndex
884
891
  /* c8 ignore next 1 - defense in depth */
885
- const rawJson = (_a = candidate.json) !== null && _a !== void 0 ? _a : {};
892
+ const rawJson = (_a = candidateValues[candidate.valueIndex]) !== null && _a !== void 0 ? _a : {};
886
893
  ts_json_base_1.Converters.jsonObject
887
894
  .convert(rawJson)
888
895
  .onSuccess((json) => {
@@ -1,10 +1,11 @@
1
1
  import { Collections, Result } from '@fgv/ts-utils';
2
2
  import { ReadOnlyConditionCollector, ReadOnlyConditionSetCollector } from '../conditions';
3
3
  import { ReadOnlyAbstractDecisionCollector } from '../decisions';
4
- import { QualifierCollector } from '../qualifiers';
5
- import { ResourceType, ResourceTypeCollector } from '../resource-types';
6
- import { QualifierType, QualifierTypeCollector } from '../qualifier-types';
4
+ import { IReadOnlyQualifierCollector } from '../qualifiers';
5
+ import { ResourceType, ReadOnlyResourceTypeCollector } from '../resource-types';
6
+ import { QualifierType, ReadOnlyQualifierTypeCollector } from '../qualifier-types';
7
7
  import { ResourceId } from '../common';
8
+ import { JsonValue } from '@fgv/ts-json-base';
8
9
  import { IResourceManager, IResource } from './iResourceManager';
9
10
  import * as ResourceJson from '../resource-json';
10
11
  import { ReadOnlyResourceTreeRoot } from './resource-tree';
@@ -40,23 +41,28 @@ export declare class CompiledResourceCollection implements IResourceManager<IRes
40
41
  private readonly _qualifierTypes;
41
42
  private readonly _qualifiers;
42
43
  private readonly _resourceTypes;
44
+ private readonly _candidateValues;
43
45
  private readonly _builtResources;
44
46
  private _cachedResourceTree?;
45
47
  /**
46
- * A {@link QualifierTypes.QualifierTypeCollector | QualifierTypeCollector} which
48
+ * A {@link QualifierTypes.ReadOnlyQualifierTypeCollector | ReadOnlyQualifierTypeCollector} which
47
49
  * contains the {@link QualifierTypes.QualifierType | qualifier types} used in this collection.
48
50
  */
49
- get qualifierTypes(): QualifierTypeCollector;
51
+ get qualifierTypes(): ReadOnlyQualifierTypeCollector;
50
52
  /**
51
- * A {@link Qualifiers.QualifierCollector | QualifierCollector} which
53
+ * A {@link Qualifiers.IReadOnlyQualifierCollector | ReadOnlyQualifierCollector} which
52
54
  * contains the {@link Qualifiers.Qualifier | qualifiers} used in this collection.
53
55
  */
54
- get qualifiers(): QualifierCollector;
56
+ get qualifiers(): IReadOnlyQualifierCollector;
55
57
  /**
56
58
  * A {@link ResourceTypes.ResourceTypeCollector | ResourceTypeCollector} which
57
59
  * contains the {@link ResourceTypes.ResourceType | resource types} used in this collection.
58
60
  */
59
- get resourceTypes(): ResourceTypeCollector;
61
+ get resourceTypes(): ReadOnlyResourceTypeCollector;
62
+ /**
63
+ * The candidate values in the collection.
64
+ */
65
+ get candidateValues(): ReadonlyArray<JsonValue>;
60
66
  /**
61
67
  * {@inheritdoc Runtime.IResourceManager.builtResources}
62
68
  */
@@ -154,6 +160,12 @@ export declare class CompiledResourceCollection implements IResourceManager<IRes
154
160
  * @internal
155
161
  */
156
162
  private _buildDecisions;
163
+ /**
164
+ * Gets a candidate value from the collection.
165
+ * @param valueIndex - The index of the candidate value to get.
166
+ * @returns
167
+ */
168
+ private _getCandidateValue;
157
169
  /**
158
170
  * Reconstructs a ValidatingResultMap of resources from compiled data.
159
171
  * @param compiled - The compiled resource collection
@@ -75,14 +75,14 @@ const Context = __importStar(require("../context"));
75
75
  */
76
76
  class CompiledResourceCollection {
77
77
  /**
78
- * A {@link QualifierTypes.QualifierTypeCollector | QualifierTypeCollector} which
78
+ * A {@link QualifierTypes.ReadOnlyQualifierTypeCollector | ReadOnlyQualifierTypeCollector} which
79
79
  * contains the {@link QualifierTypes.QualifierType | qualifier types} used in this collection.
80
80
  */
81
81
  get qualifierTypes() {
82
82
  return this._qualifierTypes;
83
83
  }
84
84
  /**
85
- * A {@link Qualifiers.QualifierCollector | QualifierCollector} which
85
+ * A {@link Qualifiers.IReadOnlyQualifierCollector | ReadOnlyQualifierCollector} which
86
86
  * contains the {@link Qualifiers.Qualifier | qualifiers} used in this collection.
87
87
  */
88
88
  get qualifiers() {
@@ -95,6 +95,12 @@ class CompiledResourceCollection {
95
95
  get resourceTypes() {
96
96
  return this._resourceTypes;
97
97
  }
98
+ /**
99
+ * The candidate values in the collection.
100
+ */
101
+ get candidateValues() {
102
+ return this._candidateValues;
103
+ }
98
104
  /**
99
105
  * {@inheritdoc Runtime.IResourceManager.builtResources}
100
106
  */
@@ -133,6 +139,7 @@ class CompiledResourceCollection {
133
139
  this.conditions = conditionCollector;
134
140
  this.conditionSets = conditionSetCollector;
135
141
  this.decisions = decisionCollector;
142
+ this._candidateValues = [...params.compiledCollection.candidateValues];
136
143
  // Build resources from compiled data
137
144
  this._builtResources = this._buildResources(params.compiledCollection, this._resourceTypes, decisionCollector).orThrow();
138
145
  }
@@ -381,6 +388,21 @@ class CompiledResourceCollection {
381
388
  }
382
389
  return errors.hasMessages ? (0, ts_utils_1.fail)(errors.toString()) : (0, ts_utils_1.succeed)(decisionCollector);
383
390
  }
391
+ /**
392
+ * Gets a candidate value from the collection.
393
+ * @param valueIndex - The index of the candidate value to get.
394
+ * @returns
395
+ */
396
+ _getCandidateValue(valueIndex) {
397
+ if (valueIndex < 0 || valueIndex >= this._candidateValues.length) {
398
+ return (0, ts_utils_1.fail)(`Invalid candidate value index ${valueIndex}`);
399
+ }
400
+ /* c8 ignore next 3 - defensive coding for invalid candidate value conversion */
401
+ if (!(0, ts_json_base_1.isJsonObject)(this._candidateValues[valueIndex])) {
402
+ return (0, ts_utils_1.fail)(`${valueIndex}: candidate value not a JSON object.`);
403
+ }
404
+ return (0, ts_utils_1.succeed)(this._candidateValues[valueIndex]);
405
+ }
384
406
  /**
385
407
  * Reconstructs a ValidatingResultMap of resources from compiled data.
386
408
  * @param compiled - The compiled resource collection
@@ -413,7 +435,7 @@ class CompiledResourceCollection {
413
435
  }
414
436
  const decision = decisionResult.value;
415
437
  // Build candidates from compiled data
416
- const candidateDeclsResult = (0, ts_utils_1.mapResults)(compiledResource.candidates.map((compiledCandidate) => ts_json_base_1.Converters.jsonObject.convert(compiledCandidate.json).onSuccess((json) => {
438
+ const candidateDeclsResult = (0, ts_utils_1.mapResults)(compiledResource.candidates.map((compiledCandidate) => this._getCandidateValue(compiledCandidate.valueIndex).onSuccess((json) => {
417
439
  return (0, ts_utils_1.succeed)({
418
440
  json,
419
441
  isPartial: compiledCandidate.isPartial,
@@ -431,7 +453,6 @@ class CompiledResourceCollection {
431
453
  isPartial: candidateDecl.isPartial,
432
454
  mergeMethod: candidateDecl.mergeMethod
433
455
  }));
434
- // Create a ConcreteDecision from the abstract decision and candidate values
435
456
  const candidatesWithConditionSets = decision.candidates.map((baseCandidate, idx) => ({
436
457
  conditionSet: baseCandidate.conditionSet,
437
458
  value: candidates[idx].json
@@ -49,7 +49,7 @@ export type IReadOnlyResourceTreeNode<T> = IReadOnlyResourceTreeLeaf<T> | IReadO
49
49
  * Interface for a read-only result-based resource tree with navigation methods.
50
50
  * @public
51
51
  */
52
- export interface IReadOnlyResourceTreeChildren<T, TID extends string = ResourceId, TNAME extends string = ResourceName> extends IReadOnlyResultMap<ResourceName, IReadOnlyResourceTreeNode<T>> {
52
+ export interface IReadOnlyResourceTreeChildren<T, TID extends string = ResourceId, TNAME extends string = ResourceName> extends IReadOnlyResultMap<TNAME, IReadOnlyResourceTreeNode<T>> {
53
53
  /**
54
54
  * Gets a tree node by its full ResourceId path.
55
55
  * @param id - The ResourceId path to look up
@@ -1,5 +1,6 @@
1
1
  import { Result } from '@fgv/ts-utils';
2
2
  import { JsonValue } from '@fgv/ts-json-base';
3
+ import { IResourceResolver } from '../common';
3
4
  import { Condition, ConditionSet } from '../conditions';
4
5
  import { AbstractDecision } from '../decisions';
5
6
  import { ReadOnlyQualifierTypeCollector } from '../qualifier-types';
@@ -7,6 +8,7 @@ import { IContextQualifierProvider } from './context';
7
8
  import { IResourceManager, IResource, IResourceCandidate } from './iResourceManager';
8
9
  import { ConditionSetResolutionResult, IConditionMatchResult } from './conditionSetResolutionResult';
9
10
  import { IResourceResolverCacheListener } from './cacheListener';
11
+ import { IReadOnlyQualifierCollector } from '../qualifiers';
10
12
  /**
11
13
  * Represents the cached result of resolving a decision.
12
14
  * Contains either a failure indicator or a list of instance indices for matching condition sets,
@@ -68,7 +70,7 @@ export interface IResourceResolverCreateParams {
68
70
  * and caching results for optimal performance.
69
71
  * @public
70
72
  */
71
- export declare class ResourceResolver {
73
+ export declare class ResourceResolver implements IResourceResolver {
72
74
  /**
73
75
  * The resource manager that defines available resources and provides condition access.
74
76
  */
@@ -85,6 +87,10 @@ export declare class ResourceResolver {
85
87
  * The configuration options for this resource resolver.
86
88
  */
87
89
  readonly options: IResourceResolverOptions;
90
+ /**
91
+ * The readonly qualifier collector that provides qualifier implementations.
92
+ */
93
+ get qualifiers(): IReadOnlyQualifierCollector;
88
94
  /**
89
95
  * The cache array for resolved conditions, indexed by condition index for O(1) lookup.
90
96
  * Each entry stores the resolved {@link Runtime.IConditionMatchResult | condition match result} for
@@ -169,6 +175,15 @@ export declare class ResourceResolver {
169
175
  * @public
170
176
  */
171
177
  resolveResource(resource: IResource): Result<IResourceCandidate>;
178
+ /**
179
+ * Resolves a resource by finding the best matching candidate.
180
+ * Uses the resource's associated decision to determine the best match based on the current context.
181
+ * @param resource - The string id of the resource to resolve.
182
+ * @returns `Success` with the best matching candidate if successful,
183
+ * or `Failure` with an error message if no candidates match or resolution fails.
184
+ * @public
185
+ */
186
+ resolveResource(resource: string): Result<IResourceCandidate>;
172
187
  /**
173
188
  * Resolves all matching resource candidates in priority order.
174
189
  * Uses the resource's associated decision to determine all matching candidates based on the current context.
@@ -178,6 +193,15 @@ export declare class ResourceResolver {
178
193
  * @public
179
194
  */
180
195
  resolveAllResourceCandidates(resource: IResource): Result<ReadonlyArray<IResourceCandidate>>;
196
+ /**
197
+ * Resolves all matching resource candidates in priority order.
198
+ * Uses the resource's associated decision to determine all matching candidates based on the current context.
199
+ * @param resource - The string id of the resource to resolve.
200
+ * @returns `Success` with an array of all matching candidates in priority order if successful,
201
+ * or `Failure` with an error message if no candidates match or resolution fails.
202
+ * @public
203
+ */
204
+ resolveAllResourceCandidates(resource: string): Result<ReadonlyArray<IResourceCandidate>>;
181
205
  /**
182
206
  * Resolves a resource to a composed value by merging matching candidates according to their merge methods.
183
207
  * Starting from the highest priority candidates, finds the first "full" candidate and merges all higher
@@ -188,6 +212,20 @@ export declare class ResourceResolver {
188
212
  * @public
189
213
  */
190
214
  resolveComposedResourceValue(resource: IResource): Result<JsonValue>;
215
+ /**
216
+ * Resolves a resource to a composed value by merging matching candidates according to their merge methods.
217
+ * Starting from the highest priority candidates, finds the first "full" candidate and merges all higher
218
+ * priority "partial" candidates into it in ascending order of priority.
219
+ * @param resource - The string id of the resource to resolve.
220
+ * @returns `Success` with the composed JsonValue if successful,
221
+ * or `Failure` with an error message if no candidates match or resolution fails.
222
+ * @public
223
+ */
224
+ resolveComposedResourceValue(resource: string): Result<JsonValue>;
225
+ /**
226
+ * {@inheritDoc IResourceResolver.withContext}
227
+ */
228
+ withContext(context: Record<string, string>): Result<ResourceResolver>;
191
229
  /**
192
230
  * Clears all caches (condition, condition set, and decision), forcing all cached items
193
231
  * to be re-evaluated on next access. This should be called when the context changes and cached
@@ -26,6 +26,7 @@ const ts_utils_1 = require("@fgv/ts-utils");
26
26
  const ts_json_base_1 = require("@fgv/ts-json-base");
27
27
  const ts_json_1 = require("@fgv/ts-json");
28
28
  const common_1 = require("../common");
29
+ const context_1 = require("./context");
29
30
  const conditionSetResolutionResult_1 = require("./conditionSetResolutionResult");
30
31
  /**
31
32
  * High-performance runtime resource resolver with O(1) condition caching.
@@ -34,6 +35,12 @@ const conditionSetResolutionResult_1 = require("./conditionSetResolutionResult")
34
35
  * @public
35
36
  */
36
37
  class ResourceResolver {
38
+ /**
39
+ * The readonly qualifier collector that provides qualifier implementations.
40
+ */
41
+ get qualifiers() {
42
+ return this.contextQualifierProvider.qualifiers;
43
+ }
37
44
  /**
38
45
  * The cache array for resolved conditions, indexed by condition index for O(1) lookup.
39
46
  * Each entry stores the resolved {@link Runtime.IConditionMatchResult | condition match result} for
@@ -268,15 +275,13 @@ class ResourceResolver {
268
275
  (_c = this._listener) === null || _c === void 0 ? void 0 : _c.onCacheMiss('decision', decisionIndex);
269
276
  return (0, ts_utils_1.succeed)(successResult);
270
277
  }
271
- /**
272
- * Resolves a resource by finding the best matching candidate.
273
- * Uses the resource's associated decision to determine the best match based on the current context.
274
- * @param resource - The {@link Resources.Resource | resource} to resolve.
275
- * @returns `Success` with the best matching candidate if successful,
276
- * or `Failure` with an error message if no candidates match or resolution fails.
277
- * @public
278
- */
279
- resolveResource(resource) {
278
+ resolveResource(idOrResource) {
279
+ if (typeof idOrResource === 'string') {
280
+ return this.resourceManager
281
+ .getBuiltResource(idOrResource)
282
+ .onSuccess((resource) => this.resolveResource(resource));
283
+ }
284
+ const resource = idOrResource;
280
285
  // Get the abstract decision from the resource's concrete decision
281
286
  const abstractDecision = resource.decision.baseDecision;
282
287
  // Resolve the decision to get candidate indices in priority order
@@ -301,15 +306,13 @@ class ResourceResolver {
301
306
  const bestCandidate = resource.candidates[candidateIndex];
302
307
  return (0, ts_utils_1.succeed)(bestCandidate);
303
308
  }
304
- /**
305
- * Resolves all matching resource candidates in priority order.
306
- * Uses the resource's associated decision to determine all matching candidates based on the current context.
307
- * @param resource - The {@link Resources.Resource | resource} to resolve.
308
- * @returns `Success` with an array of all matching candidates in priority order if successful,
309
- * or `Failure` with an error message if no candidates match or resolution fails.
310
- * @public
311
- */
312
- resolveAllResourceCandidates(resource) {
309
+ resolveAllResourceCandidates(idOrResource) {
310
+ if (typeof idOrResource === 'string') {
311
+ return this.resourceManager
312
+ .getBuiltResource(idOrResource)
313
+ .onSuccess((resource) => this.resolveAllResourceCandidates(resource));
314
+ }
315
+ const resource = idOrResource;
313
316
  // Get the abstract decision from the resource's concrete decision
314
317
  const abstractDecision = resource.decision.baseDecision;
315
318
  // Resolve the decision to get candidate indices in priority order
@@ -345,16 +348,13 @@ class ResourceResolver {
345
348
  }
346
349
  return (0, ts_utils_1.succeed)(candidates);
347
350
  }
348
- /**
349
- * Resolves a resource to a composed value by merging matching candidates according to their merge methods.
350
- * Starting from the highest priority candidates, finds the first "full" candidate and merges all higher
351
- * priority "partial" candidates into it in ascending order of priority.
352
- * @param resource - The {@link Resources.Resource | resource} to resolve.
353
- * @returns `Success` with the composed JsonValue if successful,
354
- * or `Failure` with an error message if no candidates match or resolution fails.
355
- * @public
356
- */
357
- resolveComposedResourceValue(resource) {
351
+ resolveComposedResourceValue(idOrResource) {
352
+ if (typeof idOrResource === 'string') {
353
+ return this.resourceManager
354
+ .getBuiltResource(idOrResource)
355
+ .onSuccess((resource) => this.resolveComposedResourceValue(resource));
356
+ }
357
+ const resource = idOrResource;
358
358
  return this.resolveAllResourceCandidates(resource).onSuccess((candidates) => {
359
359
  /* c8 ignore next 3 - defense in depth should never occur */
360
360
  if (candidates.length === 0) {
@@ -415,6 +415,23 @@ class ResourceResolver {
415
415
  .withErrorFormat((err) => `${resource.id}: Composition failed: ${err}`);
416
416
  });
417
417
  }
418
+ /**
419
+ * {@inheritDoc IResourceResolver.withContext}
420
+ */
421
+ withContext(context) {
422
+ const { resourceManager, qualifierTypes, options } = this;
423
+ return context_1.ValidatingSimpleContextQualifierProvider.create({
424
+ qualifiers: this.qualifiers,
425
+ qualifierValues: context
426
+ }).onSuccess((contextQualifierProvider) => {
427
+ return ResourceResolver.create({
428
+ resourceManager,
429
+ qualifierTypes,
430
+ options,
431
+ contextQualifierProvider
432
+ });
433
+ });
434
+ }
418
435
  /**
419
436
  * Clears all caches (condition, condition set, and decision), forcing all cached items
420
437
  * to be re-evaluated on next access. This should be called when the context changes and cached
@@ -1,15 +1,19 @@
1
1
  import { Result } from '@fgv/ts-utils';
2
2
  import * as TsRes from '../../../index';
3
+ import { JsonObject } from '@fgv/ts-json-base';
3
4
  export interface ITestQualifierTypeConstructorParams {
4
5
  name?: string;
5
6
  allowContextList?: string;
6
7
  index?: number;
7
8
  }
8
9
  export declare class TestQualifierType extends TsRes.QualifierTypes.QualifierType {
10
+ readonly systemTypeName: TsRes.QualifierTypeName;
9
11
  constructor(params?: ITestQualifierTypeConstructorParams);
10
12
  static create(params?: ITestQualifierTypeConstructorParams): Result<TestQualifierType>;
11
13
  isValidConditionValue(value: string): value is TsRes.QualifierConditionValue;
12
14
  validateCondition(value: string, operator?: TsRes.ConditionOperator): Result<TsRes.QualifierConditionValue>;
15
+ getConfigurationJson(): Result<JsonObject>;
16
+ validateConfigurationJson(from: unknown): Result<JsonObject>;
13
17
  protected _matchOne(condition: TsRes.QualifierConditionValue, context: TsRes.QualifierContextValue, operator: TsRes.ConditionOperator): TsRes.QualifierMatchScore;
14
18
  }
15
19
  //# sourceMappingURL=testQualifierType.d.ts.map
@@ -65,6 +65,9 @@ class TestQualifierType extends TsRes.QualifierTypes.QualifierType {
65
65
  allowContextList: (params === null || params === void 0 ? void 0 : params.allowContextList) === 'true',
66
66
  index: params === null || params === void 0 ? void 0 : params.index
67
67
  });
68
+ this.systemTypeName = TsRes.Convert.qualifierTypeName
69
+ .convert('test')
70
+ .orThrow();
68
71
  }
69
72
  static create(params) {
70
73
  return (0, ts_utils_1.captureResult)(() => new TestQualifierType(params));
@@ -75,6 +78,27 @@ class TestQualifierType extends TsRes.QualifierTypes.QualifierType {
75
78
  validateCondition(value, operator) {
76
79
  return this.isValidConditionValue(value) ? (0, ts_utils_1.succeed)(value) : (0, ts_utils_1.fail)(`Invalid condition value: ${value}`);
77
80
  }
81
+ getConfigurationJson() {
82
+ return (0, ts_utils_1.succeed)({
83
+ name: this.name,
84
+ systemType: 'test',
85
+ configuration: {}
86
+ });
87
+ }
88
+ validateConfigurationJson(from) {
89
+ // Simple validation for test class
90
+ if (typeof from !== 'object' || from === null) {
91
+ return (0, ts_utils_1.fail)('Expected object');
92
+ }
93
+ const obj = from;
94
+ if (typeof obj.name !== 'string') {
95
+ return (0, ts_utils_1.fail)('name must be string');
96
+ }
97
+ if (obj.systemType !== 'test') {
98
+ return (0, ts_utils_1.fail)('systemType must be test');
99
+ }
100
+ return (0, ts_utils_1.succeed)(from);
101
+ }
78
102
  _matchOne(condition, context, operator) {
79
103
  if (condition === context) {
80
104
  return TsRes.PerfectMatch;
@@ -0,0 +1,2 @@
1
+ import '@fgv/ts-utils-jest';
2
+ //# sourceMappingURL=derivedResourceType.test.d.ts.map
@@ -0,0 +1,79 @@
1
+ import { JsonObject, JsonValue } from '@fgv/ts-json-base';
2
+ import { Result } from '@fgv/ts-utils';
3
+ import { CandidateCompleteness, ResourceTypeName, ResourceId, IResourceResolver } from '../../../packlets/common';
4
+ import { IResourceCandidateValidationProperties, ResourceType } from '../../../packlets/resource-types/resourceType';
5
+ import * as ResourceJson from '../../../packlets/resource-json';
6
+ /**
7
+ * Parameters to create a TestDerivedResourceType instance.
8
+ */
9
+ export interface ITestDerivedResourceTypeCreateParams {
10
+ /**
11
+ * Optional key for the new TestDerivedResourceType instance.
12
+ * Defaults to 'test-derived'.
13
+ */
14
+ key?: string;
15
+ /**
16
+ * Optional index for the new TestDerivedResourceType instance.
17
+ */
18
+ index?: number;
19
+ /**
20
+ * Optional template for new instances.
21
+ */
22
+ template?: JsonObject;
23
+ /**
24
+ * Optional resource ID to use as a template source.
25
+ * When provided, the resource resolver will be used to look up
26
+ * this resource and use its value as the template.
27
+ */
28
+ templateResourceId?: string;
29
+ }
30
+ /**
31
+ * Test data structure for the derived resource type
32
+ */
33
+ export interface ITestData {
34
+ title: string;
35
+ description?: string;
36
+ metadata?: Record<string, JsonValue>;
37
+ }
38
+ /**
39
+ * Partial test data structure for the derived resource type
40
+ */
41
+ export interface IPartialTestData {
42
+ title?: string;
43
+ description?: string;
44
+ metadata?: Record<string, JsonValue>;
45
+ }
46
+ /**
47
+ * A derived resource type for testing that demonstrates:
48
+ * 1. Custom validation logic
49
+ * 2. Using a resource resolver to look up template values
50
+ * 3. Type-specific defaults and error handling
51
+ */
52
+ export declare class TestDerivedResourceType extends ResourceType<ITestData> {
53
+ readonly systemTypeName: ResourceTypeName;
54
+ private _templateResourceId?;
55
+ protected constructor(key: ResourceTypeName, index?: number, template?: JsonObject, templateResourceId?: string);
56
+ /**
57
+ * Factory method to create a new TestDerivedResourceType instance.
58
+ */
59
+ static create(params?: ITestDerivedResourceTypeCreateParams): Result<TestDerivedResourceType>;
60
+ /**
61
+ * Validates a resource candidate declaration with custom logic.
62
+ */
63
+ validateDeclaration(props: IResourceCandidateValidationProperties): Result<ITestData | IPartialTestData>;
64
+ /**
65
+ * Validates JSON for this resource type with custom business logic.
66
+ */
67
+ validate(json: JsonValue, completeness: CandidateCompleteness): Result<IPartialTestData>;
68
+ validate(json: JsonValue, completeness: 'full'): Result<ITestData>;
69
+ validate(json: JsonValue, completeness: 'partial'): Result<IPartialTestData>;
70
+ /**
71
+ * Override to demonstrate looking up template values from another resource.
72
+ */
73
+ getDefaultTemplateCandidate(json?: JsonValue, conditions?: ResourceJson.Json.ConditionSetDecl, resolver?: IResourceResolver): Result<ResourceJson.Json.IChildResourceCandidateDecl>;
74
+ /**
75
+ * Override createTemplate to add additional validation for the derived type.
76
+ */
77
+ createTemplate(resourceId: ResourceId, init?: JsonValue, conditions?: ResourceJson.Json.ConditionSetDecl, resolver?: IResourceResolver): Result<ResourceJson.Json.ILooseResourceDecl>;
78
+ }
79
+ //# sourceMappingURL=testDerivedResourceType.d.ts.map