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

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 (557) hide show
  1. package/.vscode/4.json +3 -0
  2. package/.vscode/launch.json +16 -0
  3. package/.vscode/settings.json +3 -0
  4. package/config/api-extractor.json +343 -0
  5. package/config/rig.json +16 -0
  6. package/dist/ts-res.d.ts +1528 -161
  7. package/dist/tsdoc-metadata.json +1 -1
  8. package/lib/index.d.ts +11 -2
  9. package/lib/index.js +25 -2
  10. package/lib/packlets/bundle/bundleBuilder.d.ts +41 -0
  11. package/lib/packlets/bundle/bundleBuilder.js +134 -0
  12. package/lib/packlets/bundle/bundleLoader.d.ts +72 -0
  13. package/lib/packlets/bundle/bundleLoader.js +105 -0
  14. package/lib/packlets/bundle/bundleNormalizer.d.ts +73 -0
  15. package/lib/packlets/bundle/bundleNormalizer.js +142 -0
  16. package/lib/packlets/bundle/bundleUtils.d.ts +70 -0
  17. package/lib/packlets/bundle/bundleUtils.js +117 -0
  18. package/lib/packlets/bundle/convert.d.ts +33 -0
  19. package/lib/packlets/bundle/convert.js +78 -0
  20. package/lib/packlets/bundle/index.d.ts +21 -0
  21. package/lib/packlets/bundle/index.js +83 -0
  22. package/lib/packlets/bundle/model.d.ts +100 -0
  23. package/lib/packlets/bundle/model.js +24 -0
  24. package/lib/packlets/common/helpers/resources.d.ts +7 -0
  25. package/lib/packlets/common/helpers/resources.js +12 -0
  26. package/lib/packlets/common/resources.d.ts +8 -0
  27. package/lib/packlets/conditions/conditionSet.d.ts +9 -0
  28. package/lib/packlets/conditions/conditionSet.js +74 -1
  29. package/lib/packlets/config/configInitFactory.d.ts +78 -0
  30. package/lib/packlets/config/configInitFactory.js +147 -0
  31. package/lib/packlets/config/convert.d.ts +9 -0
  32. package/lib/packlets/config/convert.js +11 -0
  33. package/lib/packlets/config/index.d.ts +1 -0
  34. package/lib/packlets/config/index.js +1 -0
  35. package/lib/packlets/config/systemConfiguration.d.ts +16 -3
  36. package/lib/packlets/config/systemConfiguration.js +19 -40
  37. package/lib/packlets/import/fsItem.js +8 -13
  38. package/lib/packlets/import/importers/jsonImporter.js +1 -0
  39. package/lib/packlets/qualifier-types/config/json.d.ts +13 -0
  40. package/lib/packlets/qualifier-types/config/json.js +11 -0
  41. package/lib/packlets/qualifier-types/literalValueHierarchy.js +1 -1
  42. package/lib/packlets/qualifiers/qualifierCollector.js +1 -2
  43. package/lib/packlets/resource-types/jsonResourceType.d.ts +9 -4
  44. package/lib/packlets/resource-types/jsonResourceType.js +8 -1
  45. package/lib/packlets/resource-types/resourceType.d.ts +102 -13
  46. package/lib/packlets/resource-types/resourceType.js +34 -2
  47. package/lib/packlets/resources/common.d.ts +26 -0
  48. package/lib/packlets/resources/resource.d.ts +6 -6
  49. package/lib/packlets/resources/resource.js +3 -8
  50. package/lib/packlets/resources/resourceCandidate.d.ts +5 -1
  51. package/lib/packlets/resources/resourceCandidate.js +6 -0
  52. package/lib/packlets/resources/resourceManagerBuilder.d.ts +182 -11
  53. package/lib/packlets/resources/resourceManagerBuilder.js +469 -15
  54. package/lib/packlets/runtime/cacheListener.d.ts +9 -0
  55. package/lib/packlets/runtime/cacheListener.js +6 -0
  56. package/lib/packlets/runtime/cacheMetrics.d.ts +6 -0
  57. package/lib/packlets/runtime/cacheMetrics.js +11 -0
  58. package/lib/packlets/runtime/compiledResourceCollection.d.ts +3 -3
  59. package/lib/packlets/runtime/compiledResourceCollection.js +7 -0
  60. package/lib/packlets/runtime/iResourceManager.d.ts +13 -5
  61. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.d.ts +7 -7
  62. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js +5 -5
  63. package/lib/packlets/runtime/resourceResolver.d.ts +21 -0
  64. package/lib/packlets/runtime/resourceResolver.js +39 -17
  65. package/lib/packlets/runtime/validate.js +1 -0
  66. package/lib/packlets/zip-archive/convert.d.ts +52 -0
  67. package/lib/packlets/zip-archive/convert.js +104 -0
  68. package/lib/packlets/zip-archive/index.d.ts +23 -0
  69. package/lib/packlets/zip-archive/index.js +95 -0
  70. package/lib/packlets/zip-archive/json.d.ts +64 -0
  71. package/lib/packlets/zip-archive/json.js +24 -0
  72. package/lib/packlets/zip-archive/types.d.ts +98 -0
  73. package/lib/packlets/zip-archive/types.js +39 -0
  74. package/lib/packlets/zip-archive/zipArchiveCreator.d.ts +35 -0
  75. package/lib/packlets/zip-archive/zipArchiveCreator.js +194 -0
  76. package/lib/packlets/zip-archive/zipArchiveFormat.d.ts +70 -0
  77. package/lib/packlets/zip-archive/zipArchiveFormat.js +184 -0
  78. package/lib/packlets/zip-archive/zipArchiveLoader.d.ts +70 -0
  79. package/lib/packlets/zip-archive/zipArchiveLoader.js +285 -0
  80. package/lib/test/data/sample.json +32 -0
  81. package/lib/test/unit/bundle/bundleBuilder.test.d.ts +2 -0
  82. package/lib/test/unit/bundle/bundleLoader.test.d.ts +2 -0
  83. package/lib/test/unit/bundle/bundleUtils.test.d.ts +2 -0
  84. package/lib/test/unit/bundle/convert.test.d.ts +2 -0
  85. package/lib/test/unit/bundle/integration.test.d.ts +2 -0
  86. package/lib/test/unit/bundle/model.test.d.ts +2 -0
  87. package/lib/test/unit/bundle/normalization.test.d.ts +2 -0
  88. package/lib/test/unit/common/conditions.test.d.ts +2 -0
  89. package/lib/test/unit/common/helpers/conditions.test.d.ts +2 -0
  90. package/lib/test/unit/common/helpers/contexts.test.d.ts +2 -0
  91. package/lib/test/unit/common/helpers/qualifierDefaultValues.test.d.ts +2 -0
  92. package/lib/test/unit/common/resources.test.d.ts +2 -0
  93. package/lib/test/unit/conditions/condition.test.d.ts +2 -0
  94. package/lib/test/unit/conditions/conditionCollector.test.d.ts +2 -0
  95. package/lib/test/unit/conditions/conditionScoreAsDefault.test.d.ts +2 -0
  96. package/lib/test/unit/conditions/conditionSet.test.d.ts +2 -0
  97. package/lib/test/unit/conditions/conditionSetCollector.test.d.ts +2 -0
  98. package/lib/test/unit/conditions/conditionToken.test.d.ts +2 -0
  99. package/lib/test/unit/conditions/convert.test.d.ts +2 -0
  100. package/lib/test/unit/config/common.test.d.ts +2 -0
  101. package/lib/test/unit/config/convert.test.d.ts +2 -0
  102. package/lib/test/unit/config/predefined/default.test.d.ts +2 -0
  103. package/lib/test/unit/config/predefined/extended.test.d.ts +2 -0
  104. package/lib/test/unit/config/systemConfiguration.test.d.ts +2 -0
  105. package/lib/test/unit/config/systemConfigurationInitParams.test.d.ts +2 -0
  106. package/lib/test/unit/context/contextToken.test.d.ts +2 -0
  107. package/lib/test/unit/context/convert.test.d.ts +2 -0
  108. package/lib/test/unit/decisions/abstractDecision.test.d.ts +2 -0
  109. package/lib/test/unit/decisions/abstractDecisionCollector.test.d.ts +2 -0
  110. package/lib/test/unit/decisions/candidate.test.d.ts +2 -0
  111. package/lib/test/unit/decisions/concreteDecision.test.d.ts +2 -0
  112. package/lib/test/unit/decisions/decision.test.d.ts +2 -0
  113. package/lib/test/unit/import/collectionImporter.test.d.ts +2 -0
  114. package/lib/test/unit/import/fsItem.test.d.ts +2 -0
  115. package/lib/test/unit/import/fsItemImporter.test.d.ts +2 -0
  116. package/lib/test/unit/import/importContext.test.d.ts +2 -0
  117. package/lib/test/unit/import/importManager.test.d.ts +2 -0
  118. package/lib/test/unit/import/jsonImporter.test.d.ts +2 -0
  119. package/lib/test/unit/import/pathImporter.test.d.ts +2 -0
  120. package/lib/test/unit/qualifier-types/convert.test.d.ts +2 -0
  121. package/lib/test/unit/qualifier-types/helpers.test.d.ts +2 -0
  122. package/lib/test/unit/qualifier-types/languageQualifierType.test.d.ts +2 -0
  123. package/lib/test/unit/qualifier-types/literalQualifierType.test.d.ts +2 -0
  124. package/lib/test/unit/qualifier-types/literalValueHierarchy.test.d.ts +2 -0
  125. package/lib/test/unit/qualifier-types/qualifierType.test.d.ts +2 -0
  126. package/lib/test/unit/qualifier-types/qualifierTypeCollector.test.d.ts +2 -0
  127. package/lib/test/unit/qualifier-types/territoryQualifierType.test.d.ts +2 -0
  128. package/lib/test/unit/qualifier-types/testQualifierType.d.ts +15 -0
  129. package/lib/test/unit/qualifier-types/testQualifierType.js +89 -0
  130. package/lib/test/unit/qualifiers/convert.test.d.ts +2 -0
  131. package/lib/test/unit/qualifiers/qualifierCollector.test.d.ts +2 -0
  132. package/lib/test/unit/qualifiers/qualifierDefaultValue.test.d.ts +2 -0
  133. package/lib/test/unit/qualifiers/qualifierDefaultValueToken.test.d.ts +2 -0
  134. package/lib/test/unit/resource-json/convert.test.d.ts +2 -0
  135. package/lib/test/unit/resource-json/nameInheritance.test.d.ts +2 -0
  136. package/lib/test/unit/resource-json/resourceDeclCollection.test.d.ts +2 -0
  137. package/lib/test/unit/resource-json/resourceDeclTree.test.d.ts +2 -0
  138. package/lib/test/unit/resource-types/jsonResourceType.test.d.ts +2 -0
  139. package/lib/test/unit/resource-types/resourceTypeCollector.test.d.ts +2 -0
  140. package/lib/test/unit/resources/candidateReducer.integration.test.d.ts +2 -0
  141. package/lib/test/unit/resources/candidateReducer.test.d.ts +2 -0
  142. package/lib/test/unit/resources/reduceCandidates.test.d.ts +2 -0
  143. package/lib/test/unit/resources/reduceQualifiers.comprehensive.test.d.ts +2 -0
  144. package/lib/test/unit/resources/reduceQualifiers.test.d.ts +2 -0
  145. package/lib/test/unit/resources/resource.test.d.ts +2 -0
  146. package/lib/test/unit/resources/resourceBuilder.test.d.ts +2 -0
  147. package/lib/test/unit/resources/resourceCandidate.test.d.ts +2 -0
  148. package/lib/test/unit/resources/resourceManagerBuilder.clone.test.d.ts +2 -0
  149. package/lib/test/unit/resources/resourceManagerBuilder.getBuiltResourceTree.test.d.ts +2 -0
  150. package/lib/test/unit/resources/resourceManagerBuilder.test.d.ts +2 -0
  151. package/lib/test/unit/runtime/cacheListener.test.d.ts +2 -0
  152. package/lib/test/unit/runtime/cacheMetrics.test.d.ts +2 -0
  153. package/lib/test/unit/runtime/compiledResourceCollection.test.d.ts +2 -0
  154. package/lib/test/unit/runtime/conditionSetResolutionResult.comprehensive.test.d.ts +2 -0
  155. package/lib/test/unit/runtime/conditionSetResolutionResult.test.d.ts +2 -0
  156. package/lib/test/unit/runtime/context/contextQualifierProvider.test.d.ts +2 -0
  157. package/lib/test/unit/runtime/context/contextQualifierProviderValidator.test.d.ts +2 -0
  158. package/lib/test/unit/runtime/context/simpleContextQualifierProvider.test.d.ts +2 -0
  159. package/lib/test/unit/runtime/context/validatingSimpleContextQualifierProvider.test.d.ts +2 -0
  160. package/lib/test/unit/runtime/resource-tree/readOnlyResourceTree.test.d.ts +2 -0
  161. package/lib/test/unit/runtime/resource-tree/resourceTreeChildren.test.d.ts +2 -0
  162. package/lib/test/unit/runtime/resource-tree/resourceTreeChildrenValidator.test.d.ts +2 -0
  163. package/lib/test/unit/runtime/resourceResolver.defaultResolution.test.d.ts +2 -0
  164. package/lib/test/unit/runtime/resourceResolver.test.d.ts +2 -0
  165. package/lib/test/unit/runtime/validate.test.d.ts +2 -0
  166. package/lib/test/unit/zip-archive/convert.test.d.ts +2 -0
  167. package/lib/test/unit/zip-archive/json.test.d.ts +2 -0
  168. package/lib/test/unit/zip-archive/zipArchiveCreator.test.d.ts +2 -0
  169. package/lib/test/unit/zip-archive/zipArchiveFormat.test.d.ts +2 -0
  170. package/lib/test/unit/zip-archive/zipArchiveIdempotency.test.d.ts +2 -0
  171. package/lib/test/unit/zip-archive/zipArchiveLoader.test.d.ts +2 -0
  172. package/package.json +19 -25
  173. package/src/index.ts +75 -0
  174. package/src/packlets/bundle/bundleBuilder.ts +159 -0
  175. package/src/packlets/bundle/bundleLoader.ts +157 -0
  176. package/src/packlets/bundle/bundleNormalizer.ts +173 -0
  177. package/src/packlets/bundle/bundleUtils.ts +142 -0
  178. package/src/packlets/bundle/convert.ts +87 -0
  179. package/src/packlets/bundle/index.ts +52 -0
  180. package/src/packlets/bundle/model.ts +138 -0
  181. package/src/packlets/common/conditions.ts +226 -0
  182. package/src/packlets/common/convert.ts +184 -0
  183. package/src/packlets/common/helpers/conditions.ts +84 -0
  184. package/src/packlets/common/helpers/context.ts +88 -0
  185. package/src/packlets/common/helpers/index.ts +26 -0
  186. package/src/packlets/common/helpers/qualifierDefaultValues.ts +91 -0
  187. package/src/packlets/common/helpers/resources.ts +96 -0
  188. package/src/packlets/common/index.ts +30 -0
  189. package/src/packlets/common/resources.ts +78 -0
  190. package/src/packlets/common/validate/conditions.ts +595 -0
  191. package/src/packlets/common/validate/index.ts +27 -0
  192. package/src/packlets/common/validate/regularExpressions.ts +92 -0
  193. package/src/packlets/common/validate/resources.ts +170 -0
  194. package/src/packlets/conditions/condition.ts +351 -0
  195. package/src/packlets/conditions/conditionCollector.ts +103 -0
  196. package/src/packlets/conditions/conditionDecls.ts +50 -0
  197. package/src/packlets/conditions/conditionSet.ts +318 -0
  198. package/src/packlets/conditions/conditionSetCollector.ts +127 -0
  199. package/src/packlets/conditions/conditionSetDecls.ts +41 -0
  200. package/src/packlets/conditions/conditionToken.ts +180 -0
  201. package/src/packlets/conditions/convert/conditionSetDecls.ts +72 -0
  202. package/src/packlets/conditions/convert/decls.ts +95 -0
  203. package/src/packlets/conditions/convert/index.ts +24 -0
  204. package/src/packlets/conditions/index.ts +33 -0
  205. package/src/packlets/config/common.ts +107 -0
  206. package/src/packlets/config/configInitFactory.ts +142 -0
  207. package/src/packlets/config/convert.ts +61 -0
  208. package/src/packlets/config/index.ts +30 -0
  209. package/src/packlets/config/json.ts +43 -0
  210. package/src/packlets/config/predefined/default.ts +150 -0
  211. package/src/packlets/config/predefined/extended.ts +198 -0
  212. package/src/packlets/config/predefined/index.ts +26 -0
  213. package/src/packlets/config/systemConfiguration.ts +217 -0
  214. package/src/packlets/context/contextDecls.ts +76 -0
  215. package/src/packlets/context/contextToken.ts +252 -0
  216. package/src/packlets/context/convert/decls.ts +126 -0
  217. package/src/packlets/context/convert/index.ts +23 -0
  218. package/src/packlets/context/index.ts +27 -0
  219. package/src/packlets/decisions/abstractDecision.ts +87 -0
  220. package/src/packlets/decisions/abstractDecisionCollector.ts +122 -0
  221. package/src/packlets/decisions/candidate.ts +101 -0
  222. package/src/packlets/decisions/common.ts +37 -0
  223. package/src/packlets/decisions/concreteDecision.ts +157 -0
  224. package/src/packlets/decisions/decision.ts +172 -0
  225. package/src/packlets/decisions/index.ts +28 -0
  226. package/src/packlets/import/fsItem.ts +212 -0
  227. package/src/packlets/import/importContext.ts +183 -0
  228. package/src/packlets/import/importManager.ts +187 -0
  229. package/src/packlets/import/importable.ts +107 -0
  230. package/src/packlets/import/importers/collectionImporter.ts +153 -0
  231. package/src/packlets/import/importers/fsItemImporter.ts +154 -0
  232. package/src/packlets/import/importers/importer.ts +58 -0
  233. package/src/packlets/import/importers/index.ts +27 -0
  234. package/src/packlets/import/importers/jsonImporter.ts +133 -0
  235. package/src/packlets/import/importers/pathImporter.ts +134 -0
  236. package/src/packlets/import/index.ts +29 -0
  237. package/src/packlets/qualifier-types/config/convert.ts +108 -0
  238. package/src/packlets/qualifier-types/config/index.ts +27 -0
  239. package/src/packlets/qualifier-types/config/json.ts +126 -0
  240. package/src/packlets/qualifier-types/convert.ts +77 -0
  241. package/src/packlets/qualifier-types/helpers.ts +94 -0
  242. package/src/packlets/qualifier-types/index.ts +34 -0
  243. package/src/packlets/qualifier-types/languageQualifierType.ts +143 -0
  244. package/src/packlets/qualifier-types/literalQualifierType.ts +244 -0
  245. package/src/packlets/qualifier-types/literalValueHierarchy.ts +332 -0
  246. package/src/packlets/qualifier-types/qualifierType.ts +360 -0
  247. package/src/packlets/qualifier-types/qualifierTypeCollector.ts +102 -0
  248. package/src/packlets/qualifier-types/territoryQualifierType.ts +255 -0
  249. package/src/packlets/qualifiers/convert/decls.ts +90 -0
  250. package/src/packlets/qualifiers/convert/index.ts +24 -0
  251. package/src/packlets/qualifiers/convert/qualifier.ts +55 -0
  252. package/src/packlets/qualifiers/index.ts +31 -0
  253. package/src/packlets/qualifiers/qualifier.ts +169 -0
  254. package/src/packlets/qualifiers/qualifierCollector.ts +194 -0
  255. package/src/packlets/qualifiers/qualifierDecl.ts +80 -0
  256. package/src/packlets/qualifiers/qualifierDefaultValueDecls.ts +57 -0
  257. package/src/packlets/qualifiers/qualifierDefaultValueToken.ts +230 -0
  258. package/src/packlets/resource-json/compiled/common.ts +35 -0
  259. package/src/packlets/resource-json/compiled/convert.ts +143 -0
  260. package/src/packlets/resource-json/compiled/index.ts +27 -0
  261. package/src/packlets/resource-json/compiled/json.ts +239 -0
  262. package/src/packlets/resource-json/convert.ts +236 -0
  263. package/src/packlets/resource-json/helpers.ts +284 -0
  264. package/src/packlets/resource-json/index.ts +33 -0
  265. package/src/packlets/resource-json/json.ts +295 -0
  266. package/src/packlets/resource-json/normalized.ts +211 -0
  267. package/src/packlets/resource-json/resourceDeclCollection.ts +117 -0
  268. package/src/packlets/resource-json/resourceDeclContainer.ts +48 -0
  269. package/src/packlets/resource-json/resourceDeclTree.ts +116 -0
  270. package/src/packlets/resource-types/config/convert.ts +36 -0
  271. package/src/packlets/resource-types/config/index.ts +27 -0
  272. package/src/packlets/resource-types/config/json.ts +30 -0
  273. package/src/packlets/resource-types/helpers.ts +44 -0
  274. package/src/packlets/resource-types/index.ts +30 -0
  275. package/src/packlets/resource-types/jsonResourceType.ts +104 -0
  276. package/src/packlets/resource-types/resourceType.ts +259 -0
  277. package/src/packlets/resource-types/resourceTypeCollector.ts +79 -0
  278. package/src/packlets/resources/candidateReducer.ts +331 -0
  279. package/src/packlets/resources/common.ts +114 -0
  280. package/src/packlets/resources/index.ts +28 -0
  281. package/src/packlets/resources/resource.ts +307 -0
  282. package/src/packlets/resources/resourceBuilder.ts +269 -0
  283. package/src/packlets/resources/resourceCandidate.ts +333 -0
  284. package/src/packlets/resources/resourceManagerBuilder.ts +1169 -0
  285. package/src/packlets/runtime/cacheListener.ts +113 -0
  286. package/src/packlets/runtime/cacheMetrics.ts +206 -0
  287. package/src/packlets/runtime/compiledResourceCollection.ts +607 -0
  288. package/src/packlets/runtime/conditionSetResolutionResult.ts +160 -0
  289. package/src/packlets/runtime/context/contextQualifierProvider.ts +117 -0
  290. package/src/packlets/runtime/context/contextQualifierProviderValidator.ts +281 -0
  291. package/src/packlets/runtime/context/index.ts +26 -0
  292. package/src/packlets/runtime/context/simpleContextQualifierProvider.ts +225 -0
  293. package/src/packlets/runtime/context/validatingSimpleContextQualifierProvider.ts +96 -0
  294. package/src/packlets/runtime/iResourceManager.ts +130 -0
  295. package/src/packlets/runtime/index.ts +35 -0
  296. package/src/packlets/runtime/resource-tree/common.ts +126 -0
  297. package/src/packlets/runtime/resource-tree/index.ts +26 -0
  298. package/src/packlets/runtime/resource-tree/readOnlyResourceTree.ts +342 -0
  299. package/src/packlets/runtime/resource-tree/resourceTreeChildren.ts +125 -0
  300. package/src/packlets/runtime/resource-tree/resourceTreeChildrenValidator.ts +187 -0
  301. package/src/packlets/runtime/resourceResolver.ts +626 -0
  302. package/src/packlets/runtime/validate.ts +63 -0
  303. package/src/packlets/zip-archive/convert.ts +121 -0
  304. package/src/packlets/zip-archive/index.ts +76 -0
  305. package/src/packlets/zip-archive/json.ts +91 -0
  306. package/src/packlets/zip-archive/types.ts +140 -0
  307. package/src/packlets/zip-archive/zipArchiveCreator.ts +229 -0
  308. package/src/packlets/zip-archive/zipArchiveFormat.ts +158 -0
  309. package/src/packlets/zip-archive/zipArchiveLoader.ts +370 -0
  310. package/CHANGELOG.md +0 -14
  311. package/CLAUDE.md +0 -186
  312. package/EXAMPLE_INIT_PARAMS.md +0 -88
  313. package/PROGRESS_SUMMARY.md +0 -48
  314. package/lib/index.d.ts.map +0 -1
  315. package/lib/index.js.map +0 -1
  316. package/lib/packlets/common/conditions.d.ts.map +0 -1
  317. package/lib/packlets/common/conditions.js.map +0 -1
  318. package/lib/packlets/common/convert.d.ts.map +0 -1
  319. package/lib/packlets/common/convert.js.map +0 -1
  320. package/lib/packlets/common/helpers/conditions.d.ts.map +0 -1
  321. package/lib/packlets/common/helpers/conditions.js.map +0 -1
  322. package/lib/packlets/common/helpers/context.d.ts.map +0 -1
  323. package/lib/packlets/common/helpers/context.js.map +0 -1
  324. package/lib/packlets/common/helpers/index.d.ts.map +0 -1
  325. package/lib/packlets/common/helpers/index.js.map +0 -1
  326. package/lib/packlets/common/helpers/qualifierDefaultValues.d.ts.map +0 -1
  327. package/lib/packlets/common/helpers/qualifierDefaultValues.js.map +0 -1
  328. package/lib/packlets/common/helpers/resources.d.ts.map +0 -1
  329. package/lib/packlets/common/helpers/resources.js.map +0 -1
  330. package/lib/packlets/common/index.d.ts.map +0 -1
  331. package/lib/packlets/common/index.js.map +0 -1
  332. package/lib/packlets/common/resources.d.ts.map +0 -1
  333. package/lib/packlets/common/resources.js.map +0 -1
  334. package/lib/packlets/common/validate/conditions.d.ts.map +0 -1
  335. package/lib/packlets/common/validate/conditions.js.map +0 -1
  336. package/lib/packlets/common/validate/index.d.ts.map +0 -1
  337. package/lib/packlets/common/validate/index.js.map +0 -1
  338. package/lib/packlets/common/validate/regularExpressions.d.ts.map +0 -1
  339. package/lib/packlets/common/validate/regularExpressions.js.map +0 -1
  340. package/lib/packlets/common/validate/resources.d.ts.map +0 -1
  341. package/lib/packlets/common/validate/resources.js.map +0 -1
  342. package/lib/packlets/conditions/condition.d.ts.map +0 -1
  343. package/lib/packlets/conditions/condition.js.map +0 -1
  344. package/lib/packlets/conditions/conditionCollector.d.ts.map +0 -1
  345. package/lib/packlets/conditions/conditionCollector.js.map +0 -1
  346. package/lib/packlets/conditions/conditionDecls.d.ts.map +0 -1
  347. package/lib/packlets/conditions/conditionDecls.js.map +0 -1
  348. package/lib/packlets/conditions/conditionSet.d.ts.map +0 -1
  349. package/lib/packlets/conditions/conditionSet.js.map +0 -1
  350. package/lib/packlets/conditions/conditionSetCollector.d.ts.map +0 -1
  351. package/lib/packlets/conditions/conditionSetCollector.js.map +0 -1
  352. package/lib/packlets/conditions/conditionSetDecls.d.ts.map +0 -1
  353. package/lib/packlets/conditions/conditionSetDecls.js.map +0 -1
  354. package/lib/packlets/conditions/conditionToken.d.ts.map +0 -1
  355. package/lib/packlets/conditions/conditionToken.js.map +0 -1
  356. package/lib/packlets/conditions/convert/conditionSetDecls.d.ts.map +0 -1
  357. package/lib/packlets/conditions/convert/conditionSetDecls.js.map +0 -1
  358. package/lib/packlets/conditions/convert/decls.d.ts.map +0 -1
  359. package/lib/packlets/conditions/convert/decls.js.map +0 -1
  360. package/lib/packlets/conditions/convert/index.d.ts.map +0 -1
  361. package/lib/packlets/conditions/convert/index.js.map +0 -1
  362. package/lib/packlets/conditions/index.d.ts.map +0 -1
  363. package/lib/packlets/conditions/index.js.map +0 -1
  364. package/lib/packlets/config/common.d.ts.map +0 -1
  365. package/lib/packlets/config/common.js.map +0 -1
  366. package/lib/packlets/config/convert.d.ts.map +0 -1
  367. package/lib/packlets/config/convert.js.map +0 -1
  368. package/lib/packlets/config/index.d.ts.map +0 -1
  369. package/lib/packlets/config/index.js.map +0 -1
  370. package/lib/packlets/config/json.d.ts.map +0 -1
  371. package/lib/packlets/config/json.js.map +0 -1
  372. package/lib/packlets/config/predefined/default.d.ts.map +0 -1
  373. package/lib/packlets/config/predefined/default.js.map +0 -1
  374. package/lib/packlets/config/predefined/extended.d.ts.map +0 -1
  375. package/lib/packlets/config/predefined/extended.js.map +0 -1
  376. package/lib/packlets/config/predefined/index.d.ts.map +0 -1
  377. package/lib/packlets/config/predefined/index.js.map +0 -1
  378. package/lib/packlets/config/systemConfiguration.d.ts.map +0 -1
  379. package/lib/packlets/config/systemConfiguration.js.map +0 -1
  380. package/lib/packlets/context/contextDecls.d.ts.map +0 -1
  381. package/lib/packlets/context/contextDecls.js.map +0 -1
  382. package/lib/packlets/context/contextToken.d.ts.map +0 -1
  383. package/lib/packlets/context/contextToken.js.map +0 -1
  384. package/lib/packlets/context/convert/decls.d.ts.map +0 -1
  385. package/lib/packlets/context/convert/decls.js.map +0 -1
  386. package/lib/packlets/context/convert/index.d.ts.map +0 -1
  387. package/lib/packlets/context/convert/index.js.map +0 -1
  388. package/lib/packlets/context/index.d.ts.map +0 -1
  389. package/lib/packlets/context/index.js.map +0 -1
  390. package/lib/packlets/decisions/abstractDecision.d.ts.map +0 -1
  391. package/lib/packlets/decisions/abstractDecision.js.map +0 -1
  392. package/lib/packlets/decisions/abstractDecisionCollector.d.ts.map +0 -1
  393. package/lib/packlets/decisions/abstractDecisionCollector.js.map +0 -1
  394. package/lib/packlets/decisions/candidate.d.ts.map +0 -1
  395. package/lib/packlets/decisions/candidate.js.map +0 -1
  396. package/lib/packlets/decisions/common.d.ts.map +0 -1
  397. package/lib/packlets/decisions/common.js.map +0 -1
  398. package/lib/packlets/decisions/concreteDecision.d.ts.map +0 -1
  399. package/lib/packlets/decisions/concreteDecision.js.map +0 -1
  400. package/lib/packlets/decisions/decision.d.ts.map +0 -1
  401. package/lib/packlets/decisions/decision.js.map +0 -1
  402. package/lib/packlets/decisions/index.d.ts.map +0 -1
  403. package/lib/packlets/decisions/index.js.map +0 -1
  404. package/lib/packlets/import/fsItem.d.ts.map +0 -1
  405. package/lib/packlets/import/fsItem.js.map +0 -1
  406. package/lib/packlets/import/importContext.d.ts.map +0 -1
  407. package/lib/packlets/import/importContext.js.map +0 -1
  408. package/lib/packlets/import/importManager.d.ts.map +0 -1
  409. package/lib/packlets/import/importManager.js.map +0 -1
  410. package/lib/packlets/import/importable.d.ts.map +0 -1
  411. package/lib/packlets/import/importable.js.map +0 -1
  412. package/lib/packlets/import/importers/collectionImporter.d.ts.map +0 -1
  413. package/lib/packlets/import/importers/collectionImporter.js.map +0 -1
  414. package/lib/packlets/import/importers/fsItemImporter.d.ts.map +0 -1
  415. package/lib/packlets/import/importers/fsItemImporter.js.map +0 -1
  416. package/lib/packlets/import/importers/importer.d.ts.map +0 -1
  417. package/lib/packlets/import/importers/importer.js.map +0 -1
  418. package/lib/packlets/import/importers/index.d.ts.map +0 -1
  419. package/lib/packlets/import/importers/index.js.map +0 -1
  420. package/lib/packlets/import/importers/jsonImporter.d.ts.map +0 -1
  421. package/lib/packlets/import/importers/jsonImporter.js.map +0 -1
  422. package/lib/packlets/import/importers/pathImporter.d.ts.map +0 -1
  423. package/lib/packlets/import/importers/pathImporter.js.map +0 -1
  424. package/lib/packlets/import/index.d.ts.map +0 -1
  425. package/lib/packlets/import/index.js.map +0 -1
  426. package/lib/packlets/qualifier-types/config/convert.d.ts.map +0 -1
  427. package/lib/packlets/qualifier-types/config/convert.js.map +0 -1
  428. package/lib/packlets/qualifier-types/config/index.d.ts.map +0 -1
  429. package/lib/packlets/qualifier-types/config/index.js.map +0 -1
  430. package/lib/packlets/qualifier-types/config/json.d.ts.map +0 -1
  431. package/lib/packlets/qualifier-types/config/json.js.map +0 -1
  432. package/lib/packlets/qualifier-types/convert.d.ts.map +0 -1
  433. package/lib/packlets/qualifier-types/convert.js.map +0 -1
  434. package/lib/packlets/qualifier-types/helpers.d.ts.map +0 -1
  435. package/lib/packlets/qualifier-types/helpers.js.map +0 -1
  436. package/lib/packlets/qualifier-types/index.d.ts.map +0 -1
  437. package/lib/packlets/qualifier-types/index.js.map +0 -1
  438. package/lib/packlets/qualifier-types/languageQualifierType.d.ts.map +0 -1
  439. package/lib/packlets/qualifier-types/languageQualifierType.js.map +0 -1
  440. package/lib/packlets/qualifier-types/literalQualifierType.d.ts.map +0 -1
  441. package/lib/packlets/qualifier-types/literalQualifierType.js.map +0 -1
  442. package/lib/packlets/qualifier-types/literalValueHierarchy.d.ts.map +0 -1
  443. package/lib/packlets/qualifier-types/literalValueHierarchy.js.map +0 -1
  444. package/lib/packlets/qualifier-types/qualifierType.d.ts.map +0 -1
  445. package/lib/packlets/qualifier-types/qualifierType.js.map +0 -1
  446. package/lib/packlets/qualifier-types/qualifierTypeCollector.d.ts.map +0 -1
  447. package/lib/packlets/qualifier-types/qualifierTypeCollector.js.map +0 -1
  448. package/lib/packlets/qualifier-types/territoryQualifierType.d.ts.map +0 -1
  449. package/lib/packlets/qualifier-types/territoryQualifierType.js.map +0 -1
  450. package/lib/packlets/qualifiers/convert/decls.d.ts.map +0 -1
  451. package/lib/packlets/qualifiers/convert/decls.js.map +0 -1
  452. package/lib/packlets/qualifiers/convert/index.d.ts.map +0 -1
  453. package/lib/packlets/qualifiers/convert/index.js.map +0 -1
  454. package/lib/packlets/qualifiers/convert/qualifier.d.ts.map +0 -1
  455. package/lib/packlets/qualifiers/convert/qualifier.js.map +0 -1
  456. package/lib/packlets/qualifiers/index.d.ts.map +0 -1
  457. package/lib/packlets/qualifiers/index.js.map +0 -1
  458. package/lib/packlets/qualifiers/qualifier.d.ts.map +0 -1
  459. package/lib/packlets/qualifiers/qualifier.js.map +0 -1
  460. package/lib/packlets/qualifiers/qualifierCollector.d.ts.map +0 -1
  461. package/lib/packlets/qualifiers/qualifierCollector.js.map +0 -1
  462. package/lib/packlets/qualifiers/qualifierDecl.d.ts.map +0 -1
  463. package/lib/packlets/qualifiers/qualifierDecl.js.map +0 -1
  464. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.d.ts.map +0 -1
  465. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.js.map +0 -1
  466. package/lib/packlets/qualifiers/qualifierDefaultValueToken.d.ts.map +0 -1
  467. package/lib/packlets/qualifiers/qualifierDefaultValueToken.js.map +0 -1
  468. package/lib/packlets/resource-json/compiled/common.d.ts.map +0 -1
  469. package/lib/packlets/resource-json/compiled/common.js.map +0 -1
  470. package/lib/packlets/resource-json/compiled/convert.d.ts.map +0 -1
  471. package/lib/packlets/resource-json/compiled/convert.js.map +0 -1
  472. package/lib/packlets/resource-json/compiled/index.d.ts.map +0 -1
  473. package/lib/packlets/resource-json/compiled/index.js.map +0 -1
  474. package/lib/packlets/resource-json/compiled/json.d.ts.map +0 -1
  475. package/lib/packlets/resource-json/compiled/json.js.map +0 -1
  476. package/lib/packlets/resource-json/convert.d.ts.map +0 -1
  477. package/lib/packlets/resource-json/convert.js.map +0 -1
  478. package/lib/packlets/resource-json/helpers.d.ts.map +0 -1
  479. package/lib/packlets/resource-json/helpers.js.map +0 -1
  480. package/lib/packlets/resource-json/index.d.ts.map +0 -1
  481. package/lib/packlets/resource-json/index.js.map +0 -1
  482. package/lib/packlets/resource-json/json.d.ts.map +0 -1
  483. package/lib/packlets/resource-json/json.js.map +0 -1
  484. package/lib/packlets/resource-json/normalized.d.ts.map +0 -1
  485. package/lib/packlets/resource-json/normalized.js.map +0 -1
  486. package/lib/packlets/resource-json/resourceDeclCollection.d.ts.map +0 -1
  487. package/lib/packlets/resource-json/resourceDeclCollection.js.map +0 -1
  488. package/lib/packlets/resource-json/resourceDeclContainer.d.ts.map +0 -1
  489. package/lib/packlets/resource-json/resourceDeclContainer.js.map +0 -1
  490. package/lib/packlets/resource-json/resourceDeclTree.d.ts.map +0 -1
  491. package/lib/packlets/resource-json/resourceDeclTree.js.map +0 -1
  492. package/lib/packlets/resource-types/config/convert.d.ts.map +0 -1
  493. package/lib/packlets/resource-types/config/convert.js.map +0 -1
  494. package/lib/packlets/resource-types/config/index.d.ts.map +0 -1
  495. package/lib/packlets/resource-types/config/index.js.map +0 -1
  496. package/lib/packlets/resource-types/config/json.d.ts.map +0 -1
  497. package/lib/packlets/resource-types/config/json.js.map +0 -1
  498. package/lib/packlets/resource-types/helpers.d.ts.map +0 -1
  499. package/lib/packlets/resource-types/helpers.js.map +0 -1
  500. package/lib/packlets/resource-types/index.d.ts.map +0 -1
  501. package/lib/packlets/resource-types/index.js.map +0 -1
  502. package/lib/packlets/resource-types/jsonResourceType.d.ts.map +0 -1
  503. package/lib/packlets/resource-types/jsonResourceType.js.map +0 -1
  504. package/lib/packlets/resource-types/resourceType.d.ts.map +0 -1
  505. package/lib/packlets/resource-types/resourceType.js.map +0 -1
  506. package/lib/packlets/resource-types/resourceTypeCollector.d.ts.map +0 -1
  507. package/lib/packlets/resource-types/resourceTypeCollector.js.map +0 -1
  508. package/lib/packlets/resources/candidateReducer.d.ts.map +0 -1
  509. package/lib/packlets/resources/candidateReducer.js.map +0 -1
  510. package/lib/packlets/resources/common.d.ts.map +0 -1
  511. package/lib/packlets/resources/common.js.map +0 -1
  512. package/lib/packlets/resources/index.d.ts.map +0 -1
  513. package/lib/packlets/resources/index.js.map +0 -1
  514. package/lib/packlets/resources/resource.d.ts.map +0 -1
  515. package/lib/packlets/resources/resource.js.map +0 -1
  516. package/lib/packlets/resources/resourceBuilder.d.ts.map +0 -1
  517. package/lib/packlets/resources/resourceBuilder.js.map +0 -1
  518. package/lib/packlets/resources/resourceCandidate.d.ts.map +0 -1
  519. package/lib/packlets/resources/resourceCandidate.js.map +0 -1
  520. package/lib/packlets/resources/resourceManagerBuilder.d.ts.map +0 -1
  521. package/lib/packlets/resources/resourceManagerBuilder.js.map +0 -1
  522. package/lib/packlets/runtime/cacheListener.d.ts.map +0 -1
  523. package/lib/packlets/runtime/cacheListener.js.map +0 -1
  524. package/lib/packlets/runtime/cacheMetrics.d.ts.map +0 -1
  525. package/lib/packlets/runtime/cacheMetrics.js.map +0 -1
  526. package/lib/packlets/runtime/compiledResourceCollection.d.ts.map +0 -1
  527. package/lib/packlets/runtime/compiledResourceCollection.js.map +0 -1
  528. package/lib/packlets/runtime/conditionSetResolutionResult.d.ts.map +0 -1
  529. package/lib/packlets/runtime/conditionSetResolutionResult.js.map +0 -1
  530. package/lib/packlets/runtime/context/contextQualifierProvider.d.ts.map +0 -1
  531. package/lib/packlets/runtime/context/contextQualifierProvider.js.map +0 -1
  532. package/lib/packlets/runtime/context/contextQualifierProviderValidator.d.ts.map +0 -1
  533. package/lib/packlets/runtime/context/contextQualifierProviderValidator.js.map +0 -1
  534. package/lib/packlets/runtime/context/index.d.ts.map +0 -1
  535. package/lib/packlets/runtime/context/index.js.map +0 -1
  536. package/lib/packlets/runtime/context/simpleContextQualifierProvider.d.ts.map +0 -1
  537. package/lib/packlets/runtime/context/simpleContextQualifierProvider.js.map +0 -1
  538. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.d.ts.map +0 -1
  539. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.js.map +0 -1
  540. package/lib/packlets/runtime/iResourceManager.d.ts.map +0 -1
  541. package/lib/packlets/runtime/iResourceManager.js.map +0 -1
  542. package/lib/packlets/runtime/index.d.ts.map +0 -1
  543. package/lib/packlets/runtime/index.js.map +0 -1
  544. package/lib/packlets/runtime/resource-tree/common.d.ts.map +0 -1
  545. package/lib/packlets/runtime/resource-tree/common.js.map +0 -1
  546. package/lib/packlets/runtime/resource-tree/index.d.ts.map +0 -1
  547. package/lib/packlets/runtime/resource-tree/index.js.map +0 -1
  548. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.d.ts.map +0 -1
  549. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.js.map +0 -1
  550. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.d.ts.map +0 -1
  551. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.js.map +0 -1
  552. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.d.ts.map +0 -1
  553. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js.map +0 -1
  554. package/lib/packlets/runtime/resourceResolver.d.ts.map +0 -1
  555. package/lib/packlets/runtime/resourceResolver.js.map +0 -1
  556. package/lib/packlets/runtime/validate.d.ts.map +0 -1
  557. package/lib/packlets/runtime/validate.js.map +0 -1
@@ -0,0 +1,1169 @@
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
+
23
+ import {
24
+ captureResult,
25
+ Collections,
26
+ DetailedResult,
27
+ fail,
28
+ failWithDetail,
29
+ Hash,
30
+ mapResults,
31
+ MessageAggregator,
32
+ Result,
33
+ succeed,
34
+ succeedWithDetail,
35
+ ValidatingResultMap
36
+ } from '@fgv/ts-utils';
37
+ import { Converters as JsonConverters } from '@fgv/ts-json-base';
38
+ import {
39
+ ConditionCollector,
40
+ ConditionSetCollector,
41
+ ReadOnlyConditionCollector,
42
+ ReadOnlyConditionSetCollector,
43
+ Convert as ConditionsConvert,
44
+ Condition,
45
+ ConditionSet,
46
+ IConditionSetDecl
47
+ } from '../conditions';
48
+ import { AbstractDecisionCollector, ReadOnlyAbstractDecisionCollector, AbstractDecision } from '../decisions';
49
+ import { IReadOnlyQualifierCollector } from '../qualifiers';
50
+ import { ReadOnlyResourceTypeCollector, ResourceType } from '../resource-types';
51
+ import { Convert, ResourceId, Validate } from '../common';
52
+ import { IResourceManager, ResourceTree } from '../runtime';
53
+ import { ResourceBuilder, ResourceBuilderResultDetail } from './resourceBuilder';
54
+ import { Resource } from './resource';
55
+ import { ResourceCandidate } from './resourceCandidate';
56
+ import { IResourceDeclarationOptions, IResourceManagerCloneOptions } from './common';
57
+ import * as ResourceJson from '../resource-json';
58
+ import * as Context from '../context';
59
+ import * as Config from '../config';
60
+ import { JsonEditor } from '@fgv/ts-json';
61
+ import { ReadOnlyQualifierTypeCollector } from '../qualifier-types';
62
+
63
+ /**
64
+ * Interface for parameters to the {@link Resources.ResourceManagerBuilder.create | ResourceManagerBuilder create method}.
65
+ * @public
66
+ */
67
+ export interface IResourceManagerBuilderCreateParams {
68
+ qualifiers: IReadOnlyQualifierCollector;
69
+ resourceTypes: ReadOnlyResourceTypeCollector;
70
+ }
71
+
72
+ /**
73
+ * Error details that can be returned by a {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder}.
74
+ * @public
75
+ */
76
+ export type ResourceManagerBuilderResultDetail =
77
+ | Collections.ResultMapResultDetail
78
+ | ResourceBuilderResultDetail;
79
+
80
+ /**
81
+ * Builder for a collection of {@link Resources.Resource | resources}. Collects
82
+ * {@link Resources.ResourceCandidate | candidates} for each resource into a
83
+ * {@link Resources.ResourceBuilder | ResourceBuilder} per resource, validates them against each other,
84
+ * and builds a collection of {@link Resources.Resource | resources} once all candidates are collected.
85
+ * @public
86
+ */
87
+ export class ResourceManagerBuilder implements IResourceManager<Resource> {
88
+ /**
89
+ * The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} used by this resource manager.
90
+ */
91
+ public readonly qualifiers: IReadOnlyQualifierCollector;
92
+
93
+ /**
94
+ * The {@link ResourceTypes.ReadOnlyResourceTypeCollector | resource types} used by this resource manager.
95
+ */
96
+ public readonly resourceTypes: ReadOnlyResourceTypeCollector;
97
+
98
+ /**
99
+ * The {@link Conditions.ConditionCollector | condition collector} used by this resource manager.
100
+ * @internal
101
+ */
102
+ protected readonly _conditions: ConditionCollector;
103
+
104
+ /**
105
+ * The {@link Conditions.ConditionSetCollector | condition set collector} used by this resource manager.
106
+ * @internal
107
+ */
108
+ protected readonly _conditionSets: ConditionSetCollector;
109
+
110
+ /**
111
+ * The {@link Decisions.AbstractDecisionCollector | abstract decision collector} used by this resource manager.
112
+ * @internal
113
+ */
114
+ protected readonly _decisions: AbstractDecisionCollector;
115
+
116
+ /**
117
+ * The {@link Resources.ResourceBuilder | resource builders} used by this resource manager.
118
+ * @internal
119
+ */
120
+ protected readonly _resources: ValidatingResultMap<ResourceId, ResourceBuilder>;
121
+
122
+ /**
123
+ * The {@link Resources.Resource | resources} built by this resource manager.
124
+ * @internal
125
+ */
126
+ protected readonly _builtResources: ValidatingResultMap<ResourceId, Resource>;
127
+
128
+ /**
129
+ * Whether the resources have been built.
130
+ * @internal
131
+ */
132
+ protected _built: boolean;
133
+
134
+ /**
135
+ * The cached resource tree for this resource manager.
136
+ * @internal
137
+ */
138
+ protected _cachedResourceTree?: ResourceTree.IReadOnlyResourceTreeRoot<Resource>;
139
+
140
+ /**
141
+ * The {@link QualifierTypes.ReadOnlyQualifierTypeCollector | qualifier types} used by this resource manager.
142
+ */
143
+ public get qualifierTypes(): ReadOnlyQualifierTypeCollector {
144
+ return this.qualifiers.qualifierTypes;
145
+ }
146
+
147
+ /**
148
+ * A {@link Conditions.ConditionCollector | ConditionCollector} which
149
+ * contains the {@link Conditions.Condition | conditions} used so far by
150
+ * the {@link Resources.ResourceCandidate | resource candidates} in this manager.
151
+ */
152
+ public get conditions(): ReadOnlyConditionCollector {
153
+ return this._conditions;
154
+ }
155
+
156
+ /**
157
+ * A {@link Conditions.ConditionSetCollector | ConditionSetCollector} which
158
+ * contains the {@link Conditions.ConditionSet | condition sets} used so far by
159
+ * the {@link Resources.ResourceCandidate | resource candidates} in this manager.
160
+ */
161
+ public get conditionSets(): ReadOnlyConditionSetCollector {
162
+ return this._conditionSets;
163
+ }
164
+
165
+ /**
166
+ * A {@link Decisions.AbstractDecisionCollector | AbstractDecisionCollector} which
167
+ * contains the {@link Decisions.Decision | abstract decisions} used so far by
168
+ * the {@link Resources.ResourceCandidate | resource candidates} in this manager.
169
+ */
170
+ public get decisions(): ReadOnlyAbstractDecisionCollector {
171
+ return this._decisions;
172
+ }
173
+
174
+ /**
175
+ * A read-only map of {@link Resources.ResourceBuilder | resource builders} used by the manager.
176
+ */
177
+ public get resources(): Collections.IReadOnlyValidatingResultMap<ResourceId, ResourceBuilder> {
178
+ return this._resources;
179
+ }
180
+
181
+ /**
182
+ * The number of {@link Resources.Resource | resources} contained by the manager.
183
+ */
184
+ public get size(): number {
185
+ return this._resources.size;
186
+ }
187
+
188
+ /**
189
+ * {@inheritdoc Runtime.IResourceManager.numResources}
190
+ */
191
+ public get numResources(): number {
192
+ return this._resources.size;
193
+ }
194
+
195
+ /**
196
+ * The number of candidates in this resource manager.
197
+ */
198
+ protected _numCandidates?: number;
199
+
200
+ /**
201
+ * {@inheritdoc Runtime.IResourceManager.numCandidates}
202
+ */
203
+ public get numCandidates(): number {
204
+ if (this._numCandidates === undefined) {
205
+ this._numCandidates = this.getAllCandidates().length;
206
+ }
207
+ return this._numCandidates;
208
+ }
209
+
210
+ /**
211
+ * {@inheritdoc Runtime.IResourceManager.builtResources}
212
+ */
213
+ public get builtResources(): Collections.IReadOnlyValidatingResultMap<ResourceId, Resource> {
214
+ return this._performBuild().orThrow();
215
+ }
216
+
217
+ /**
218
+ * Constructor for a {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object.
219
+ * @param params - Parameters to create a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder}.
220
+ * @public
221
+ */
222
+ protected constructor(params: IResourceManagerBuilderCreateParams) {
223
+ this.qualifiers = params.qualifiers;
224
+ this.resourceTypes = params.resourceTypes;
225
+ this._conditions = ConditionCollector.create({ qualifiers: params.qualifiers }).orThrow();
226
+ this._conditionSets = ConditionSetCollector.create({ conditions: this._conditions }).orThrow();
227
+ this._decisions = AbstractDecisionCollector.create({ conditionSets: this._conditionSets }).orThrow();
228
+ this._resources = new ValidatingResultMap({
229
+ converters: new Collections.KeyValueConverters<ResourceId, ResourceBuilder>({
230
+ key: Convert.resourceId,
231
+ /* c8 ignore next 2 - defense in depth against internal error */
232
+ value: (from: unknown) =>
233
+ from instanceof ResourceBuilder ? succeed(from) : fail('not a resource builder')
234
+ })
235
+ });
236
+ this._builtResources = new ValidatingResultMap({
237
+ converters: new Collections.KeyValueConverters<ResourceId, Resource>({
238
+ key: Convert.resourceId,
239
+ /* c8 ignore next 1 - defense in depth against internal error */
240
+ value: (from: unknown) => (from instanceof Resource ? succeed(from) : fail('not a resource'))
241
+ })
242
+ });
243
+ this._built = false;
244
+ this._cachedResourceTree = undefined;
245
+ }
246
+
247
+ /**
248
+ * Creates a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object.
249
+ * @param params - Parameters to create a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder}.
250
+ * @returns `Success` with the new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object if successful,
251
+ * or `Failure` with an error message if not.
252
+ * @public
253
+ */
254
+ public static create(params: IResourceManagerBuilderCreateParams): Result<ResourceManagerBuilder> {
255
+ return captureResult(() => new ResourceManagerBuilder(params));
256
+ }
257
+
258
+ /**
259
+ * Creates a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object from a predefined system configuration.
260
+ * @param name - The name of the predefined system configuration to use.
261
+ * @param qualifierDefaultValues - Optional default values for qualifiers.
262
+ * @returns `Success` with the new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object if successful,
263
+ * or `Failure` with an error message if not.
264
+ * @public
265
+ */
266
+ public static createPredefined(
267
+ name: Config.PredefinedSystemConfiguration,
268
+ qualifierDefaultValues?: Config.ISystemConfigurationInitParams['qualifierDefaultValues']
269
+ ): Result<ResourceManagerBuilder> {
270
+ return Config.getPredefinedSystemConfiguration(
271
+ name,
272
+ /* c8 ignore next 1 - defense in depth */
273
+ qualifierDefaultValues ? { qualifierDefaultValues } : undefined
274
+ ).onSuccess((systemConfig) => {
275
+ return ResourceManagerBuilder.create({
276
+ qualifiers: systemConfig.qualifiers,
277
+ resourceTypes: systemConfig.resourceTypes
278
+ });
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Creates a new {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} from a
284
+ * {@link ResourceJson.Compiled.ICompiledResourceCollection | compiled resource collection}.
285
+ * This method reconstructs an exactly equivalent builder where all qualifier, condition,
286
+ * condition set, and decision indices match the original compiled collection.
287
+ * @param compiledCollection - The compiled resource collection to reconstruct from.
288
+ * @param systemConfig - The system configuration containing qualifiers and resource types.
289
+ * @returns `Success` with the new manager if successful, or `Failure` with an error message if not.
290
+ * @public
291
+ */
292
+ public static createFromCompiledResourceCollection(
293
+ compiledCollection: ResourceJson.Compiled.ICompiledResourceCollection,
294
+ systemConfig: Config.SystemConfiguration
295
+ ): Result<ResourceManagerBuilder> {
296
+ // Create the base builder with system configuration
297
+ return ResourceManagerBuilder.create({
298
+ qualifiers: systemConfig.qualifiers,
299
+ resourceTypes: systemConfig.resourceTypes
300
+ }).onSuccess((builder) => {
301
+ // Reconstruct all entities in order to preserve indices
302
+ return ResourceManagerBuilder._reconstructConditions(builder, compiledCollection)
303
+ .onSuccess(() => ResourceManagerBuilder._reconstructConditionSets(builder, compiledCollection))
304
+ .onSuccess(() => ResourceManagerBuilder._reconstructDecisions(builder, compiledCollection))
305
+ .onSuccess(() => ResourceManagerBuilder._reconstructResources(builder, compiledCollection))
306
+ .onSuccess(() => succeed(builder));
307
+ });
308
+ }
309
+
310
+ /**
311
+ * Given a {@link ResourceJson.Json.ILooseResourceCandidateDecl | resource candidate declaration}, builds and adds
312
+ * a {@link Resources.ResourceCandidate | candidate} to the manager.
313
+ * @param candidate - The {@link Resources.ResourceCandidate | candidate} to add.
314
+ * @returns `Success` with the candidate if successful, or `Failure` with an error message if not.
315
+ * @public
316
+ */
317
+ public addLooseCandidate(
318
+ decl: ResourceJson.Json.ILooseResourceCandidateDecl
319
+ ): DetailedResult<ResourceCandidate, ResourceBuilderResultDetail> {
320
+ const { value: id, message } = Validate.toResourceId(decl.id);
321
+ if (message !== undefined) {
322
+ return failWithDetail(`${id}: invalid id - ${message}`, 'failure');
323
+ }
324
+
325
+ const builderResult = this._resources.getOrAdd(id, () =>
326
+ ResourceBuilder.create({
327
+ id,
328
+ resourceTypes: this.resourceTypes,
329
+ conditionSets: this._conditionSets,
330
+ decisions: this._decisions
331
+ })
332
+ );
333
+ /* c8 ignore next 6 - defense in depth against internal error */
334
+ if (builderResult.isFailure()) {
335
+ return failWithDetail(
336
+ `${id}: unable to get or add resource\n${builderResult.message}`,
337
+ builderResult.detail
338
+ );
339
+ }
340
+ return builderResult.value.addLooseCandidate(decl).onSuccess((c, d) => {
341
+ this._builtResources.delete(id);
342
+ this._built = false;
343
+ this._numCandidates = undefined;
344
+ this._cachedResourceTree = undefined;
345
+ return succeedWithDetail(c, d);
346
+ });
347
+ }
348
+
349
+ public addResource(
350
+ decl: ResourceJson.Json.ILooseResourceDecl
351
+ ): DetailedResult<ResourceBuilder, ResourceBuilderResultDetail> {
352
+ const { value: id, message } = Validate.toResourceId(decl.id);
353
+ if (message !== undefined) {
354
+ return failWithDetail(`${id}: invalid id - ${message}`, 'failure');
355
+ }
356
+
357
+ const {
358
+ value: builder,
359
+ message: getOrAddMessage,
360
+ detail
361
+ } = this._resources.getOrAdd(id, () =>
362
+ ResourceBuilder.create({
363
+ id,
364
+ typeName: decl.resourceTypeName,
365
+ resourceTypes: this.resourceTypes,
366
+ conditionSets: this._conditionSets,
367
+ decisions: this._decisions
368
+ })
369
+ );
370
+ /* c8 ignore next 3 - defense in depth against internal error */
371
+ if (getOrAddMessage !== undefined) {
372
+ return failWithDetail(`${id}: unable to get or add resource\n${getOrAddMessage}`, detail);
373
+ }
374
+
375
+ if (detail === 'exists') {
376
+ const { message } = builder.setResourceType(decl.resourceTypeName);
377
+ if (message !== undefined) {
378
+ return failWithDetail(`${id}: unable to set resource type\n${message}`, 'type-mismatch');
379
+ }
380
+ }
381
+
382
+ const candidates = decl.candidates ?? [];
383
+ return mapResults(candidates.map((c) => builder.addChildCandidate(c)))
384
+ .onSuccess(() => {
385
+ return succeed(builder);
386
+ })
387
+ .withDetail('failure', detail);
388
+ }
389
+
390
+ /**
391
+ * Adds a condition to the manager.
392
+ * @param decl - The condition declaration to add.
393
+ * @returns `Success` with the condition if successful, or `Failure` with an error message if not.
394
+ * @public
395
+ */
396
+ public addCondition(decl: ResourceJson.Json.ILooseConditionDecl): Result<Condition> {
397
+ return ConditionsConvert.validatedConditionDecl
398
+ .convert(decl, { qualifiers: this.qualifiers })
399
+ .onSuccess((validated) => {
400
+ return Condition.getKeyForDecl(validated).onSuccess((key) => {
401
+ return this._conditions.validating.getOrAdd(key, () => Condition.create(validated));
402
+ });
403
+ });
404
+ }
405
+
406
+ /**
407
+ * Adds a condition set to the manager.
408
+ * @param decl - The condition set declaration to add.
409
+ * @returns `Success` with the condition set if successful, or `Failure` with an error message if not.
410
+ * @public
411
+ */
412
+ public addConditionSet(conditions: ResourceJson.Normalized.ConditionSetDecl): Result<ConditionSet> {
413
+ const decl: IConditionSetDecl = { conditions: [...conditions] };
414
+ return ConditionsConvert.validatedConditionSetDecl
415
+ .convert(decl, { conditions: this._conditions })
416
+ .onSuccess((validated) => {
417
+ return ConditionSet.getKeyForDecl(validated).onSuccess((key) => {
418
+ return this._conditionSets.validating.getOrAdd(key, () => ConditionSet.create(validated));
419
+ });
420
+ });
421
+ }
422
+
423
+ /**
424
+ * Gets a read-only array of all {@link Resources.ResourceBuilder | resource builders} present in the manager.
425
+ * @returns `Success` with the {@link Resources.ResourceBuilder | resource builder} if successful,
426
+ * or `Failure` with an error message if not.
427
+ */
428
+ public getAllResources(): ReadonlyArray<ResourceBuilder> {
429
+ return Array.from(this._resources.values()).sort((a, b) => a.id.localeCompare(b.id));
430
+ }
431
+
432
+ /**
433
+ * Gets a read-only array of all {@link Resources.ResourceCandidate | resource candidates} present in the manager.
434
+ */
435
+ public getAllCandidates(): ReadonlyArray<ResourceCandidate> {
436
+ return this.getAllResources().flatMap((r) => r.candidates);
437
+ }
438
+
439
+ /**
440
+ * Gets an individual {@link Resources.Resource | built resource} from the manager.
441
+ * @param id - The {@link ResourceId | id} of the resource to get.
442
+ * @returns `Success` with the resource if successful, or `Failure` with an error message if not.
443
+ * @public
444
+ */
445
+ public getBuiltResource(id: string): Result<Resource> {
446
+ return this._resources.validating
447
+ .get(id)
448
+ .onSuccess((builder) => this._builtResources.validating.getOrAdd(id, () => builder.build()));
449
+ }
450
+
451
+ /**
452
+ * Validates a context declaration against the qualifiers managed by this resource manager.
453
+ * @param context - The context declaration to validate
454
+ * @returns Success with the validated context if successful, Failure otherwise
455
+ * @public
456
+ */
457
+ /* c8 ignore next 5 - functional code path tested but coverage intermittently missed */
458
+ public validateContext(context: Context.IContextDecl): Result<Context.IValidatedContextDecl> {
459
+ return Context.Convert.validatedContextDecl.convert(context, {
460
+ qualifiers: this.qualifiers
461
+ });
462
+ }
463
+
464
+ /**
465
+ * Gets a read-only array of all {@link Resources.Resource | built resources} in the manager.
466
+ * @returns `Success` with an array of resources if successful, or `Failure` with an error message if not.
467
+ * @public
468
+ */
469
+ public getAllBuiltResources(): Result<ReadonlyArray<Resource>> {
470
+ return this.build().onSuccess((manager) =>
471
+ succeed(Array.from(manager._builtResources.values()).sort((a, b) => a.id.localeCompare(b.id)))
472
+ );
473
+ }
474
+
475
+ /**
476
+ * Builds and returns a hierarchical tree representation of all resources managed by this builder.
477
+ * Resources are organized based on their dot-separated resource IDs (e.g., "app.messages.welcome"
478
+ * becomes a tree with "app" as root, "messages" as branch, and "welcome" as leaf).
479
+ *
480
+ * String-based validation is available through the `children.validating` property,
481
+ * allowing callers to use `tree.children.validating.getById(stringId)` for validated access.
482
+ *
483
+ * Uses lazy initialization with caching for performance.
484
+ * @returns Result containing the resource tree root, or failure if tree construction fails
485
+ * @public
486
+ */
487
+ public getBuiltResourceTree(): Result<ResourceTree.IReadOnlyResourceTreeRoot<Resource>> {
488
+ // Ensure resources are built first
489
+ return this.build().onSuccess((manager) => {
490
+ if (manager._cachedResourceTree) {
491
+ return succeed(manager._cachedResourceTree);
492
+ }
493
+
494
+ // Convert all built resources to [ResourceId, Resource] pairs
495
+ const resources: [ResourceId, Resource][] = [];
496
+ for (const [id, resource] of manager._builtResources.entries()) {
497
+ resources.push([id, resource]);
498
+ }
499
+
500
+ // Create the resource tree with lazy initialization
501
+ return ResourceTree.ReadOnlyResourceTreeRoot.create(resources).onSuccess((tree) => {
502
+ manager._cachedResourceTree = tree;
503
+ return succeed(tree);
504
+ });
505
+ });
506
+ }
507
+
508
+ /**
509
+ * Gets a read-only array of all {@link Resources.Resource | built resources} in the manager.
510
+ * @returns `Success` with an array of resources if successful, or `Failure` with an error message if not.
511
+ * @public
512
+ */
513
+ public getAllBuiltCandidates(): Result<ReadonlyArray<ResourceCandidate>> {
514
+ return this.getAllBuiltResources().onSuccess((built) => succeed(built.flatMap((r) => r.candidates)));
515
+ }
516
+
517
+ /**
518
+ * Internal helper method that performs the actual building of resources.
519
+ * @returns `Success` with the built resources if all resources were built successfully, `Failure` otherwise.
520
+ * @internal
521
+ */
522
+ public _performBuild(): Result<Collections.IReadOnlyValidatingResultMap<ResourceId, Resource>> {
523
+ if (this._built) {
524
+ return succeed(this._builtResources);
525
+ }
526
+
527
+ const errors: MessageAggregator = new MessageAggregator();
528
+ this._resources.forEach((r, id) => {
529
+ this._builtResources.getOrAdd(id, () => r.build()).aggregateError(errors);
530
+ });
531
+ /* c8 ignore next 3 - defense in depth against internal error */
532
+ if (errors.hasMessages) {
533
+ return fail(`build failed: ${errors.toString()}`);
534
+ }
535
+ this._built = true;
536
+ return succeed(this._builtResources);
537
+ }
538
+
539
+ /**
540
+ * Builds the {@link Resources.Resource | resources} from the collected {@link Resources.ResourceCandidate | candidates}.
541
+ * @returns `Success` with the {@link Resources.ResourceManagerBuilder | ResourceManagerBuilder} object if successful,
542
+ * or `Failure` with an error message if not.
543
+ * @public
544
+ */
545
+ public build(): Result<this> {
546
+ return this._performBuild().onSuccess(() => succeed(this));
547
+ }
548
+
549
+ /**
550
+ * Gets a read-only array of all {@link Resources.ResourceCandidate | resource candidates} that can match the supplied context.
551
+ * @param context - The {@link Context.IValidatedContextDecl | context} to match against.
552
+ * @param options - {@link Context.IContextMatchOptions | options} for the context match.
553
+ * @returns A read-only array of {@link Resources.ResourceCandidate | candidates} that can match the context.
554
+ * @public
555
+ */
556
+ public getCandidatesForContext(
557
+ context: Context.IValidatedContextDecl,
558
+ options?: Context.IContextMatchOptions
559
+ ): ReadonlyArray<ResourceCandidate> {
560
+ return this.getAllCandidates().filter((candidate) => candidate.canMatchPartialContext(context, options));
561
+ }
562
+
563
+ /**
564
+ * Gets a read-only array of all {@link Resources.ResourceBuilder | resource builders} that have at least one candidate
565
+ * that can match the supplied context.
566
+ * @param context - The {@link Context.IValidatedContextDecl | context} to match against.
567
+ * @param options - {@link Context.IContextMatchOptions | options} for the context match.
568
+ * @returns A read-only array of {@link Resources.ResourceBuilder | resource builders} with matching candidates.
569
+ * @public
570
+ */
571
+ public getResourcesForContext(
572
+ context: Context.IValidatedContextDecl,
573
+ options?: Context.IContextMatchOptions
574
+ ): ReadonlyArray<ResourceBuilder> {
575
+ return this.getAllResources().filter(
576
+ (resource) => resource.getCandidatesForContext(context, options).length > 0
577
+ );
578
+ }
579
+
580
+ /**
581
+ * Gets a read-only array of all {@link Resources.ResourceCandidate | built resource candidates} that can match the supplied context.
582
+ * @param context - The {@link Context.IValidatedContextDecl | context} to match against.
583
+ * @param options - {@link Context.IContextMatchOptions | options} for the context match.
584
+ * @returns `Success` with an array of {@link Resources.ResourceCandidate | candidates} if successful, or `Failure` with an error message if not.
585
+ * @public
586
+ */
587
+ public getBuiltCandidatesForContext(
588
+ context: Context.IValidatedContextDecl,
589
+ options?: Context.IContextMatchOptions
590
+ ): Result<ReadonlyArray<ResourceCandidate>> {
591
+ return this.getAllBuiltCandidates().onSuccess((candidates) =>
592
+ succeed(candidates.filter((candidate) => candidate.canMatchPartialContext(context, options)))
593
+ );
594
+ }
595
+
596
+ /**
597
+ * Gets a read-only array of all {@link Resources.Resource | built resources} that have at least one candidate
598
+ * that can match the supplied context.
599
+ * @param context - The {@link Context.IValidatedContextDecl | context} to match against.
600
+ * @param options - {@link Context.IContextMatchOptions | options} for the context match.
601
+ * @returns `Success` with an array of {@link Resources.Resource | resources} if successful, or `Failure` with an error message if not.
602
+ * @public
603
+ */
604
+ public getBuiltResourcesForContext(
605
+ context: Context.IValidatedContextDecl,
606
+ options?: Context.IContextMatchOptions
607
+ ): Result<ReadonlyArray<Resource>> {
608
+ return this.getAllBuiltResources().onSuccess((resources) =>
609
+ succeed(resources.filter((resource) => resource.getCandidatesForContext(context, options).length > 0))
610
+ );
611
+ }
612
+
613
+ /**
614
+ * Gets a compiled resource collection from the current state of the resource manager builder.
615
+ * This method generates an optimized, index-based representation of all resources, conditions,
616
+ * and decisions that can be used for serialization or efficient runtime processing.
617
+ * @param options - Optional compilation options controlling the output format.
618
+ * @returns Success with the compiled resource collection if successful, Failure otherwise.
619
+ * @public
620
+ */
621
+ public getCompiledResourceCollection(
622
+ options?: ResourceJson.Compiled.ICompiledResourceOptions
623
+ ): Result<ResourceJson.Compiled.ICompiledResourceCollection> {
624
+ // Build resources first to ensure all data is available
625
+ const buildResult = this._performBuild();
626
+ if (buildResult.isFailure()) {
627
+ return fail(`Failed to build resources: ${buildResult.message}`);
628
+ }
629
+
630
+ // Generate compiled data from internal collections using the new toCompiled methods
631
+ // Note: All objects have a defined index property due to the collector pattern - indices are assigned during collection building
632
+ const compiledData = {
633
+ qualifierTypes: Array.from(this.qualifiers.qualifierTypes.values()).map((qt) => ({
634
+ name: qt.name
635
+ })),
636
+ qualifiers: Array.from(this.qualifiers.values()).map((q) => ({
637
+ name: q.name,
638
+ type: q.type.index!,
639
+ defaultPriority: q.defaultPriority
640
+ })),
641
+ resourceTypes: Array.from(this.resourceTypes.values()).map((rt) => ({
642
+ name: rt.key
643
+ })),
644
+ conditions: Array.from(this._conditions.values()).map((c) => c.toCompiled(options)),
645
+ conditionSets: Array.from(this._conditionSets.values()).map((cs) => cs.toCompiled(options)),
646
+ decisions: Array.from(this._decisions.values()).map((d) => d.toCompiled(options)),
647
+ resources: Array.from(this._builtResources.values()).map((r) => r.toCompiled(options))
648
+ };
649
+
650
+ // Apply validation through the converter
651
+ return ResourceJson.Compiled.Convert.compiledResourceCollection.convert(compiledData);
652
+ }
653
+
654
+ /**
655
+ * Gets a resource collection declaration containing all built resources in a flat array structure.
656
+ * This method returns all built resources as an {@link ResourceJson.Normalized.IResourceCollectionDecl | IResourceCollectionDecl}
657
+ * that can be used for serialization, export, or re-import. Resources are sorted by ID for consistent ordering.
658
+ * @param options - Optional {@link Resources.IResourceDeclarationOptions | declaration options} controlling the output format.
659
+ * If `options.normalized` is `true`, applies hash-based normalization for additional consistency guarantees.
660
+ * @returns Success with the resource collection declaration if successful, Failure otherwise.
661
+ * @public
662
+ */
663
+ public getResourceCollectionDecl(
664
+ options?: IResourceDeclarationOptions
665
+ ): Result<ResourceJson.Normalized.IResourceCollectionDecl> {
666
+ return this._performBuild().onSuccess(() => {
667
+ // Get all built resources and convert to loose resource declarations
668
+ const resources = Array.from(this._builtResources.values()).map((resource) =>
669
+ resource.toLooseResourceDecl(options)
670
+ );
671
+
672
+ // Sort resources by ID for consistent ordering
673
+ resources.sort((a, b) => a.id.localeCompare(b.id));
674
+
675
+ // Create the collection declaration structure
676
+ const collectionData = {
677
+ resources
678
+ };
679
+
680
+ // Convert and validate using the normalized converter
681
+ return ResourceJson.Convert.resourceCollectionDecl
682
+ .convert(collectionData)
683
+ .onSuccess((compiledCollection) => {
684
+ // Apply hash-based normalization only if requested
685
+ if (options?.normalized === true) {
686
+ const normalizer = new Hash.Crc32Normalizer();
687
+ return normalizer
688
+ .normalize(compiledCollection)
689
+ .withErrorFormat((e) => `Failed to normalize resource collection: ${e}`);
690
+ }
691
+ return succeed(compiledCollection);
692
+ });
693
+ });
694
+ }
695
+
696
+ /**
697
+ * Creates a clone of this ResourceManagerBuilder with optional configuration overrides.
698
+ * This method creates a new ResourceManagerBuilder that can optionally use different
699
+ * qualifiers and/or resource types than the original. It can also be filtered to include
700
+ * only candidates that match the provided context and apply candidate edits.
701
+ *
702
+ * @param options - Options for the cloning operation:
703
+ * - `qualifiers`: Optional qualifier collector to use instead of the original
704
+ * - `resourceTypes`: Optional resource type collector to use instead of the original
705
+ * - `filterForContext`: Optional context filter for candidates
706
+ * - `candidates`: Optional candidate edits to apply during cloning
707
+ * @returns A Result containing the new ResourceManagerBuilder with the specified configuration.
708
+ * @public
709
+ */
710
+ /* c8 ignore next 21 - functional code path tested but coverage intermittently missed */
711
+ public clone(options?: IResourceManagerCloneOptions): Result<ResourceManagerBuilder> {
712
+ return this.getResourceCollectionDecl(options).onSuccess((collection) => {
713
+ return ResourceManagerBuilder.create({
714
+ qualifiers: options?.qualifiers ?? this.qualifiers,
715
+ resourceTypes: options?.resourceTypes ?? this.resourceTypes
716
+ }).onSuccess((newManager) => {
717
+ // Check if we have candidates to apply as edits
718
+ const editCandidates = options?.candidates || [];
719
+ const candidatesByResourceResult =
720
+ editCandidates.length > 0
721
+ ? ResourceManagerBuilder._createCandidatesByResourceMap(editCandidates)
722
+ : succeed(new Map());
723
+
724
+ return candidatesByResourceResult.onSuccess((candidatesByResource) => {
725
+ // Track which resource IDs have been processed from the original collection
726
+ const processedResourceIds = new Set<ResourceId>();
727
+
728
+ // Add each resource from the filtered collection to the new manager
729
+ if (collection.resources) {
730
+ for (const resourceDecl of collection.resources) {
731
+ processedResourceIds.add(resourceDecl.id as ResourceId);
732
+
733
+ // Apply edits if there are candidates for this resource
734
+ const editedDeclResult = ResourceManagerBuilder._applyEditsToResourceDeclaration(
735
+ resourceDecl,
736
+ candidatesByResource,
737
+ this._conditions
738
+ );
739
+
740
+ if (editedDeclResult.isFailure()) {
741
+ return fail(`${resourceDecl.id}: Failed to apply edits: ${editedDeclResult.message}`);
742
+ }
743
+
744
+ const addResult = newManager.addResource(editedDeclResult.value);
745
+ /* c8 ignore next 5 - edge case (nearly?) impossible to reproduce */
746
+ if (addResult.isFailure()) {
747
+ return fail(
748
+ `${resourceDecl.id}: Failed to add resource to cloned manager: ${addResult.message}`
749
+ );
750
+ }
751
+ }
752
+ }
753
+
754
+ // Handle any remaining candidates that target new resources not in the original collection
755
+ const errors = new MessageAggregator();
756
+ for (const [resourceId, candidates] of candidatesByResource) {
757
+ if (!processedResourceIds.has(resourceId)) {
758
+ // Create a new resource declaration for candidates targeting a new resource ID
759
+ ResourceManagerBuilder._createResourceDeclFromCandidates(
760
+ resourceId,
761
+ candidates,
762
+ this._conditions
763
+ )
764
+ .withErrorFormat((e) => `${resourceId}: Failed to create new resource from candidates: ${e}`)
765
+ .onSuccess((newResourceDecl) => {
766
+ return newManager
767
+ .addResource(newResourceDecl)
768
+ .withErrorFormat(
769
+ (e) => `${resourceId}: Failed to add new resource to cloned manager: ${e}`
770
+ );
771
+ })
772
+ .aggregateError(errors);
773
+ }
774
+ }
775
+
776
+ return errors.returnOrReport(succeed(newManager));
777
+ });
778
+ });
779
+ });
780
+ }
781
+
782
+ /**
783
+ * Creates a resource ID keyed map from an array of loose resource candidate declarations.
784
+ * This enables efficient detection of edit collisions by grouping candidates by their target resource.
785
+ * @param candidates - Array of loose resource candidate declarations to organize
786
+ * @returns A Result containing a Map where keys are validated ResourceIds and values are arrays of candidates for that resource
787
+ * @internal
788
+ */
789
+ private static _createCandidatesByResourceMap(
790
+ candidates: ReadonlyArray<ResourceJson.Json.ILooseResourceCandidateDecl>
791
+ ): Result<Map<ResourceId, ResourceJson.Json.ILooseResourceCandidateDecl[]>> {
792
+ const candidatesByResource = new Map<ResourceId, ResourceJson.Json.ILooseResourceCandidateDecl[]>();
793
+
794
+ for (const candidate of candidates) {
795
+ const { value: resourceId, message } = Validate.toResourceId(candidate.id);
796
+ if (message !== undefined) {
797
+ return fail(`Invalid resource ID "${candidate.id}": ${message}`);
798
+ }
799
+
800
+ const existingCandidates = candidatesByResource.get(resourceId);
801
+ if (existingCandidates) {
802
+ existingCandidates.push(candidate);
803
+ } else {
804
+ candidatesByResource.set(resourceId, [candidate]);
805
+ }
806
+ }
807
+
808
+ return succeed(candidatesByResource);
809
+ }
810
+
811
+ /**
812
+ * Generates a proper ConditionSet token for collision detection using the existing ConditionSet.getKeyForDecl method.
813
+ * @param conditionSet - The condition set to generate a token for
814
+ * @param conditionCollector - The condition collector needed for validation context
815
+ * @returns A Result containing the ConditionSet token if successful, or failure if validation fails
816
+ * @internal
817
+ */
818
+
819
+ /**
820
+ * Applies candidate edits to a resource declaration, handling collisions using condition set tokens.
821
+ * If there's no collision, adds the candidate. If there's a collision, replaces the original candidate with the edit.
822
+ * @param resourceDecl - The original resource declaration to potentially modify
823
+ * @param candidatesByResource - Map of resource IDs to arrays of candidate edits
824
+ * @param conditionCollector - The condition collector needed for generating condition tokens
825
+ * @returns A Result containing the resource declaration to use (original or modified)
826
+ * @internal
827
+ */
828
+ private static _applyEditsToResourceDeclaration(
829
+ resourceDecl: ResourceJson.Json.ILooseResourceDecl,
830
+ candidatesByResource: Map<ResourceId, ResourceJson.Json.ILooseResourceCandidateDecl[]>,
831
+ conditionCollector: ConditionCollector
832
+ ): Result<ResourceJson.Json.ILooseResourceDecl> {
833
+ const { value: resourceId, message } = Validate.toResourceId(resourceDecl.id);
834
+ /* c8 ignore next 3 - defensive validation: resource IDs are validated when added to builder, but this protects against corrupted data */
835
+ if (message !== undefined) {
836
+ return fail(`Invalid resource ID "${resourceDecl.id}": ${message}`);
837
+ }
838
+
839
+ const editCandidates = candidatesByResource.get(resourceId);
840
+ if (!editCandidates || editCandidates.length === 0) {
841
+ return succeed(resourceDecl);
842
+ }
843
+
844
+ // Use Map approach: apply original candidates first, then replace with edits on collision
845
+ const candidatesByConditionKey = new Map<string, ResourceJson.Json.IChildResourceCandidateDecl>();
846
+
847
+ /* c8 ignore next 1 - ?? is defense in depth */
848
+ const declCandidates = resourceDecl.candidates ?? [];
849
+
850
+ // First, add all original candidates keyed by their condition set token
851
+ for (const candidate of declCandidates) {
852
+ const conditionTokenResult = ConditionSet.getKeyFromLooseDecl(candidate.conditions, conditionCollector);
853
+ /* c8 ignore next 5 - edge case or internal error (nearly?) impossible to reproduce */
854
+ if (conditionTokenResult.isFailure()) {
855
+ return fail(
856
+ `Failed to generate condition token for original candidate: ${conditionTokenResult.message}`
857
+ );
858
+ }
859
+ candidatesByConditionKey.set(conditionTokenResult.value, candidate);
860
+ }
861
+
862
+ // Then, apply edits (this replaces any colliding original candidates)
863
+ // Convert edit candidates (which have ids) to child candidates (without ids) for merging
864
+ for (const editCandidate of editCandidates) {
865
+ const conditionTokenResult = ConditionSet.getKeyFromLooseDecl(
866
+ editCandidate.conditions,
867
+ conditionCollector
868
+ );
869
+ if (conditionTokenResult.isFailure()) {
870
+ return fail(`Failed to generate condition token for edit candidate: ${conditionTokenResult.message}`);
871
+ }
872
+ let editedJson = editCandidate.json;
873
+ const previousJson = candidatesByConditionKey.get(conditionTokenResult.value)?.json;
874
+ if (previousJson && previousJson !== editedJson) {
875
+ editedJson = JsonEditor.create({
876
+ merge: {
877
+ arrayMergeBehavior: 'replace',
878
+ nullAsDelete: false
879
+ }
880
+ })
881
+ .onSuccess((editor) => {
882
+ return editor.mergeObjectsInPlace({}, [previousJson, editedJson]);
883
+ })
884
+ .orThrow();
885
+ }
886
+
887
+ const childCandidate: ResourceJson.Json.IChildResourceCandidateDecl = {
888
+ json: editedJson,
889
+ conditions: editCandidate.conditions,
890
+ isPartial: editCandidate.isPartial,
891
+ mergeMethod: editCandidate.mergeMethod
892
+ };
893
+ candidatesByConditionKey.set(conditionTokenResult.value, childCandidate);
894
+ }
895
+
896
+ // Extract the final merged candidate list
897
+ const mergedCandidates = Array.from(candidatesByConditionKey.values());
898
+
899
+ const modifiedDecl: ResourceJson.Json.ILooseResourceDecl = {
900
+ ...resourceDecl,
901
+ candidates: mergedCandidates
902
+ };
903
+
904
+ return succeed(modifiedDecl);
905
+ }
906
+
907
+ /**
908
+ * Creates a new resource declaration from an array of candidate declarations.
909
+ * This is used when cloning to create new resources that don't exist in the original manager.
910
+ * @param resourceId - The validated resource ID for the new resource
911
+ * @param candidates - Array of loose candidate declarations for the new resource
912
+ * @param conditionCollector - The condition collector for validation context
913
+ * @returns A Result containing the new resource declaration if successful, or failure if validation fails
914
+ * @internal
915
+ */
916
+ private static _createResourceDeclFromCandidates(
917
+ resourceId: ResourceId,
918
+ candidates: ResourceJson.Json.ILooseResourceCandidateDecl[],
919
+ conditionCollector: ConditionCollector
920
+ ): Result<ResourceJson.Json.ILooseResourceDecl> {
921
+ // Convert candidate declarations to child candidate declarations
922
+ const childCandidates: ResourceJson.Json.IChildResourceCandidateDecl[] = [];
923
+
924
+ // Ensure we have candidates
925
+ /* c8 ignore next 3 - defense in depth against internal error */
926
+ if (candidates.length === 0) {
927
+ return fail('Cannot create resource declaration from empty candidates array');
928
+ }
929
+
930
+ // Extract resourceTypeName from the first candidate (all candidates for the same resource should have the same type)
931
+ const resourceTypeName = candidates[0].resourceTypeName;
932
+ /* c8 ignore next 3 - defense in depth */
933
+ if (!resourceTypeName) {
934
+ return fail('resourceTypeName is required for new resource candidates');
935
+ }
936
+
937
+ for (const candidate of candidates) {
938
+ const childCandidate: ResourceJson.Json.IChildResourceCandidateDecl = {
939
+ json: candidate.json,
940
+ conditions: candidate.conditions,
941
+ isPartial: candidate.isPartial,
942
+ mergeMethod: candidate.mergeMethod
943
+ };
944
+ childCandidates.push(childCandidate);
945
+ }
946
+
947
+ // Create the new resource declaration
948
+ const newResourceDecl: ResourceJson.Json.ILooseResourceDecl = {
949
+ id: resourceId,
950
+ candidates: childCandidates,
951
+ resourceTypeName
952
+ };
953
+
954
+ return succeed(newResourceDecl);
955
+ }
956
+
957
+ /**
958
+ * Reconstructs conditions from a compiled collection and adds them to the builder.
959
+ * @param builder - The builder to add conditions to.
960
+ * @param compiledCollection - The compiled collection containing conditions.
961
+ * @returns `Success` if all conditions were added successfully, `Failure` otherwise.
962
+ * @internal
963
+ */
964
+ private static _reconstructConditions(
965
+ builder: ResourceManagerBuilder,
966
+ compiledCollection: ResourceJson.Compiled.ICompiledResourceCollection
967
+ ): Result<boolean> {
968
+ const errors = new MessageAggregator();
969
+
970
+ for (const compiledCondition of compiledCollection.conditions) {
971
+ // Get the qualifier by index
972
+ const qualifierResult = builder.qualifiers.getAt(compiledCondition.qualifierIndex);
973
+ /* c8 ignore next 4 - edge case or internal error (nearly?) impossible to reproduce */
974
+ if (qualifierResult.isFailure()) {
975
+ qualifierResult.aggregateError(errors);
976
+ continue;
977
+ }
978
+
979
+ // Create condition declaration from compiled condition
980
+ const conditionDecl: ResourceJson.Json.ILooseConditionDecl = {
981
+ qualifierName: qualifierResult.value.name,
982
+ operator: compiledCondition.operator,
983
+ value: compiledCondition.value,
984
+ priority: compiledCondition.priority,
985
+ scoreAsDefault: compiledCondition.scoreAsDefault
986
+ };
987
+
988
+ // Add condition to builder (it will get the next sequential index)
989
+ builder.addCondition(conditionDecl).aggregateError(errors);
990
+ }
991
+
992
+ return errors.returnOrReport(succeed(true));
993
+ }
994
+
995
+ /**
996
+ * Reconstructs condition sets from a compiled collection and adds them to the builder.
997
+ * @param builder - The builder to add condition sets to.
998
+ * @param compiledCollection - The compiled collection containing condition sets.
999
+ * @returns `Success` if all condition sets were added successfully, `Failure` otherwise.
1000
+ * @internal
1001
+ */
1002
+ private static _reconstructConditionSets(
1003
+ builder: ResourceManagerBuilder,
1004
+ compiledCollection: ResourceJson.Compiled.ICompiledResourceCollection
1005
+ ): Result<boolean> {
1006
+ const errors = new MessageAggregator();
1007
+
1008
+ for (const compiledConditionSet of compiledCollection.conditionSets) {
1009
+ // Get conditions by their indices
1010
+ const conditionResults = compiledConditionSet.conditions.map((idx) => builder._conditions.getAt(idx));
1011
+
1012
+ // Check for any failures
1013
+ const failedIndex = conditionResults.findIndex((r) => r.isFailure());
1014
+ /* c8 ignore next 4 - edge case or internal error (nearly?) impossible to reproduce */
1015
+ if (failedIndex >= 0) {
1016
+ conditionResults[failedIndex].aggregateError(errors);
1017
+ continue;
1018
+ }
1019
+
1020
+ // Create condition set from conditions (not declarations)
1021
+ const conditions = conditionResults.map((r) => r.orThrow());
1022
+ // Convert conditions to declarations for addConditionSet
1023
+ const conditionDecls = conditions.map((c) => c.toLooseConditionDecl());
1024
+ builder.addConditionSet(conditionDecls).aggregateError(errors);
1025
+ }
1026
+
1027
+ return errors.returnOrReport(succeed(true));
1028
+ }
1029
+
1030
+ /**
1031
+ * Reconstructs decisions from a compiled collection and adds them to the builder.
1032
+ * @param builder - The builder to add decisions to.
1033
+ * @param compiledCollection - The compiled collection containing decisions.
1034
+ * @returns `Success` if all decisions were added successfully, `Failure` otherwise.
1035
+ * @internal
1036
+ */
1037
+ private static _reconstructDecisions(
1038
+ builder: ResourceManagerBuilder,
1039
+ compiledCollection: ResourceJson.Compiled.ICompiledResourceCollection
1040
+ ): Result<boolean> {
1041
+ const errors = new MessageAggregator();
1042
+
1043
+ for (const compiledDecision of compiledCollection.decisions) {
1044
+ // Get condition sets by their indices
1045
+ const conditionSetResults = compiledDecision.conditionSets.map((idx) =>
1046
+ builder._conditionSets.getAt(idx)
1047
+ );
1048
+
1049
+ // Check for any failures
1050
+ const failedIndex = conditionSetResults.findIndex((r) => r.isFailure());
1051
+ if (failedIndex >= 0) {
1052
+ conditionSetResults[failedIndex].aggregateError(errors);
1053
+ continue;
1054
+ }
1055
+
1056
+ // Get condition sets from successful results
1057
+ const conditionSets = conditionSetResults.map((r) => r.orThrow());
1058
+ // Create AbstractDecision from condition sets and add to collector
1059
+ AbstractDecision.createAbstractDecision({ conditionSets })
1060
+ .onSuccess((decision) => builder._decisions.getOrAdd(decision))
1061
+ .aggregateError(errors);
1062
+ }
1063
+
1064
+ return errors.returnOrReport(succeed(true));
1065
+ }
1066
+
1067
+ /**
1068
+ * Reconstructs resources and their candidates from a compiled collection and adds them to the builder.
1069
+ * @param builder - The builder to add resources to.
1070
+ * @param compiledCollection - The compiled collection containing resources.
1071
+ * @returns `Success` if all resources were added successfully, `Failure` otherwise.
1072
+ * @internal
1073
+ */
1074
+ private static _reconstructResources(
1075
+ builder: ResourceManagerBuilder,
1076
+ compiledCollection: ResourceJson.Compiled.ICompiledResourceCollection
1077
+ ): Result<boolean> {
1078
+ const errors = new MessageAggregator();
1079
+
1080
+ for (const compiledResource of compiledCollection.resources) {
1081
+ // Get the resource type by index
1082
+ const resourceTypeResult = builder.resourceTypes.getAt(compiledResource.type);
1083
+ /* c8 ignore next 4 - edge case or internal error (nearly?) impossible to reproduce */
1084
+ if (resourceTypeResult.isFailure()) {
1085
+ resourceTypeResult.aggregateError(errors);
1086
+ continue;
1087
+ }
1088
+
1089
+ // Get the decision by index
1090
+ const decisionResult = builder._decisions.getAt(compiledResource.decision);
1091
+ /* c8 ignore next 4 - edge case or internal error (nearly?) impossible to reproduce */
1092
+ if (decisionResult.isFailure()) {
1093
+ decisionResult.aggregateError(errors);
1094
+ continue;
1095
+ }
1096
+
1097
+ const decision = decisionResult.value;
1098
+ const resourceType = resourceTypeResult.value;
1099
+
1100
+ // Create candidates from the decision's condition sets
1101
+ ResourceManagerBuilder._createCandidatesFromDecision(
1102
+ compiledResource,
1103
+ decision,
1104
+ resourceType,
1105
+ builder
1106
+ ).aggregateError(errors);
1107
+ }
1108
+
1109
+ return errors.returnOrReport(succeed(true));
1110
+ }
1111
+
1112
+ /**
1113
+ * Helper method to create candidates from a decision's condition sets.
1114
+ * @param compiledResource - The compiled resource containing candidates.
1115
+ * @param decision - The decision containing condition sets.
1116
+ * @param resourceType - The resource type for the candidates.
1117
+ * @param builder - The builder to add candidates to.
1118
+ * @returns `Success` if all candidates were added successfully, `Failure` otherwise.
1119
+ * @internal
1120
+ */
1121
+ private static _createCandidatesFromDecision(
1122
+ compiledResource: ResourceJson.Compiled.ICompiledResource,
1123
+ decision: AbstractDecision,
1124
+ resourceType: ResourceType,
1125
+ builder: ResourceManagerBuilder
1126
+ ): Result<boolean> {
1127
+ const errors = new MessageAggregator();
1128
+
1129
+ // Match each candidate to its corresponding condition set
1130
+ for (let i = 0; i < compiledResource.candidates.length; i++) {
1131
+ const candidate = compiledResource.candidates[i];
1132
+
1133
+ // Build conditions from the corresponding condition set (if available)
1134
+ let conditions: Record<string, string> | undefined;
1135
+ if (i < decision.candidates.length) {
1136
+ const decisionCandidate = decision.candidates[i];
1137
+ conditions = {};
1138
+ for (const condition of decisionCandidate.conditionSet.conditions) {
1139
+ conditions[condition.qualifier.name] = condition.value;
1140
+ }
1141
+ /* c8 ignore next 3 - defense in depth */
1142
+ if (Object.keys(conditions).length === 0) {
1143
+ conditions = undefined;
1144
+ }
1145
+ }
1146
+
1147
+ // Convert json value to JsonObject, handling undefined case
1148
+ /* c8 ignore next 1 - defense in depth */
1149
+ const rawJson = candidate.json ?? {};
1150
+ JsonConverters.jsonObject
1151
+ .convert(rawJson)
1152
+ .onSuccess((json) => {
1153
+ const candidateDecl: ResourceJson.Json.ILooseResourceCandidateDecl = {
1154
+ id: compiledResource.id,
1155
+ json,
1156
+ conditions,
1157
+ isPartial: candidate.isPartial,
1158
+ mergeMethod: candidate.mergeMethod,
1159
+ resourceTypeName: resourceType.key
1160
+ };
1161
+
1162
+ return builder.addLooseCandidate(candidateDecl).aggregateError(errors);
1163
+ })
1164
+ .aggregateError(errors);
1165
+ }
1166
+
1167
+ return errors.returnOrReport(succeed(true));
1168
+ }
1169
+ }