@fgv/ts-res 4.5.0-3 → 5.0.0-2

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 (405) hide show
  1. package/CHANGELOG.json +26 -0
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +186 -0
  4. package/EXAMPLE_INIT_PARAMS.md +88 -0
  5. package/PROGRESS_SUMMARY.md +48 -0
  6. package/README.md +535 -14
  7. package/dist/ts-res.d.ts +4241 -318
  8. package/dist/tsdoc-metadata.json +1 -1
  9. package/lib/index.d.ts +4 -1
  10. package/lib/index.d.ts.map +1 -1
  11. package/lib/index.js +7 -1
  12. package/lib/index.js.map +1 -1
  13. package/lib/packlets/common/conditions.d.ts +30 -0
  14. package/lib/packlets/common/conditions.d.ts.map +1 -1
  15. package/lib/packlets/common/conditions.js.map +1 -1
  16. package/lib/packlets/common/convert.d.ts +22 -2
  17. package/lib/packlets/common/convert.d.ts.map +1 -1
  18. package/lib/packlets/common/convert.js +21 -1
  19. package/lib/packlets/common/convert.js.map +1 -1
  20. package/lib/packlets/common/helpers/context.d.ts +39 -0
  21. package/lib/packlets/common/helpers/context.d.ts.map +1 -0
  22. package/lib/packlets/common/helpers/context.js +108 -0
  23. package/lib/packlets/common/helpers/context.js.map +1 -0
  24. package/lib/packlets/common/helpers/index.d.ts +2 -0
  25. package/lib/packlets/common/helpers/index.d.ts.map +1 -1
  26. package/lib/packlets/common/helpers/index.js +2 -0
  27. package/lib/packlets/common/helpers/index.js.map +1 -1
  28. package/lib/packlets/common/helpers/qualifierDefaultValues.d.ts +39 -0
  29. package/lib/packlets/common/helpers/qualifierDefaultValues.d.ts.map +1 -0
  30. package/lib/packlets/common/helpers/qualifierDefaultValues.js +105 -0
  31. package/lib/packlets/common/helpers/qualifierDefaultValues.js.map +1 -0
  32. package/lib/packlets/common/helpers/resources.d.ts.map +1 -1
  33. package/lib/packlets/common/helpers/resources.js +6 -2
  34. package/lib/packlets/common/helpers/resources.js.map +1 -1
  35. package/lib/packlets/common/validate/conditions.d.ts +69 -1
  36. package/lib/packlets/common/validate/conditions.d.ts.map +1 -1
  37. package/lib/packlets/common/validate/conditions.js +126 -0
  38. package/lib/packlets/common/validate/conditions.js.map +1 -1
  39. package/lib/packlets/common/validate/regularExpressions.d.ts +20 -0
  40. package/lib/packlets/common/validate/regularExpressions.d.ts.map +1 -1
  41. package/lib/packlets/common/validate/regularExpressions.js +21 -1
  42. package/lib/packlets/common/validate/regularExpressions.js.map +1 -1
  43. package/lib/packlets/conditions/condition.d.ts +37 -0
  44. package/lib/packlets/conditions/condition.d.ts.map +1 -1
  45. package/lib/packlets/conditions/condition.js +67 -1
  46. package/lib/packlets/conditions/condition.js.map +1 -1
  47. package/lib/packlets/conditions/conditionCollector.d.ts.map +1 -1
  48. package/lib/packlets/conditions/conditionCollector.js +1 -0
  49. package/lib/packlets/conditions/conditionCollector.js.map +1 -1
  50. package/lib/packlets/conditions/conditionSet.d.ts +34 -3
  51. package/lib/packlets/conditions/conditionSet.d.ts.map +1 -1
  52. package/lib/packlets/conditions/conditionSet.js +31 -3
  53. package/lib/packlets/conditions/conditionSet.js.map +1 -1
  54. package/lib/packlets/conditions/conditionSetCollector.d.ts.map +1 -1
  55. package/lib/packlets/conditions/conditionSetCollector.js +3 -0
  56. package/lib/packlets/conditions/conditionSetCollector.js.map +1 -1
  57. package/lib/packlets/conditions/conditionToken.d.ts.map +1 -1
  58. package/lib/packlets/conditions/conditionToken.js +2 -1
  59. package/lib/packlets/conditions/conditionToken.js.map +1 -1
  60. package/lib/packlets/conditions/convert/decls.js +1 -1
  61. package/lib/packlets/conditions/convert/decls.js.map +1 -1
  62. package/lib/packlets/config/common.d.ts +35 -0
  63. package/lib/packlets/config/common.d.ts.map +1 -0
  64. package/lib/packlets/config/common.js +96 -0
  65. package/lib/packlets/config/common.js.map +1 -0
  66. package/lib/packlets/config/convert.d.ts +14 -0
  67. package/lib/packlets/config/convert.d.ts.map +1 -0
  68. package/lib/packlets/config/convert.js +82 -0
  69. package/lib/packlets/config/convert.js.map +1 -0
  70. package/lib/packlets/config/index.d.ts +6 -0
  71. package/lib/packlets/config/index.d.ts.map +1 -0
  72. package/lib/packlets/config/index.js +67 -0
  73. package/lib/packlets/config/index.js.map +1 -0
  74. package/lib/packlets/config/json.d.ts +20 -0
  75. package/lib/packlets/config/json.d.ts.map +1 -0
  76. package/lib/packlets/config/json.js +24 -0
  77. package/lib/packlets/config/json.js.map +1 -0
  78. package/lib/packlets/config/predefined/default.d.ts +57 -0
  79. package/lib/packlets/config/predefined/default.d.ts.map +1 -0
  80. package/lib/packlets/config/predefined/default.js +141 -0
  81. package/lib/packlets/config/predefined/default.js.map +1 -0
  82. package/lib/packlets/config/predefined/extended.d.ts +25 -0
  83. package/lib/packlets/config/predefined/extended.d.ts.map +1 -0
  84. package/lib/packlets/config/predefined/extended.js +193 -0
  85. package/lib/packlets/config/predefined/extended.js.map +1 -0
  86. package/lib/packlets/config/predefined/index.d.ts +4 -0
  87. package/lib/packlets/config/predefined/index.d.ts.map +1 -0
  88. package/lib/packlets/config/predefined/index.js +62 -0
  89. package/lib/packlets/config/predefined/index.js.map +1 -0
  90. package/lib/packlets/config/systemConfiguration.d.ts +81 -0
  91. package/lib/packlets/config/systemConfiguration.d.ts.map +1 -0
  92. package/lib/packlets/config/systemConfiguration.js +172 -0
  93. package/lib/packlets/config/systemConfiguration.js.map +1 -0
  94. package/lib/packlets/context/contextDecls.d.ts +49 -0
  95. package/lib/packlets/context/contextDecls.d.ts.map +1 -0
  96. package/lib/packlets/context/contextDecls.js +24 -0
  97. package/lib/packlets/context/contextDecls.js.map +1 -0
  98. package/lib/packlets/context/contextToken.d.ts +111 -0
  99. package/lib/packlets/context/contextToken.d.ts.map +1 -0
  100. package/lib/packlets/context/contextToken.js +206 -0
  101. package/lib/packlets/context/contextToken.js.map +1 -0
  102. package/lib/packlets/context/convert/decls.d.ts +37 -0
  103. package/lib/packlets/context/convert/decls.d.ts.map +1 -0
  104. package/lib/packlets/context/convert/decls.js +94 -0
  105. package/lib/packlets/context/convert/decls.js.map +1 -0
  106. package/lib/packlets/context/convert/index.d.ts +2 -0
  107. package/lib/packlets/context/convert/index.d.ts.map +1 -0
  108. package/lib/packlets/context/convert/index.js +39 -0
  109. package/lib/packlets/context/convert/index.js.map +1 -0
  110. package/lib/packlets/context/index.d.ts +5 -0
  111. package/lib/packlets/context/index.d.ts.map +1 -0
  112. package/lib/packlets/context/index.js +65 -0
  113. package/lib/packlets/context/index.js.map +1 -0
  114. package/lib/packlets/decisions/abstractDecision.d.ts +8 -0
  115. package/lib/packlets/decisions/abstractDecision.d.ts.map +1 -1
  116. package/lib/packlets/decisions/abstractDecision.js +9 -0
  117. package/lib/packlets/decisions/abstractDecision.js.map +1 -1
  118. package/lib/packlets/decisions/abstractDecisionCollector.d.ts.map +1 -1
  119. package/lib/packlets/decisions/abstractDecisionCollector.js +2 -0
  120. package/lib/packlets/decisions/abstractDecisionCollector.js.map +1 -1
  121. package/lib/packlets/decisions/concreteDecision.d.ts.map +1 -1
  122. package/lib/packlets/decisions/concreteDecision.js +1 -0
  123. package/lib/packlets/decisions/concreteDecision.js.map +1 -1
  124. package/lib/packlets/decisions/decision.d.ts.map +1 -1
  125. package/lib/packlets/decisions/decision.js +4 -0
  126. package/lib/packlets/decisions/decision.js.map +1 -1
  127. package/lib/packlets/import/fsItem.d.ts.map +1 -1
  128. package/lib/packlets/import/fsItem.js +1 -0
  129. package/lib/packlets/import/fsItem.js.map +1 -1
  130. package/lib/packlets/import/importContext.d.ts +19 -0
  131. package/lib/packlets/import/importContext.d.ts.map +1 -1
  132. package/lib/packlets/import/importContext.js +39 -0
  133. package/lib/packlets/import/importContext.js.map +1 -1
  134. package/lib/packlets/import/importManager.d.ts +5 -5
  135. package/lib/packlets/import/importManager.d.ts.map +1 -1
  136. package/lib/packlets/import/importManager.js.map +1 -1
  137. package/lib/packlets/import/importers/collectionImporter.d.ts +11 -13
  138. package/lib/packlets/import/importers/collectionImporter.d.ts.map +1 -1
  139. package/lib/packlets/import/importers/collectionImporter.js +29 -20
  140. package/lib/packlets/import/importers/collectionImporter.js.map +1 -1
  141. package/lib/packlets/import/importers/fsItemImporter.d.ts +2 -2
  142. package/lib/packlets/import/importers/fsItemImporter.d.ts.map +1 -1
  143. package/lib/packlets/import/importers/fsItemImporter.js +2 -2
  144. package/lib/packlets/import/importers/fsItemImporter.js.map +1 -1
  145. package/lib/packlets/import/importers/importer.d.ts +3 -3
  146. package/lib/packlets/import/importers/importer.d.ts.map +1 -1
  147. package/lib/packlets/import/importers/importer.js.map +1 -1
  148. package/lib/packlets/import/importers/jsonImporter.d.ts +2 -3
  149. package/lib/packlets/import/importers/jsonImporter.d.ts.map +1 -1
  150. package/lib/packlets/import/importers/jsonImporter.js +10 -20
  151. package/lib/packlets/import/importers/jsonImporter.js.map +1 -1
  152. package/lib/packlets/import/importers/pathImporter.d.ts +2 -2
  153. package/lib/packlets/import/importers/pathImporter.d.ts.map +1 -1
  154. package/lib/packlets/import/importers/pathImporter.js.map +1 -1
  155. package/lib/packlets/qualifier-types/config/convert.d.ts +44 -0
  156. package/lib/packlets/qualifier-types/config/convert.d.ts.map +1 -0
  157. package/lib/packlets/qualifier-types/config/convert.js +96 -0
  158. package/lib/packlets/qualifier-types/config/convert.js.map +1 -0
  159. package/lib/packlets/qualifier-types/config/index.d.ts +4 -0
  160. package/lib/packlets/qualifier-types/config/index.d.ts.map +1 -0
  161. package/lib/packlets/qualifier-types/config/index.js +64 -0
  162. package/lib/packlets/qualifier-types/config/index.js.map +1 -0
  163. package/lib/packlets/qualifier-types/config/json.d.ts +69 -0
  164. package/lib/packlets/qualifier-types/config/json.d.ts.map +1 -0
  165. package/lib/packlets/qualifier-types/config/json.js +24 -0
  166. package/lib/packlets/qualifier-types/config/json.js.map +1 -0
  167. package/lib/packlets/qualifier-types/convert.d.ts +10 -2
  168. package/lib/packlets/qualifier-types/convert.d.ts.map +1 -1
  169. package/lib/packlets/qualifier-types/convert.js +15 -0
  170. package/lib/packlets/qualifier-types/convert.js.map +1 -1
  171. package/lib/packlets/qualifier-types/helpers.d.ts +27 -0
  172. package/lib/packlets/qualifier-types/helpers.d.ts.map +1 -0
  173. package/lib/packlets/qualifier-types/helpers.js +118 -0
  174. package/lib/packlets/qualifier-types/helpers.js.map +1 -0
  175. package/lib/packlets/qualifier-types/index.d.ts +4 -1
  176. package/lib/packlets/qualifier-types/index.d.ts.map +1 -1
  177. package/lib/packlets/qualifier-types/index.js +5 -1
  178. package/lib/packlets/qualifier-types/index.js.map +1 -1
  179. package/lib/packlets/qualifier-types/languageQualifierType.d.ts +19 -8
  180. package/lib/packlets/qualifier-types/languageQualifierType.d.ts.map +1 -1
  181. package/lib/packlets/qualifier-types/languageQualifierType.js +28 -9
  182. package/lib/packlets/qualifier-types/languageQualifierType.js.map +1 -1
  183. package/lib/packlets/qualifier-types/literalQualifierType.d.ts +42 -13
  184. package/lib/packlets/qualifier-types/literalQualifierType.d.ts.map +1 -1
  185. package/lib/packlets/qualifier-types/literalQualifierType.js +58 -10
  186. package/lib/packlets/qualifier-types/literalQualifierType.js.map +1 -1
  187. package/lib/packlets/qualifier-types/literalValueHierarchy.d.ts +114 -0
  188. package/lib/packlets/qualifier-types/literalValueHierarchy.d.ts.map +1 -0
  189. package/lib/packlets/qualifier-types/literalValueHierarchy.js +228 -0
  190. package/lib/packlets/qualifier-types/literalValueHierarchy.js.map +1 -0
  191. package/lib/packlets/qualifier-types/qualifierType.d.ts +33 -18
  192. package/lib/packlets/qualifier-types/qualifierType.d.ts.map +1 -1
  193. package/lib/packlets/qualifier-types/qualifierType.js +18 -4
  194. package/lib/packlets/qualifier-types/qualifierType.js.map +1 -1
  195. package/lib/packlets/qualifier-types/qualifierTypeCollector.d.ts +4 -2
  196. package/lib/packlets/qualifier-types/qualifierTypeCollector.d.ts.map +1 -1
  197. package/lib/packlets/qualifier-types/qualifierTypeCollector.js +2 -1
  198. package/lib/packlets/qualifier-types/qualifierTypeCollector.js.map +1 -1
  199. package/lib/packlets/qualifier-types/territoryQualifierType.d.ts +47 -11
  200. package/lib/packlets/qualifier-types/territoryQualifierType.d.ts.map +1 -1
  201. package/lib/packlets/qualifier-types/territoryQualifierType.js +61 -17
  202. package/lib/packlets/qualifier-types/territoryQualifierType.js.map +1 -1
  203. package/lib/packlets/qualifiers/convert/decls.d.ts.map +1 -1
  204. package/lib/packlets/qualifiers/convert/decls.js +17 -15
  205. package/lib/packlets/qualifiers/convert/decls.js.map +1 -1
  206. package/lib/packlets/qualifiers/index.d.ts +2 -0
  207. package/lib/packlets/qualifiers/index.d.ts.map +1 -1
  208. package/lib/packlets/qualifiers/index.js +2 -0
  209. package/lib/packlets/qualifiers/index.js.map +1 -1
  210. package/lib/packlets/qualifiers/qualifier.d.ts +22 -2
  211. package/lib/packlets/qualifiers/qualifier.d.ts.map +1 -1
  212. package/lib/packlets/qualifiers/qualifier.js +26 -1
  213. package/lib/packlets/qualifiers/qualifier.js.map +1 -1
  214. package/lib/packlets/qualifiers/qualifierCollector.d.ts.map +1 -1
  215. package/lib/packlets/qualifiers/qualifierCollector.js +4 -0
  216. package/lib/packlets/qualifiers/qualifierCollector.js.map +1 -1
  217. package/lib/packlets/qualifiers/qualifierDecl.d.ts +6 -1
  218. package/lib/packlets/qualifiers/qualifierDecl.d.ts.map +1 -1
  219. package/lib/packlets/qualifiers/qualifierDecl.js.map +1 -1
  220. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.d.ts +32 -0
  221. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.d.ts.map +1 -0
  222. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.js +24 -0
  223. package/lib/packlets/qualifiers/qualifierDefaultValueDecls.js.map +1 -0
  224. package/lib/packlets/qualifiers/qualifierDefaultValueToken.d.ts +96 -0
  225. package/lib/packlets/qualifiers/qualifierDefaultValueToken.d.ts.map +1 -0
  226. package/lib/packlets/qualifiers/qualifierDefaultValueToken.js +179 -0
  227. package/lib/packlets/qualifiers/qualifierDefaultValueToken.js.map +1 -0
  228. package/lib/packlets/resource-json/compiled/common.d.ts +14 -0
  229. package/lib/packlets/resource-json/compiled/common.d.ts.map +1 -0
  230. package/lib/packlets/resource-json/compiled/common.js +24 -0
  231. package/lib/packlets/resource-json/compiled/common.js.map +1 -0
  232. package/lib/packlets/resource-json/compiled/convert.d.ts +63 -0
  233. package/lib/packlets/resource-json/compiled/convert.d.ts.map +1 -0
  234. package/lib/packlets/resource-json/compiled/convert.js +167 -0
  235. package/lib/packlets/resource-json/compiled/convert.js.map +1 -0
  236. package/lib/packlets/resource-json/compiled/index.d.ts +5 -0
  237. package/lib/packlets/resource-json/compiled/index.d.ts.map +1 -0
  238. package/lib/packlets/resource-json/compiled/index.js +65 -0
  239. package/lib/packlets/resource-json/compiled/index.js.map +1 -0
  240. package/lib/packlets/resource-json/compiled/json.d.ts +204 -0
  241. package/lib/packlets/resource-json/compiled/json.d.ts.map +1 -0
  242. package/lib/packlets/resource-json/compiled/json.js +3 -0
  243. package/lib/packlets/resource-json/compiled/json.js.map +1 -0
  244. package/lib/packlets/resource-json/convert.d.ts +16 -0
  245. package/lib/packlets/resource-json/convert.d.ts.map +1 -1
  246. package/lib/packlets/resource-json/convert.js +41 -6
  247. package/lib/packlets/resource-json/convert.js.map +1 -1
  248. package/lib/packlets/resource-json/helpers.d.ts +82 -3
  249. package/lib/packlets/resource-json/helpers.d.ts.map +1 -1
  250. package/lib/packlets/resource-json/helpers.js +185 -2
  251. package/lib/packlets/resource-json/helpers.js.map +1 -1
  252. package/lib/packlets/resource-json/index.d.ts +2 -1
  253. package/lib/packlets/resource-json/index.d.ts.map +1 -1
  254. package/lib/packlets/resource-json/index.js +3 -1
  255. package/lib/packlets/resource-json/index.js.map +1 -1
  256. package/lib/packlets/resource-json/json.d.ts +55 -3
  257. package/lib/packlets/resource-json/json.d.ts.map +1 -1
  258. package/lib/packlets/resource-json/json.js +16 -0
  259. package/lib/packlets/resource-json/json.js.map +1 -1
  260. package/lib/packlets/resource-json/normalized.d.ts +46 -3
  261. package/lib/packlets/resource-json/normalized.d.ts.map +1 -1
  262. package/lib/packlets/resource-json/normalized.js.map +1 -1
  263. package/lib/packlets/resource-json/resourceDeclCollection.d.ts +14 -10
  264. package/lib/packlets/resource-json/resourceDeclCollection.d.ts.map +1 -1
  265. package/lib/packlets/resource-json/resourceDeclCollection.js +18 -14
  266. package/lib/packlets/resource-json/resourceDeclCollection.js.map +1 -1
  267. package/lib/packlets/resource-json/resourceDeclContainer.d.ts +15 -2
  268. package/lib/packlets/resource-json/resourceDeclContainer.d.ts.map +1 -1
  269. package/lib/packlets/resource-json/resourceDeclContainer.js.map +1 -1
  270. package/lib/packlets/resource-json/resourceDeclTree.d.ts +6 -2
  271. package/lib/packlets/resource-json/resourceDeclTree.d.ts.map +1 -1
  272. package/lib/packlets/resource-json/resourceDeclTree.js +12 -3
  273. package/lib/packlets/resource-json/resourceDeclTree.js.map +1 -1
  274. package/lib/packlets/resource-types/config/convert.d.ts +8 -0
  275. package/lib/packlets/resource-types/config/convert.d.ts.map +1 -0
  276. package/lib/packlets/resource-types/config/convert.js +36 -0
  277. package/lib/packlets/resource-types/config/convert.js.map +1 -0
  278. package/lib/packlets/resource-types/config/index.d.ts +4 -0
  279. package/lib/packlets/resource-types/config/index.d.ts.map +1 -0
  280. package/lib/packlets/resource-types/config/index.js +64 -0
  281. package/lib/packlets/resource-types/config/index.js.map +1 -0
  282. package/lib/packlets/resource-types/config/json.d.ts +9 -0
  283. package/lib/packlets/resource-types/config/json.d.ts.map +1 -0
  284. package/lib/packlets/resource-types/config/json.js +24 -0
  285. package/lib/packlets/resource-types/config/json.js.map +1 -0
  286. package/lib/packlets/resource-types/helpers.d.ts +13 -0
  287. package/lib/packlets/resource-types/helpers.d.ts.map +1 -0
  288. package/lib/packlets/resource-types/helpers.js +44 -0
  289. package/lib/packlets/resource-types/helpers.js.map +1 -0
  290. package/lib/packlets/resource-types/index.d.ts +3 -0
  291. package/lib/packlets/resource-types/index.d.ts.map +1 -1
  292. package/lib/packlets/resource-types/index.js +26 -0
  293. package/lib/packlets/resource-types/index.js.map +1 -1
  294. package/lib/packlets/resource-types/jsonResourceType.d.ts +5 -13
  295. package/lib/packlets/resource-types/jsonResourceType.d.ts.map +1 -1
  296. package/lib/packlets/resource-types/jsonResourceType.js +5 -2
  297. package/lib/packlets/resource-types/jsonResourceType.js.map +1 -1
  298. package/lib/packlets/resource-types/resourceType.d.ts +31 -30
  299. package/lib/packlets/resource-types/resourceType.d.ts.map +1 -1
  300. package/lib/packlets/resource-types/resourceType.js.map +1 -1
  301. package/lib/packlets/resources/candidateReducer.d.ts +98 -0
  302. package/lib/packlets/resources/candidateReducer.d.ts.map +1 -0
  303. package/lib/packlets/resources/candidateReducer.js +247 -0
  304. package/lib/packlets/resources/candidateReducer.js.map +1 -0
  305. package/lib/packlets/resources/common.d.ts +60 -0
  306. package/lib/packlets/resources/common.d.ts.map +1 -0
  307. package/lib/packlets/resources/common.js +24 -0
  308. package/lib/packlets/resources/common.js.map +1 -0
  309. package/lib/packlets/resources/index.d.ts +3 -1
  310. package/lib/packlets/resources/index.d.ts.map +1 -1
  311. package/lib/packlets/resources/index.js +3 -1
  312. package/lib/packlets/resources/index.js.map +1 -1
  313. package/lib/packlets/resources/resource.d.ts +57 -5
  314. package/lib/packlets/resources/resource.d.ts.map +1 -1
  315. package/lib/packlets/resources/resource.js +96 -6
  316. package/lib/packlets/resources/resource.js.map +1 -1
  317. package/lib/packlets/resources/resourceBuilder.d.ts +14 -0
  318. package/lib/packlets/resources/resourceBuilder.d.ts.map +1 -1
  319. package/lib/packlets/resources/resourceBuilder.js +19 -1
  320. package/lib/packlets/resources/resourceBuilder.js.map +1 -1
  321. package/lib/packlets/resources/resourceCandidate.d.ts +42 -6
  322. package/lib/packlets/resources/resourceCandidate.d.ts.map +1 -1
  323. package/lib/packlets/resources/resourceCandidate.js +40 -1
  324. package/lib/packlets/resources/resourceCandidate.js.map +1 -1
  325. package/lib/packlets/resources/resourceManagerBuilder.d.ts +220 -0
  326. package/lib/packlets/resources/resourceManagerBuilder.d.ts.map +1 -0
  327. package/lib/packlets/resources/resourceManagerBuilder.js +451 -0
  328. package/lib/packlets/resources/resourceManagerBuilder.js.map +1 -0
  329. package/lib/packlets/runtime/cacheListener.d.ts +62 -0
  330. package/lib/packlets/runtime/cacheListener.d.ts.map +1 -0
  331. package/lib/packlets/runtime/cacheListener.js +56 -0
  332. package/lib/packlets/runtime/cacheListener.js.map +1 -0
  333. package/lib/packlets/runtime/cacheMetrics.d.ts +82 -0
  334. package/lib/packlets/runtime/cacheMetrics.d.ts.map +1 -0
  335. package/lib/packlets/runtime/cacheMetrics.js +143 -0
  336. package/lib/packlets/runtime/cacheMetrics.js.map +1 -0
  337. package/lib/packlets/runtime/compiledResourceCollection.d.ts +167 -0
  338. package/lib/packlets/runtime/compiledResourceCollection.d.ts.map +1 -0
  339. package/lib/packlets/runtime/compiledResourceCollection.js +466 -0
  340. package/lib/packlets/runtime/compiledResourceCollection.js.map +1 -0
  341. package/lib/packlets/runtime/conditionSetResolutionResult.d.ts +70 -0
  342. package/lib/packlets/runtime/conditionSetResolutionResult.d.ts.map +1 -0
  343. package/lib/packlets/runtime/conditionSetResolutionResult.js +135 -0
  344. package/lib/packlets/runtime/conditionSetResolutionResult.js.map +1 -0
  345. package/lib/packlets/runtime/context/contextQualifierProvider.d.ts +80 -0
  346. package/lib/packlets/runtime/context/contextQualifierProvider.d.ts.map +1 -0
  347. package/lib/packlets/runtime/context/contextQualifierProvider.js +33 -0
  348. package/lib/packlets/runtime/context/contextQualifierProvider.js.map +1 -0
  349. package/lib/packlets/runtime/context/contextQualifierProviderValidator.d.ts +165 -0
  350. package/lib/packlets/runtime/context/contextQualifierProviderValidator.d.ts.map +1 -0
  351. package/lib/packlets/runtime/context/contextQualifierProviderValidator.js +179 -0
  352. package/lib/packlets/runtime/context/contextQualifierProviderValidator.js.map +1 -0
  353. package/lib/packlets/runtime/context/index.d.ts +5 -0
  354. package/lib/packlets/runtime/context/index.d.ts.map +1 -0
  355. package/lib/packlets/runtime/context/index.js +42 -0
  356. package/lib/packlets/runtime/context/index.js.map +1 -0
  357. package/lib/packlets/runtime/context/simpleContextQualifierProvider.d.ts +111 -0
  358. package/lib/packlets/runtime/context/simpleContextQualifierProvider.d.ts.map +1 -0
  359. package/lib/packlets/runtime/context/simpleContextQualifierProvider.js +177 -0
  360. package/lib/packlets/runtime/context/simpleContextQualifierProvider.js.map +1 -0
  361. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.d.ts +47 -0
  362. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.d.ts.map +1 -0
  363. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.js +64 -0
  364. package/lib/packlets/runtime/context/validatingSimpleContextQualifierProvider.js.map +1 -0
  365. package/lib/packlets/runtime/iResourceManager.d.ts +88 -0
  366. package/lib/packlets/runtime/iResourceManager.d.ts.map +1 -0
  367. package/lib/packlets/runtime/iResourceManager.js +24 -0
  368. package/lib/packlets/runtime/iResourceManager.js.map +1 -0
  369. package/lib/packlets/runtime/index.d.ts +12 -0
  370. package/lib/packlets/runtime/index.d.ts.map +1 -0
  371. package/lib/packlets/runtime/index.js +73 -0
  372. package/lib/packlets/runtime/index.js.map +1 -0
  373. package/lib/packlets/runtime/resource-tree/common.d.ts +91 -0
  374. package/lib/packlets/runtime/resource-tree/common.d.ts.map +1 -0
  375. package/lib/packlets/runtime/resource-tree/common.js +24 -0
  376. package/lib/packlets/runtime/resource-tree/common.js.map +1 -0
  377. package/lib/packlets/runtime/resource-tree/index.d.ts +5 -0
  378. package/lib/packlets/runtime/resource-tree/index.d.ts.map +1 -0
  379. package/lib/packlets/runtime/resource-tree/index.js +42 -0
  380. package/lib/packlets/runtime/resource-tree/index.js.map +1 -0
  381. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.d.ts +141 -0
  382. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.d.ts.map +1 -0
  383. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.js +224 -0
  384. package/lib/packlets/runtime/resource-tree/readOnlyResourceTree.js.map +1 -0
  385. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.d.ts +24 -0
  386. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.d.ts.map +1 -0
  387. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.js +98 -0
  388. package/lib/packlets/runtime/resource-tree/resourceTreeChildren.js.map +1 -0
  389. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.d.ts +99 -0
  390. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.d.ts.map +1 -0
  391. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js +165 -0
  392. package/lib/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js.map +1 -0
  393. package/lib/packlets/runtime/resourceResolver.d.ts +196 -0
  394. package/lib/packlets/runtime/resourceResolver.d.ts.map +1 -0
  395. package/lib/packlets/runtime/resourceResolver.js +437 -0
  396. package/lib/packlets/runtime/resourceResolver.js.map +1 -0
  397. package/lib/packlets/runtime/validate.d.ts +13 -0
  398. package/lib/packlets/runtime/validate.d.ts.map +1 -0
  399. package/lib/packlets/runtime/validate.js +49 -0
  400. package/lib/packlets/runtime/validate.js.map +1 -0
  401. package/package.json +76 -75
  402. package/lib/packlets/resources/resourceManager.d.ts +0 -104
  403. package/lib/packlets/resources/resourceManager.d.ts.map +0 -1
  404. package/lib/packlets/resources/resourceManager.js +0 -201
  405. package/lib/packlets/resources/resourceManager.js.map +0 -1
@@ -0,0 +1,437 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2025 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.ResourceResolver = void 0;
25
+ const ts_utils_1 = require("@fgv/ts-utils");
26
+ const ts_json_base_1 = require("@fgv/ts-json-base");
27
+ const ts_json_1 = require("@fgv/ts-json");
28
+ const common_1 = require("../common");
29
+ const conditionSetResolutionResult_1 = require("./conditionSetResolutionResult");
30
+ /**
31
+ * High-performance runtime resource resolver with O(1) condition caching.
32
+ * Resolves resources for a given context by evaluating conditions against qualifier values
33
+ * and caching results for optimal performance.
34
+ * @public
35
+ */
36
+ class ResourceResolver {
37
+ /**
38
+ * The cache array for resolved conditions, indexed by condition index for O(1) lookup.
39
+ * Each entry stores the resolved {@link Runtime.IConditionMatchResult | condition match result} for
40
+ * the corresponding condition.
41
+ */
42
+ get conditionCache() {
43
+ return this._conditionCache;
44
+ }
45
+ /**
46
+ * The cache array for resolved condition sets, indexed by condition set index for O(1) lookup.
47
+ * Each entry stores the resolved ConditionSetResolutionResult for the corresponding condition set.
48
+ */
49
+ get conditionSetCache() {
50
+ return this._conditionSetCache;
51
+ }
52
+ /**
53
+ * The cache array for resolved decisions, indexed by decision index for O(1) lookup.
54
+ * Each entry stores the resolved DecisionResolutionResult for the corresponding decision.
55
+ */
56
+ get decisionCache() {
57
+ return this._decisionCache;
58
+ }
59
+ /**
60
+ * Constructor for a {@link Runtime.ResourceResolver | ResourceResolver} object.
61
+ * @param params - {@link Runtime.IResourceResolverCreateParams | Parameters} used to create the resolver.
62
+ */
63
+ constructor(params) {
64
+ this.resourceManager = params.resourceManager;
65
+ this.qualifierTypes = params.qualifierTypes;
66
+ this.contextQualifierProvider = params.contextQualifierProvider;
67
+ // Initialize condition cache array with size matching the condition collector
68
+ const conditionCollectorSize = this.resourceManager.conditions.size;
69
+ this._conditionCache = new Array(conditionCollectorSize);
70
+ // Initialize condition set cache array with size matching the condition set collector
71
+ const conditionSetCollectorSize = this.resourceManager.conditionSets.size;
72
+ this._conditionSetCache = new Array(conditionSetCollectorSize);
73
+ // Initialize decision cache array with size matching the decision collector
74
+ const decisionCollectorSize = this.resourceManager.decisions.size;
75
+ this._decisionCache = new Array(decisionCollectorSize);
76
+ this._listener = params.listener;
77
+ }
78
+ /**
79
+ * Creates a new {@link Runtime.ResourceResolver | ResourceResolver} object.
80
+ * @param params - {@link Runtime.IResourceResolverCreateParams | Parameters} used to create the resolver.
81
+ * @returns `Success` with the new {@link Runtime.ResourceResolver | ResourceResolver} object if successful,
82
+ * or `Failure` with an error message if not.
83
+ * @public
84
+ */
85
+ static create(params) {
86
+ return (0, ts_utils_1.captureResult)(() => new ResourceResolver(params));
87
+ }
88
+ /**
89
+ * Resolves a condition by evaluating it against the current context.
90
+ * Uses O(1) caching based on the condition's globally unique sequential index.
91
+ * @param condition - The {@link Conditions.Condition | condition} to resolve.
92
+ * @returns `Success` with the {@link QualifierMatchScore | match score} if successful,
93
+ * or `Failure` with an error message if the condition cannot be resolved.
94
+ * @public
95
+ */
96
+ resolveCondition(condition) {
97
+ var _a, _b, _c, _d;
98
+ // Get the condition's index for cache lookup
99
+ const conditionIndex = condition.index;
100
+ if (conditionIndex === undefined) {
101
+ return (0, ts_utils_1.fail)(`Condition "${condition.key}" does not have a valid index`);
102
+ }
103
+ // Check cache first for O(1) lookup
104
+ const cachedResult = this._conditionCache[conditionIndex];
105
+ if (cachedResult !== undefined) {
106
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheHit('condition', conditionIndex);
107
+ return (0, ts_utils_1.succeed)(cachedResult);
108
+ }
109
+ // Resolve the condition by getting qualifier value and evaluating with qualifier type
110
+ const qualifierValueResult = this.contextQualifierProvider.get(condition.qualifier);
111
+ if (qualifierValueResult.isFailure()) {
112
+ (_b = this._listener) === null || _b === void 0 ? void 0 : _b.onCacheError('condition', conditionIndex);
113
+ return (0, ts_utils_1.fail)(`Failed to get qualifier value for "${condition.qualifier.name}": ${qualifierValueResult.message}`);
114
+ }
115
+ const qualifierValue = qualifierValueResult.value;
116
+ // Evaluate the condition using the qualifier type's matching logic
117
+ const score = condition.qualifier.type.matches(condition.value, qualifierValue, condition.operator);
118
+ const priority = condition.priority;
119
+ const scoreAsDefault = (_c = condition.scoreAsDefault) !== null && _c !== void 0 ? _c : common_1.NoMatch;
120
+ const matchResult = score > common_1.NoMatch
121
+ ? { score, priority, matchType: 'match' }
122
+ : scoreAsDefault > common_1.NoMatch
123
+ ? { score: scoreAsDefault, priority, matchType: 'matchAsDefault' }
124
+ : { score: common_1.NoMatch, priority, matchType: 'noMatch' };
125
+ // Cache the resolved value for future O(1) lookup
126
+ this._conditionCache[conditionIndex] = matchResult;
127
+ (_d = this._listener) === null || _d === void 0 ? void 0 : _d.onCacheMiss('condition', conditionIndex);
128
+ return (0, ts_utils_1.succeed)(matchResult);
129
+ }
130
+ /**
131
+ * Resolves a condition set by evaluating all its constituent conditions against the current context.
132
+ * Uses O(1) caching based on the condition set's globally unique sequential index.
133
+ * @param conditionSet - The {@link Conditions.ConditionSet | condition set} to resolve.
134
+ * @returns `Success` with the {@link Runtime.ConditionSetResolutionResult | resolution result} if successful,
135
+ * or `Failure` with an error message if the condition set cannot be resolved.
136
+ * @public
137
+ */
138
+ resolveConditionSet(conditionSet) {
139
+ var _a, _b;
140
+ // Get the condition set's index for cache lookup
141
+ const conditionSetIndex = conditionSet.index;
142
+ if (conditionSetIndex === undefined) {
143
+ return (0, ts_utils_1.fail)(`ConditionSet "${conditionSet.key}" does not have a valid index`);
144
+ }
145
+ // Check cache first for O(1) lookup
146
+ const cachedResult = this._conditionSetCache[conditionSetIndex];
147
+ if (cachedResult !== undefined) {
148
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheHit('conditionSet', conditionSetIndex);
149
+ return (0, ts_utils_1.succeed)(cachedResult);
150
+ }
151
+ // Resolve all conditions in the condition set
152
+ const conditions = [];
153
+ let matchType = 'match';
154
+ for (const condition of conditionSet.conditions) {
155
+ const { value: conditionResult, message: conditionMessage } = this.resolveCondition(condition);
156
+ if (conditionMessage !== undefined) {
157
+ /* c8 ignore next 2 - defensive coding: extreme internal error scenario not reachable in normal operation */
158
+ (_b = this._listener) === null || _b === void 0 ? void 0 : _b.onCacheError('conditionSet', conditionSetIndex);
159
+ return (0, ts_utils_1.fail)(`Failed to resolve condition "${condition.key}": ${conditionMessage}`);
160
+ }
161
+ conditions.push(conditionResult);
162
+ if (conditionResult.matchType === 'noMatch') {
163
+ // Cache the failure result
164
+ return conditionSetResolutionResult_1.ConditionSetResolutionResult.create('noMatch', conditions)
165
+ .onSuccess((result) => {
166
+ var _a;
167
+ this._conditionSetCache[conditionSetIndex] = result;
168
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheMiss('conditionSet', conditionSetIndex);
169
+ return (0, ts_utils_1.succeed)(result);
170
+ })
171
+ .onFailure((err) => {
172
+ var _a;
173
+ /* c8 ignore next 4 - defensive coding: extreme internal error scenario not reachable in normal operation */
174
+ this._conditionSetCache[conditionSetIndex] = undefined;
175
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheError('conditionSet', conditionSetIndex);
176
+ return (0, ts_utils_1.fail)(`${conditionSetIndex}: error creating condition set resolution result: ${err}`);
177
+ });
178
+ }
179
+ if (conditionResult.matchType === 'matchAsDefault') {
180
+ matchType = 'matchAsDefault';
181
+ }
182
+ }
183
+ // Cache the successful result
184
+ return conditionSetResolutionResult_1.ConditionSetResolutionResult.create(matchType, conditions)
185
+ .onSuccess((result) => {
186
+ var _a;
187
+ this._conditionSetCache[conditionSetIndex] = result;
188
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheMiss('conditionSet', conditionSetIndex);
189
+ return (0, ts_utils_1.succeed)(result);
190
+ })
191
+ .onFailure((err) => {
192
+ var _a;
193
+ /* c8 ignore next 4 - defensive coding: extreme internal error scenario not reachable in normal operation */
194
+ this._conditionSetCache[conditionSetIndex] = undefined;
195
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheError('conditionSet', conditionSetIndex);
196
+ return (0, ts_utils_1.fail)(`${conditionSetIndex}: error creating condition set resolution result: ${err}`);
197
+ });
198
+ }
199
+ /**
200
+ * Resolves a decision by evaluating all its constituent condition sets against the current context.
201
+ * Uses O(1) caching based on the decision's globally unique sequential index.
202
+ * @param decision - The {@link Decisions.AbstractDecision | abstract decision} to resolve.
203
+ * @returns `Success` with the {@link Runtime.DecisionResolutionResult | resolution result} if successful,
204
+ * or `Failure` with an error message if the decision cannot be resolved.
205
+ * @public
206
+ */
207
+ resolveDecision(decision) {
208
+ var _a, _b, _c;
209
+ // Get the decision's index for cache lookup
210
+ const decisionIndex = decision.index;
211
+ if (decisionIndex === undefined) {
212
+ return (0, ts_utils_1.fail)(`Decision "${decision.key}" does not have a valid index`);
213
+ }
214
+ // Check cache first for O(1) lookup
215
+ const cachedResult = this._decisionCache[decisionIndex];
216
+ if (cachedResult !== undefined) {
217
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheHit('decision', decisionIndex);
218
+ return (0, ts_utils_1.succeed)(cachedResult);
219
+ }
220
+ // Resolve all condition sets in the decision
221
+ const matchingInstanceResults = [];
222
+ const matchingDefaultInstanceResults = [];
223
+ for (let instanceIndex = 0; instanceIndex < decision.candidates.length; instanceIndex++) {
224
+ const candidate = decision.candidates[instanceIndex];
225
+ const conditionSetResult = this.resolveConditionSet(candidate.conditionSet);
226
+ if (conditionSetResult.isFailure()) {
227
+ /* c8 ignore next 2 - defensive coding: extreme internal error scenario not reachable in normal operation */
228
+ (_b = this._listener) === null || _b === void 0 ? void 0 : _b.onCacheError('decision', decisionIndex);
229
+ return (0, ts_utils_1.fail)(`${decision.key}: Failed to resolve condition set": ${conditionSetResult.message}`);
230
+ }
231
+ const resolution = conditionSetResult.value;
232
+ // Only include condition sets that match
233
+ if (resolution.matchType === 'match') {
234
+ matchingInstanceResults.push({
235
+ index: instanceIndex,
236
+ result: resolution
237
+ });
238
+ }
239
+ else if (resolution.matchType === 'matchAsDefault') {
240
+ matchingDefaultInstanceResults.push({
241
+ index: instanceIndex,
242
+ result: resolution
243
+ });
244
+ }
245
+ // If condition set doesn't match, we simply skip it and continue (don't fail the decision)
246
+ }
247
+ // Sort by condition set resolution priority using the proper comparison logic
248
+ matchingInstanceResults.sort((a, b) => conditionSetResolutionResult_1.ConditionSetResolutionResult.compare(a.result, b.result));
249
+ matchingDefaultInstanceResults.sort((a, b) => conditionSetResolutionResult_1.ConditionSetResolutionResult.compare(a.result, b.result));
250
+ // Extract just the instance indices in priority order
251
+ const instanceIndices = matchingInstanceResults.map((item) => item.index);
252
+ const defaultInstanceIndices = matchingDefaultInstanceResults.map((item) => item.index);
253
+ // Cache the successful result
254
+ const successResult = {
255
+ success: true,
256
+ instanceIndices,
257
+ defaultInstanceIndices
258
+ };
259
+ this._decisionCache[decisionIndex] = successResult;
260
+ (_c = this._listener) === null || _c === void 0 ? void 0 : _c.onCacheMiss('decision', decisionIndex);
261
+ return (0, ts_utils_1.succeed)(successResult);
262
+ }
263
+ /**
264
+ * Resolves a resource by finding the best matching candidate.
265
+ * Uses the resource's associated decision to determine the best match based on the current context.
266
+ * @param resource - The {@link Resources.Resource | resource} to resolve.
267
+ * @returns `Success` with the best matching candidate if successful,
268
+ * or `Failure` with an error message if no candidates match or resolution fails.
269
+ * @public
270
+ */
271
+ resolveResource(resource) {
272
+ // Get the abstract decision from the resource's concrete decision
273
+ const abstractDecision = resource.decision.baseDecision;
274
+ // Resolve the decision to get candidate indices in priority order
275
+ const decisionResult = this.resolveDecision(abstractDecision);
276
+ /* c8 ignore next 3 - defense in depth almost impossible to hit */
277
+ if (decisionResult.isFailure()) {
278
+ return (0, ts_utils_1.fail)(`Failed to resolve decision for resource "${resource.id}": ${decisionResult.message}`);
279
+ }
280
+ const resolution = decisionResult.value;
281
+ // Check if any candidates matched (regular or default)
282
+ if (!resolution.success ||
283
+ (resolution.instanceIndices.length === 0 && resolution.defaultInstanceIndices.length === 0)) {
284
+ return (0, ts_utils_1.fail)(`No matching candidates found for resource "${resource.id}"`);
285
+ }
286
+ // Prefer regular matches over default matches
287
+ const candidateIndex = resolution.instanceIndices.length > 0
288
+ ? resolution.instanceIndices[0] // Best regular match
289
+ : resolution.defaultInstanceIndices[0]; // Best default match
290
+ if (candidateIndex >= resource.candidates.length) {
291
+ return (0, ts_utils_1.fail)(`Invalid candidate index ${candidateIndex} for resource "${resource.id}"`);
292
+ }
293
+ const bestCandidate = resource.candidates[candidateIndex];
294
+ return (0, ts_utils_1.succeed)(bestCandidate);
295
+ }
296
+ /**
297
+ * Resolves all matching resource candidates in priority order.
298
+ * Uses the resource's associated decision to determine all matching candidates based on the current context.
299
+ * @param resource - The {@link Resources.Resource | resource} to resolve.
300
+ * @returns `Success` with an array of all matching candidates in priority order if successful,
301
+ * or `Failure` with an error message if no candidates match or resolution fails.
302
+ * @public
303
+ */
304
+ resolveAllResourceCandidates(resource) {
305
+ // Get the abstract decision from the resource's concrete decision
306
+ const abstractDecision = resource.decision.baseDecision;
307
+ // Resolve the decision to get candidate indices in priority order
308
+ const decisionResult = this.resolveDecision(abstractDecision);
309
+ /* c8 ignore next 3 - defense in depth almost impossible to hit */
310
+ if (decisionResult.isFailure()) {
311
+ return (0, ts_utils_1.fail)(`Failed to resolve decision for resource "${resource.id}": ${decisionResult.message}`);
312
+ }
313
+ const resolution = decisionResult.value;
314
+ // Check if any candidates matched (regular or default)
315
+ if (!resolution.success ||
316
+ (resolution.instanceIndices.length === 0 && resolution.defaultInstanceIndices.length === 0)) {
317
+ return (0, ts_utils_1.fail)(`No matching candidates found for resource "${resource.id}"`);
318
+ }
319
+ // Get all matching candidates: regular matches first, then default matches
320
+ const candidates = [];
321
+ // Add all regular matches first (already sorted by priority)
322
+ for (const candidateIndex of resolution.instanceIndices) {
323
+ if (candidateIndex >= resource.candidates.length) {
324
+ return (0, ts_utils_1.fail)(`Invalid candidate index ${candidateIndex} for resource "${resource.id}"`);
325
+ }
326
+ const candidate = resource.candidates[candidateIndex];
327
+ candidates.push(candidate);
328
+ }
329
+ // Add all default matches after regular matches (already sorted by priority)
330
+ for (const candidateIndex of resolution.defaultInstanceIndices) {
331
+ /* c8 ignore next 3 - defensive coding: extreme internal error scenario not reachable in normal operation */
332
+ if (candidateIndex >= resource.candidates.length) {
333
+ return (0, ts_utils_1.fail)(`Invalid candidate index ${candidateIndex} for resource "${resource.id}"`);
334
+ }
335
+ const candidate = resource.candidates[candidateIndex];
336
+ candidates.push(candidate);
337
+ }
338
+ return (0, ts_utils_1.succeed)(candidates);
339
+ }
340
+ /**
341
+ * Resolves a resource to a composed value by merging matching candidates according to their merge methods.
342
+ * Starting from the highest priority candidates, finds the first "full" candidate and merges all higher
343
+ * priority "partial" candidates into it in ascending order of priority.
344
+ * @param resource - The {@link Resources.Resource | resource} to resolve.
345
+ * @returns `Success` with the composed JsonValue if successful,
346
+ * or `Failure` with an error message if no candidates match or resolution fails.
347
+ * @public
348
+ */
349
+ resolveComposedResourceValue(resource) {
350
+ return this.resolveAllResourceCandidates(resource).onSuccess((candidates) => {
351
+ /* c8 ignore next 3 - defense in depth should never occur */
352
+ if (candidates.length === 0) {
353
+ return (0, ts_utils_1.fail)(`${resource.id}: No matching candidates found.`);
354
+ }
355
+ // Find the first full candidate and collect all partial candidates above it
356
+ let fullCandidateIndex = -1;
357
+ const partialCandidates = [];
358
+ for (let i = 0; i < candidates.length; i++) {
359
+ const candidate = candidates[i];
360
+ if (!candidate.isPartial) {
361
+ // Found the first full candidate
362
+ fullCandidateIndex = i;
363
+ break;
364
+ }
365
+ else {
366
+ // Collect partial candidates (these are in ascending priority order)
367
+ partialCandidates.unshift(candidate);
368
+ }
369
+ }
370
+ // If no full candidate found, use the last candidate as the base
371
+ const baseCandidateIndex = fullCandidateIndex >= 0 ? fullCandidateIndex : candidates.length - 1;
372
+ const baseCandidate = candidates[baseCandidateIndex];
373
+ // If there are no partial candidates to merge, return the base candidate's value
374
+ if (partialCandidates.length === 0) {
375
+ return (0, ts_utils_1.succeed)(baseCandidate.json);
376
+ }
377
+ const allCandidates = [
378
+ baseCandidate.json,
379
+ ...partialCandidates.map((candidate) => candidate.json)
380
+ ].filter((v) => (0, ts_json_base_1.isJsonObject)(v));
381
+ /* c8 ignore next 3 - defensive check: non-object values in resource candidates should be prevented at validation time */
382
+ if (allCandidates.length !== partialCandidates.length + 1) {
383
+ return (0, ts_utils_1.fail)(`${resource.id}: Unable to compose non-object candidate values.`);
384
+ }
385
+ // Create JsonEditor with array replacement behavior for resource composition
386
+ const editor = ts_json_1.JsonEditor.create({
387
+ merge: {
388
+ arrayMergeBehavior: 'replace'
389
+ }
390
+ }).orThrow(); // Should never fail with valid options
391
+ return editor
392
+ .mergeObjectsInPlace({}, allCandidates)
393
+ .withErrorFormat((err) => `${resource.id}: Composition failed: ${err}`);
394
+ });
395
+ }
396
+ /**
397
+ * Clears all caches (condition, condition set, and decision), forcing all cached items
398
+ * to be re-evaluated on next access. This should be called when the context changes and cached
399
+ * results are no longer valid.
400
+ * @public
401
+ */
402
+ clearConditionCache() {
403
+ var _a, _b, _c;
404
+ this._conditionCache.fill(undefined);
405
+ this._conditionSetCache.fill(undefined);
406
+ this._decisionCache.fill(undefined);
407
+ (_a = this._listener) === null || _a === void 0 ? void 0 : _a.onCacheClear('condition');
408
+ (_b = this._listener) === null || _b === void 0 ? void 0 : _b.onCacheClear('conditionSet');
409
+ (_c = this._listener) === null || _c === void 0 ? void 0 : _c.onCacheClear('decision');
410
+ }
411
+ /**
412
+ * Gets the current size of the condition cache array.
413
+ * @returns The size of the condition cache array.
414
+ * @public
415
+ */
416
+ get conditionCacheSize() {
417
+ return this._conditionCache.length;
418
+ }
419
+ /**
420
+ * Gets the current size of the condition set cache array.
421
+ * @returns The size of the condition set cache array.
422
+ * @public
423
+ */
424
+ get conditionSetCacheSize() {
425
+ return this._conditionSetCache.length;
426
+ }
427
+ /**
428
+ * Gets the current size of the decision cache array.
429
+ * @returns The size of the decision cache array.
430
+ * @public
431
+ */
432
+ get decisionCacheSize() {
433
+ return this._decisionCache.length;
434
+ }
435
+ }
436
+ exports.ResourceResolver = ResourceResolver;
437
+ //# sourceMappingURL=resourceResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceResolver.js","sourceRoot":"","sources":["../../../src/packlets/runtime/resourceResolver.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright (c) 2025 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { Result, captureResult, fail, succeed } from '@fgv/ts-utils';\nimport { JsonValue, JsonObject, isJsonObject } from '@fgv/ts-json-base';\nimport { JsonEditor } from '@fgv/ts-json';\nimport { NoMatch } from '../common';\nimport { Condition, ConditionSet } from '../conditions';\nimport { AbstractDecision } from '../decisions';\nimport { ReadOnlyQualifierTypeCollector } from '../qualifier-types';\nimport { IContextQualifierProvider } from './context';\nimport { IResourceManager, IResource, IResourceCandidate } from './iResourceManager';\nimport {\n ConditionMatchType,\n ConditionSetResolutionResult,\n IConditionMatchResult\n} from './conditionSetResolutionResult';\nimport { IResourceResolverCacheListener } from './cacheListener';\n\n/**\n * Represents the cached result of resolving a decision.\n * Contains either a failure indicator or a list of instance indices for matching condition sets,\n * ordered by condition set priority.\n * @public\n */\nexport type DecisionResolutionResult =\n | { success: false }\n | { success: true; instanceIndices: ReadonlyArray<number>; defaultInstanceIndices: ReadonlyArray<number> };\n\n/**\n * Parameters for creating a {@link Runtime.ResourceResolver | ResourceResolver}.\n * @public\n */\nexport interface IResourceResolverCreateParams {\n /**\n * The {@link Runtime.IResourceManager | resource manager} that defines the resources available\n * and provides access to qualifiers and conditions.\n */\n resourceManager: IResourceManager;\n\n /**\n * The {@link QualifierTypes.ReadOnlyQualifierTypeCollector | readonly qualifier type collector}\n * that provides qualifier implementations for condition evaluation.\n */\n qualifierTypes: ReadOnlyQualifierTypeCollector;\n\n /**\n * The {@link Runtime.Context.IContextQualifierProvider | context qualifier provider} that resolves\n * qualifier values for the current context.\n */\n contextQualifierProvider: IContextQualifierProvider;\n\n /**\n * An optional listener for {@link Runtime.ResourceResolver | ResourceResolver} cache activity.\n */\n listener?: IResourceResolverCacheListener;\n}\n\n/**\n * High-performance runtime resource resolver with O(1) condition caching.\n * Resolves resources for a given context by evaluating conditions against qualifier values\n * and caching results for optimal performance.\n * @public\n */\nexport class ResourceResolver {\n /**\n * The resource manager that defines available resources and provides condition access.\n */\n public readonly resourceManager: IResourceManager;\n\n /**\n * The readonly qualifier type collector that provides qualifier implementations.\n */\n public readonly qualifierTypes: ReadOnlyQualifierTypeCollector;\n\n /**\n * The context qualifier provider that resolves qualifier values.\n */\n public readonly contextQualifierProvider: IContextQualifierProvider;\n\n /**\n * The cache array for resolved conditions, indexed by condition index for O(1) lookup.\n * Each entry stores the resolved {@link Runtime.IConditionMatchResult | condition match result} for\n * the corresponding condition.\n */\n public get conditionCache(): ReadonlyArray<IConditionMatchResult | undefined> {\n return this._conditionCache;\n }\n\n /**\n * The cache array for resolved condition sets, indexed by condition set index for O(1) lookup.\n * Each entry stores the resolved ConditionSetResolutionResult for the corresponding condition set.\n */\n public get conditionSetCache(): ReadonlyArray<ConditionSetResolutionResult | undefined> {\n return this._conditionSetCache;\n }\n\n /**\n * The cache array for resolved decisions, indexed by decision index for O(1) lookup.\n * Each entry stores the resolved DecisionResolutionResult for the corresponding decision.\n */\n public get decisionCache(): ReadonlyArray<DecisionResolutionResult | undefined> {\n return this._decisionCache;\n }\n\n /**\n * Cache array for resolved conditions, indexed by condition index for O(1) lookup.\n * Each entry stores the resolved QualifierMatchScore for the corresponding condition.\n */\n private readonly _conditionCache: Array<IConditionMatchResult | undefined>;\n\n /**\n * Cache array for resolved condition sets, indexed by condition set index for O(1) lookup.\n * Each entry stores the resolved ConditionSetResolutionResult for the corresponding condition set.\n */\n private readonly _conditionSetCache: Array<ConditionSetResolutionResult | undefined>;\n\n /**\n * Cache array for resolved decisions, indexed by decision index for O(1) lookup.\n * Each entry stores the resolved DecisionResolutionResult for the corresponding decision.\n */\n private readonly _decisionCache: Array<DecisionResolutionResult | undefined>;\n\n /**\n * The listener for {@link Runtime.ResourceResolver | ResourceResolver} cache activity.\n */\n private readonly _listener?: IResourceResolverCacheListener;\n\n /**\n * Constructor for a {@link Runtime.ResourceResolver | ResourceResolver} object.\n * @param params - {@link Runtime.IResourceResolverCreateParams | Parameters} used to create the resolver.\n */\n protected constructor(params: IResourceResolverCreateParams) {\n this.resourceManager = params.resourceManager;\n this.qualifierTypes = params.qualifierTypes;\n this.contextQualifierProvider = params.contextQualifierProvider;\n\n // Initialize condition cache array with size matching the condition collector\n const conditionCollectorSize = this.resourceManager.conditions.size;\n this._conditionCache = new Array<IConditionMatchResult | undefined>(conditionCollectorSize);\n\n // Initialize condition set cache array with size matching the condition set collector\n const conditionSetCollectorSize = this.resourceManager.conditionSets.size;\n this._conditionSetCache = new Array<ConditionSetResolutionResult | undefined>(conditionSetCollectorSize);\n\n // Initialize decision cache array with size matching the decision collector\n const decisionCollectorSize = this.resourceManager.decisions.size;\n this._decisionCache = new Array<DecisionResolutionResult | undefined>(decisionCollectorSize);\n\n this._listener = params.listener;\n }\n\n /**\n * Creates a new {@link Runtime.ResourceResolver | ResourceResolver} object.\n * @param params - {@link Runtime.IResourceResolverCreateParams | Parameters} used to create the resolver.\n * @returns `Success` with the new {@link Runtime.ResourceResolver | ResourceResolver} object if successful,\n * or `Failure` with an error message if not.\n * @public\n */\n public static create(params: IResourceResolverCreateParams): Result<ResourceResolver> {\n return captureResult(() => new ResourceResolver(params));\n }\n\n /**\n * Resolves a condition by evaluating it against the current context.\n * Uses O(1) caching based on the condition's globally unique sequential index.\n * @param condition - The {@link Conditions.Condition | condition} to resolve.\n * @returns `Success` with the {@link QualifierMatchScore | match score} if successful,\n * or `Failure` with an error message if the condition cannot be resolved.\n * @public\n */\n public resolveCondition(condition: Condition): Result<IConditionMatchResult> {\n // Get the condition's index for cache lookup\n const conditionIndex = condition.index;\n if (conditionIndex === undefined) {\n return fail(`Condition \"${condition.key}\" does not have a valid index`);\n }\n\n // Check cache first for O(1) lookup\n const cachedResult = this._conditionCache[conditionIndex];\n if (cachedResult !== undefined) {\n this._listener?.onCacheHit('condition', conditionIndex);\n return succeed(cachedResult);\n }\n\n // Resolve the condition by getting qualifier value and evaluating with qualifier type\n const qualifierValueResult = this.contextQualifierProvider.get(condition.qualifier);\n if (qualifierValueResult.isFailure()) {\n this._listener?.onCacheError('condition', conditionIndex);\n return fail(\n `Failed to get qualifier value for \"${condition.qualifier.name}\": ${qualifierValueResult.message}`\n );\n }\n\n const qualifierValue = qualifierValueResult.value;\n\n // Evaluate the condition using the qualifier type's matching logic\n const score = condition.qualifier.type.matches(condition.value, qualifierValue, condition.operator);\n const priority = condition.priority;\n const scoreAsDefault = condition.scoreAsDefault ?? NoMatch;\n const matchResult: IConditionMatchResult =\n score > NoMatch\n ? { score, priority, matchType: 'match' }\n : scoreAsDefault > NoMatch\n ? { score: scoreAsDefault, priority, matchType: 'matchAsDefault' }\n : { score: NoMatch, priority, matchType: 'noMatch' };\n\n // Cache the resolved value for future O(1) lookup\n this._conditionCache[conditionIndex] = matchResult;\n this._listener?.onCacheMiss('condition', conditionIndex);\n\n return succeed(matchResult);\n }\n\n /**\n * Resolves a condition set by evaluating all its constituent conditions against the current context.\n * Uses O(1) caching based on the condition set's globally unique sequential index.\n * @param conditionSet - The {@link Conditions.ConditionSet | condition set} to resolve.\n * @returns `Success` with the {@link Runtime.ConditionSetResolutionResult | resolution result} if successful,\n * or `Failure` with an error message if the condition set cannot be resolved.\n * @public\n */\n public resolveConditionSet(conditionSet: ConditionSet): Result<ConditionSetResolutionResult> {\n // Get the condition set's index for cache lookup\n const conditionSetIndex = conditionSet.index;\n if (conditionSetIndex === undefined) {\n return fail(`ConditionSet \"${conditionSet.key}\" does not have a valid index`);\n }\n\n // Check cache first for O(1) lookup\n const cachedResult = this._conditionSetCache[conditionSetIndex];\n if (cachedResult !== undefined) {\n this._listener?.onCacheHit('conditionSet', conditionSetIndex);\n return succeed(cachedResult);\n }\n\n // Resolve all conditions in the condition set\n const conditions: Array<IConditionMatchResult> = [];\n let matchType: ConditionMatchType = 'match';\n\n for (const condition of conditionSet.conditions) {\n const { value: conditionResult, message: conditionMessage } = this.resolveCondition(condition);\n\n if (conditionMessage !== undefined) {\n /* c8 ignore next 2 - defensive coding: extreme internal error scenario not reachable in normal operation */\n this._listener?.onCacheError('conditionSet', conditionSetIndex);\n return fail(`Failed to resolve condition \"${condition.key}\": ${conditionMessage}`);\n }\n\n conditions.push(conditionResult);\n\n if (conditionResult.matchType === 'noMatch') {\n // Cache the failure result\n return ConditionSetResolutionResult.create('noMatch', conditions)\n .onSuccess((result) => {\n this._conditionSetCache[conditionSetIndex] = result;\n this._listener?.onCacheMiss('conditionSet', conditionSetIndex);\n return succeed(result);\n })\n .onFailure((err) => {\n /* c8 ignore next 4 - defensive coding: extreme internal error scenario not reachable in normal operation */\n this._conditionSetCache[conditionSetIndex] = undefined;\n this._listener?.onCacheError('conditionSet', conditionSetIndex);\n return fail(`${conditionSetIndex}: error creating condition set resolution result: ${err}`);\n });\n }\n\n if (conditionResult.matchType === 'matchAsDefault') {\n matchType = 'matchAsDefault';\n }\n }\n\n // Cache the successful result\n return ConditionSetResolutionResult.create(matchType, conditions)\n .onSuccess((result) => {\n this._conditionSetCache[conditionSetIndex] = result;\n this._listener?.onCacheMiss('conditionSet', conditionSetIndex);\n return succeed(result);\n })\n .onFailure((err) => {\n /* c8 ignore next 4 - defensive coding: extreme internal error scenario not reachable in normal operation */\n this._conditionSetCache[conditionSetIndex] = undefined;\n this._listener?.onCacheError('conditionSet', conditionSetIndex);\n return fail(`${conditionSetIndex}: error creating condition set resolution result: ${err}`);\n });\n }\n\n /**\n * Resolves a decision by evaluating all its constituent condition sets against the current context.\n * Uses O(1) caching based on the decision's globally unique sequential index.\n * @param decision - The {@link Decisions.AbstractDecision | abstract decision} to resolve.\n * @returns `Success` with the {@link Runtime.DecisionResolutionResult | resolution result} if successful,\n * or `Failure` with an error message if the decision cannot be resolved.\n * @public\n */\n public resolveDecision(decision: AbstractDecision): Result<DecisionResolutionResult> {\n // Get the decision's index for cache lookup\n const decisionIndex = decision.index;\n if (decisionIndex === undefined) {\n return fail(`Decision \"${decision.key}\" does not have a valid index`);\n }\n\n // Check cache first for O(1) lookup\n const cachedResult = this._decisionCache[decisionIndex];\n if (cachedResult !== undefined) {\n this._listener?.onCacheHit('decision', decisionIndex);\n return succeed(cachedResult);\n }\n\n // Resolve all condition sets in the decision\n const matchingInstanceResults: Array<{ index: number; result: ConditionSetResolutionResult }> = [];\n const matchingDefaultInstanceResults: Array<{ index: number; result: ConditionSetResolutionResult }> = [];\n\n for (let instanceIndex = 0; instanceIndex < decision.candidates.length; instanceIndex++) {\n const candidate = decision.candidates[instanceIndex];\n const conditionSetResult = this.resolveConditionSet(candidate.conditionSet);\n\n if (conditionSetResult.isFailure()) {\n /* c8 ignore next 2 - defensive coding: extreme internal error scenario not reachable in normal operation */\n this._listener?.onCacheError('decision', decisionIndex);\n return fail(`${decision.key}: Failed to resolve condition set\": ${conditionSetResult.message}`);\n }\n\n const resolution = conditionSetResult.value;\n\n // Only include condition sets that match\n if (resolution.matchType === 'match') {\n matchingInstanceResults.push({\n index: instanceIndex,\n result: resolution\n });\n } else if (resolution.matchType === 'matchAsDefault') {\n matchingDefaultInstanceResults.push({\n index: instanceIndex,\n result: resolution\n });\n }\n // If condition set doesn't match, we simply skip it and continue (don't fail the decision)\n }\n\n // Sort by condition set resolution priority using the proper comparison logic\n matchingInstanceResults.sort((a, b) => ConditionSetResolutionResult.compare(a.result, b.result));\n matchingDefaultInstanceResults.sort((a, b) => ConditionSetResolutionResult.compare(a.result, b.result));\n\n // Extract just the instance indices in priority order\n const instanceIndices = matchingInstanceResults.map((item) => item.index);\n const defaultInstanceIndices = matchingDefaultInstanceResults.map((item) => item.index);\n\n // Cache the successful result\n const successResult: DecisionResolutionResult = {\n success: true,\n instanceIndices,\n defaultInstanceIndices\n };\n this._decisionCache[decisionIndex] = successResult;\n this._listener?.onCacheMiss('decision', decisionIndex);\n\n return succeed(successResult);\n }\n\n /**\n * Resolves a resource by finding the best matching candidate.\n * Uses the resource's associated decision to determine the best match based on the current context.\n * @param resource - The {@link Resources.Resource | resource} to resolve.\n * @returns `Success` with the best matching candidate if successful,\n * or `Failure` with an error message if no candidates match or resolution fails.\n * @public\n */\n public resolveResource(resource: IResource): Result<IResourceCandidate> {\n // Get the abstract decision from the resource's concrete decision\n const abstractDecision = resource.decision.baseDecision;\n\n // Resolve the decision to get candidate indices in priority order\n const decisionResult = this.resolveDecision(abstractDecision);\n /* c8 ignore next 3 - defense in depth almost impossible to hit */\n if (decisionResult.isFailure()) {\n return fail(`Failed to resolve decision for resource \"${resource.id}\": ${decisionResult.message}`);\n }\n\n const resolution = decisionResult.value;\n\n // Check if any candidates matched (regular or default)\n if (\n !resolution.success ||\n (resolution.instanceIndices.length === 0 && resolution.defaultInstanceIndices.length === 0)\n ) {\n return fail(`No matching candidates found for resource \"${resource.id}\"`);\n }\n\n // Prefer regular matches over default matches\n const candidateIndex =\n resolution.instanceIndices.length > 0\n ? resolution.instanceIndices[0] // Best regular match\n : resolution.defaultInstanceIndices[0]; // Best default match\n\n if (candidateIndex >= resource.candidates.length) {\n return fail(`Invalid candidate index ${candidateIndex} for resource \"${resource.id}\"`);\n }\n\n const bestCandidate = resource.candidates[candidateIndex];\n return succeed(bestCandidate);\n }\n\n /**\n * Resolves all matching resource candidates in priority order.\n * Uses the resource's associated decision to determine all matching candidates based on the current context.\n * @param resource - The {@link Resources.Resource | resource} to resolve.\n * @returns `Success` with an array of all matching candidates in priority order if successful,\n * or `Failure` with an error message if no candidates match or resolution fails.\n * @public\n */\n public resolveAllResourceCandidates(resource: IResource): Result<ReadonlyArray<IResourceCandidate>> {\n // Get the abstract decision from the resource's concrete decision\n const abstractDecision = resource.decision.baseDecision;\n\n // Resolve the decision to get candidate indices in priority order\n const decisionResult = this.resolveDecision(abstractDecision);\n /* c8 ignore next 3 - defense in depth almost impossible to hit */\n if (decisionResult.isFailure()) {\n return fail(`Failed to resolve decision for resource \"${resource.id}\": ${decisionResult.message}`);\n }\n\n const resolution = decisionResult.value;\n\n // Check if any candidates matched (regular or default)\n if (\n !resolution.success ||\n (resolution.instanceIndices.length === 0 && resolution.defaultInstanceIndices.length === 0)\n ) {\n return fail(`No matching candidates found for resource \"${resource.id}\"`);\n }\n\n // Get all matching candidates: regular matches first, then default matches\n const candidates: IResourceCandidate[] = [];\n\n // Add all regular matches first (already sorted by priority)\n for (const candidateIndex of resolution.instanceIndices) {\n if (candidateIndex >= resource.candidates.length) {\n return fail(`Invalid candidate index ${candidateIndex} for resource \"${resource.id}\"`);\n }\n const candidate = resource.candidates[candidateIndex];\n candidates.push(candidate);\n }\n\n // Add all default matches after regular matches (already sorted by priority)\n for (const candidateIndex of resolution.defaultInstanceIndices) {\n /* c8 ignore next 3 - defensive coding: extreme internal error scenario not reachable in normal operation */\n if (candidateIndex >= resource.candidates.length) {\n return fail(`Invalid candidate index ${candidateIndex} for resource \"${resource.id}\"`);\n }\n const candidate = resource.candidates[candidateIndex];\n candidates.push(candidate);\n }\n\n return succeed(candidates);\n }\n\n /**\n * Resolves a resource to a composed value by merging matching candidates according to their merge methods.\n * Starting from the highest priority candidates, finds the first \"full\" candidate and merges all higher\n * priority \"partial\" candidates into it in ascending order of priority.\n * @param resource - The {@link Resources.Resource | resource} to resolve.\n * @returns `Success` with the composed JsonValue if successful,\n * or `Failure` with an error message if no candidates match or resolution fails.\n * @public\n */\n public resolveComposedResourceValue(resource: IResource): Result<JsonValue> {\n return this.resolveAllResourceCandidates(resource).onSuccess((candidates) => {\n /* c8 ignore next 3 - defense in depth should never occur */\n if (candidates.length === 0) {\n return fail(`${resource.id}: No matching candidates found.`);\n }\n\n // Find the first full candidate and collect all partial candidates above it\n let fullCandidateIndex = -1;\n const partialCandidates: IResourceCandidate[] = [];\n\n for (let i = 0; i < candidates.length; i++) {\n const candidate = candidates[i];\n if (!candidate.isPartial) {\n // Found the first full candidate\n fullCandidateIndex = i;\n break;\n } else {\n // Collect partial candidates (these are in ascending priority order)\n partialCandidates.unshift(candidate);\n }\n }\n\n // If no full candidate found, use the last candidate as the base\n const baseCandidateIndex = fullCandidateIndex >= 0 ? fullCandidateIndex : candidates.length - 1;\n const baseCandidate = candidates[baseCandidateIndex];\n\n // If there are no partial candidates to merge, return the base candidate's value\n if (partialCandidates.length === 0) {\n return succeed(baseCandidate.json);\n }\n\n const allCandidates = [\n baseCandidate.json,\n ...partialCandidates.map((candidate) => candidate.json)\n ].filter((v): v is JsonObject => isJsonObject(v));\n\n /* c8 ignore next 3 - defensive check: non-object values in resource candidates should be prevented at validation time */\n if (allCandidates.length !== partialCandidates.length + 1) {\n return fail(`${resource.id}: Unable to compose non-object candidate values.`);\n }\n\n // Create JsonEditor with array replacement behavior for resource composition\n const editor = JsonEditor.create({\n merge: {\n arrayMergeBehavior: 'replace'\n }\n }).orThrow(); // Should never fail with valid options\n\n return editor\n .mergeObjectsInPlace({}, allCandidates)\n .withErrorFormat((err) => `${resource.id}: Composition failed: ${err}`);\n });\n }\n\n /**\n * Clears all caches (condition, condition set, and decision), forcing all cached items\n * to be re-evaluated on next access. This should be called when the context changes and cached\n * results are no longer valid.\n * @public\n */\n public clearConditionCache(): void {\n this._conditionCache.fill(undefined);\n this._conditionSetCache.fill(undefined);\n this._decisionCache.fill(undefined);\n\n this._listener?.onCacheClear('condition');\n this._listener?.onCacheClear('conditionSet');\n this._listener?.onCacheClear('decision');\n }\n\n /**\n * Gets the current size of the condition cache array.\n * @returns The size of the condition cache array.\n * @public\n */\n public get conditionCacheSize(): number {\n return this._conditionCache.length;\n }\n\n /**\n * Gets the current size of the condition set cache array.\n * @returns The size of the condition set cache array.\n * @public\n */\n public get conditionSetCacheSize(): number {\n return this._conditionSetCache.length;\n }\n\n /**\n * Gets the current size of the decision cache array.\n * @returns The size of the decision cache array.\n * @public\n */\n public get decisionCacheSize(): number {\n return this._decisionCache.length;\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { Validator } from '@fgv/ts-utils';
2
+ import { IResource, IResourceCandidate } from './iResourceManager';
3
+ /**
4
+ * Validates an {@link Runtime.IResourceCandidate | IResourceCandidate} object.
5
+ * @public
6
+ */
7
+ export declare const resourceCandidate: Validator<IResourceCandidate, unknown>;
8
+ /**
9
+ * Validates an {@link Runtime.IResource | IResource} object.
10
+ * @public
11
+ */
12
+ export declare const resource: Validator<IResource, unknown>;
13
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/packlets/runtime/validate.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAc,SAAS,EAAE,MAAM,eAAe,CAAC;AAKtD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,kBAAkB,EAAE,OAAO,CAQjE,CAAC;AAEL;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,SAAS,CAAC,SAAS,EAAE,OAAO,CAWjD,CAAC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2025 Erik Fortune
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be included in all
13
+ * copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ * SOFTWARE.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.resource = exports.resourceCandidate = void 0;
25
+ const ts_utils_1 = require("@fgv/ts-utils");
26
+ const ts_json_base_1 = require("@fgv/ts-json-base");
27
+ const common_1 = require("../common");
28
+ const resource_types_1 = require("../resource-types");
29
+ const decisions_1 = require("../decisions");
30
+ /**
31
+ * Validates an {@link Runtime.IResourceCandidate | IResourceCandidate} object.
32
+ * @public
33
+ */
34
+ exports.resourceCandidate = ts_utils_1.Validators.object({
35
+ json: ts_json_base_1.Validators.jsonObject,
36
+ isPartial: ts_utils_1.Validators.boolean,
37
+ mergeMethod: ts_utils_1.Validators.isA('resource value merge method', (v) => v === 'augment' || v === 'delete' || v === 'replace')
38
+ });
39
+ /**
40
+ * Validates an {@link Runtime.IResource | IResource} object.
41
+ * @public
42
+ */
43
+ exports.resource = ts_utils_1.Validators.object({
44
+ id: ts_utils_1.Validators.isA('ResourceId', (v) => typeof v === 'string' && common_1.Validate.isValidResourceId(v)),
45
+ resourceType: ts_utils_1.Validators.isA('ResourceType instance', (v) => v instanceof resource_types_1.ResourceType),
46
+ decision: ts_utils_1.Validators.isA('ConcreteDecision instance', (v) => v instanceof decisions_1.ConcreteDecision),
47
+ candidates: ts_utils_1.Validators.arrayOf(exports.resourceCandidate)
48
+ });
49
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/packlets/runtime/validate.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAEH,4CAAsD;AACtD,oDAAiE;AACjE,sCAAiD;AACjD,sDAAiD;AACjD,4CAAgD;AAGhD;;;GAGG;AACU,QAAA,iBAAiB,GAC5B,qBAAU,CAAC,MAAM,CAAqB;IACpC,IAAI,EAAE,yBAAc,CAAC,UAAU;IAC/B,SAAS,EAAE,qBAAU,CAAC,OAAO;IAC7B,WAAW,EAAE,qBAAU,CAAC,GAAG,CACzB,6BAA6B,EAC7B,CAAC,CAAC,EAAyC,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,SAAS,CACnG;CACF,CAAC,CAAC;AAEL;;;GAGG;AACU,QAAA,QAAQ,GAAkC,qBAAU,CAAC,MAAM,CAAY;IAClF,EAAE,EAAE,qBAAU,CAAC,GAAG,CAChB,YAAY,EACZ,CAAC,CAAC,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,iBAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAC/E;IACD,YAAY,EAAE,qBAAU,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,YAAY,6BAAY,CAAC;IAC1G,QAAQ,EAAE,qBAAU,CAAC,GAAG,CACtB,2BAA2B,EAC3B,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,YAAY,4BAAgB,CAC5D;IACD,UAAU,EAAE,qBAAU,CAAC,OAAO,CAAC,yBAAiB,CAAC;CAClD,CAAC,CAAC","sourcesContent":["/*\n * Copyright (c) 2025 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { Validators, Validator } from '@fgv/ts-utils';\nimport { Validators as JsonValidators } from '@fgv/ts-json-base';\nimport { Validate, ResourceId } from '../common';\nimport { ResourceType } from '../resource-types';\nimport { ConcreteDecision } from '../decisions';\nimport { IResource, IResourceCandidate } from './iResourceManager';\n\n/**\n * Validates an {@link Runtime.IResourceCandidate | IResourceCandidate} object.\n * @public\n */\nexport const resourceCandidate: Validator<IResourceCandidate, unknown> =\n Validators.object<IResourceCandidate>({\n json: JsonValidators.jsonObject,\n isPartial: Validators.boolean,\n mergeMethod: Validators.isA(\n 'resource value merge method',\n (v): v is 'augment' | 'delete' | 'replace' => v === 'augment' || v === 'delete' || v === 'replace'\n )\n });\n\n/**\n * Validates an {@link Runtime.IResource | IResource} object.\n * @public\n */\nexport const resource: Validator<IResource, unknown> = Validators.object<IResource>({\n id: Validators.isA(\n 'ResourceId',\n (v): v is ResourceId => typeof v === 'string' && Validate.isValidResourceId(v)\n ),\n resourceType: Validators.isA('ResourceType instance', (v): v is ResourceType => v instanceof ResourceType),\n decision: Validators.isA(\n 'ConcreteDecision instance',\n (v): v is ConcreteDecision => v instanceof ConcreteDecision\n ),\n candidates: Validators.arrayOf(resourceCandidate)\n});\n"]}