@roster-lock/shared 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/LICENSE.md +11 -0
  2. package/dist/index.js +19 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/match-lock-file/config-types.js +3 -0
  5. package/dist/match-lock-file/config-types.js.map +1 -0
  6. package/dist/match-lock-file/index.js +19 -0
  7. package/dist/match-lock-file/index.js.map +1 -0
  8. package/dist/match-lock-file/match-config/index.js +18 -0
  9. package/dist/match-lock-file/match-config/index.js.map +1 -0
  10. package/dist/match-lock-file/match-config/version-1/draft/index.js +44 -0
  11. package/dist/match-lock-file/match-config/version-1/draft/index.js.map +1 -0
  12. package/dist/match-lock-file/match-config/version-1/draft/roster-piece-info.js +32 -0
  13. package/dist/match-lock-file/match-config/version-1/draft/roster-piece-info.js.map +1 -0
  14. package/dist/match-lock-file/match-config/version-1/draft/selection-script-info.js +13 -0
  15. package/dist/match-lock-file/match-config/version-1/draft/selection-script-info.js.map +1 -0
  16. package/dist/match-lock-file/match-config/version-1/index.js +22 -0
  17. package/dist/match-lock-file/match-config/version-1/index.js.map +1 -0
  18. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.js +37 -0
  19. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.js.map +1 -0
  20. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.js +43 -0
  21. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.js.map +1 -0
  22. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.js +7 -0
  23. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.js.map +1 -0
  24. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.js +41 -0
  25. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.js.map +1 -0
  26. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.js +20 -0
  27. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.js.map +1 -0
  28. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.js +31 -0
  29. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.js.map +1 -0
  30. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.js +40 -0
  31. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.js.map +1 -0
  32. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.js +17 -0
  33. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.js.map +1 -0
  34. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.js +16 -0
  35. package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.js.map +1 -0
  36. package/dist/match-lock-file/match-config/version-1/lock/engine/index.js +19 -0
  37. package/dist/match-lock-file/match-config/version-1/lock/engine/index.js.map +1 -0
  38. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/error.js +25 -0
  39. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/error.js.map +1 -0
  40. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/index.js +33 -0
  41. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/index.js.map +1 -0
  42. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.js +31 -0
  43. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.js.map +1 -0
  44. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.js +37 -0
  45. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.js.map +1 -0
  46. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.js +22 -0
  47. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.js.map +1 -0
  48. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.js +24 -0
  49. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.js.map +1 -0
  50. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.js +39 -0
  51. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.js.map +1 -0
  52. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.js +46 -0
  53. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.js.map +1 -0
  54. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.js +23 -0
  55. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.js.map +1 -0
  56. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.js +99 -0
  57. package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.js.map +1 -0
  58. package/dist/match-lock-file/match-config/version-1/lock/index.js +56 -0
  59. package/dist/match-lock-file/match-config/version-1/lock/index.js.map +1 -0
  60. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.js +87 -0
  61. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.js.map +1 -0
  62. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/index.js +19 -0
  63. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/index.js.map +1 -0
  64. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.js +94 -0
  65. package/dist/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.js.map +1 -0
  66. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.js +18 -0
  67. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.js.map +1 -0
  68. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.js +28 -0
  69. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.js.map +1 -0
  70. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.js +31 -0
  71. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.js.map +1 -0
  72. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.js +68 -0
  73. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.js.map +1 -0
  74. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.js +49 -0
  75. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.js.map +1 -0
  76. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.js +62 -0
  77. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.js.map +1 -0
  78. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.js +21 -0
  79. package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.js.map +1 -0
  80. package/dist/match-lock-file/match-config/version-1/lock/rosters/index.js +19 -0
  81. package/dist/match-lock-file/match-config/version-1/lock/rosters/index.js.map +1 -0
  82. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.js +10 -0
  83. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.js.map +1 -0
  84. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/human.js +27 -0
  85. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/human.js.map +1 -0
  86. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/id.js +27 -0
  87. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/id.js.map +1 -0
  88. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/index.js +74 -0
  89. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/index.js.map +1 -0
  90. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.js +31 -0
  91. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.js.map +1 -0
  92. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.js +25 -0
  93. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.js.map +1 -0
  94. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/utils.js +23 -0
  95. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/utils.js.map +1 -0
  96. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/version.js +19 -0
  97. package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/version.js.map +1 -0
  98. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.js +42 -0
  99. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.js.map +1 -0
  100. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.js +46 -0
  101. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.js.map +1 -0
  102. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.js +12 -0
  103. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.js.map +1 -0
  104. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.js +49 -0
  105. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.js.map +1 -0
  106. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.js +32 -0
  107. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.js.map +1 -0
  108. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.js +12 -0
  109. package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.js.map +1 -0
  110. package/dist/match-lock-file/match-config/version-1/lock/selection/index.js +19 -0
  111. package/dist/match-lock-file/match-config/version-1/lock/selection/index.js.map +1 -0
  112. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/index.js +33 -0
  113. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/index.js.map +1 -0
  114. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/script.js +23 -0
  115. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/script.js.map +1 -0
  116. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.js +49 -0
  117. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.js.map +1 -0
  118. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.js +14 -0
  119. package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.js.map +1 -0
  120. package/dist/match-lock-file/match-config/version-1/piece-info/file-paths.js +5 -0
  121. package/dist/match-lock-file/match-config/version-1/piece-info/file-paths.js.map +1 -0
  122. package/dist/match-lock-file/match-config/version-1/piece-info/index.js +23 -0
  123. package/dist/match-lock-file/match-config/version-1/piece-info/index.js.map +1 -0
  124. package/dist/match-lock-file/match-config/version-1/piece-info/keywords.js +29 -0
  125. package/dist/match-lock-file/match-config/version-1/piece-info/keywords.js.map +1 -0
  126. package/dist/match-lock-file/match-config/version-1/piece-info/schema.js +19 -0
  127. package/dist/match-lock-file/match-config/version-1/piece-info/schema.js.map +1 -0
  128. package/dist/match-lock-file/match-config/version-1/shared/Identity.js +15 -0
  129. package/dist/match-lock-file/match-config/version-1/shared/Identity.js.map +1 -0
  130. package/dist/match-lock-file/match-config/version-1/shared/SelectedPiece.js +38 -0
  131. package/dist/match-lock-file/match-config/version-1/shared/SelectedPiece.js.map +1 -0
  132. package/dist/match-lock-file/match-config/version-1/shared/count.js +48 -0
  133. package/dist/match-lock-file/match-config/version-1/shared/count.js.map +1 -0
  134. package/dist/match-lock-file/match-config/version-1/shared/index.js +25 -0
  135. package/dist/match-lock-file/match-config/version-1/shared/index.js.map +1 -0
  136. package/dist/match-lock-file/match-config/version-1/usage/calculatePieceVersion.js +70 -0
  137. package/dist/match-lock-file/match-config/version-1/usage/calculatePieceVersion.js.map +1 -0
  138. package/dist/match-lock-file/match-config/version-1/usage/empty-configs.js +49 -0
  139. package/dist/match-lock-file/match-config/version-1/usage/empty-configs.js.map +1 -0
  140. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/constants.js +8 -0
  141. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/constants.js.map +1 -0
  142. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.js +75 -0
  143. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.js.map +1 -0
  144. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.js +28 -0
  145. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.js.map +1 -0
  146. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/index.js +20 -0
  147. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/index.js.map +1 -0
  148. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/types.js +3 -0
  149. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/types.js.map +1 -0
  150. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.js +33 -0
  151. package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.js.map +1 -0
  152. package/dist/match-lock-file/match-config/version-1/usage/index.js +22 -0
  153. package/dist/match-lock-file/match-config/version-1/usage/index.js.map +1 -0
  154. package/dist/match-lock-file/match-config/version-1/usage/publish/SemVer.js +63 -0
  155. package/dist/match-lock-file/match-config/version-1/usage/publish/SemVer.js.map +1 -0
  156. package/dist/match-lock-file/match-config/version-1/usage/publish/diffLocks.js +51 -0
  157. package/dist/match-lock-file/match-config/version-1/usage/publish/diffLocks.js.map +1 -0
  158. package/dist/match-lock-file/match-config/version-1/usage/publish/index.js +19 -0
  159. package/dist/match-lock-file/match-config/version-1/usage/publish/index.js.map +1 -0
  160. package/dist/match-lock-file/match-config/version-1/usage/validate-select/constants.js +14 -0
  161. package/dist/match-lock-file/match-config/version-1/usage/validate-select/constants.js.map +1 -0
  162. package/dist/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.js +53 -0
  163. package/dist/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.js.map +1 -0
  164. package/dist/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.js +49 -0
  165. package/dist/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.js.map +1 -0
  166. package/dist/match-lock-file/match-config/version-1/usage/validate-select/index.js +68 -0
  167. package/dist/match-lock-file/match-config/version-1/usage/validate-select/index.js.map +1 -0
  168. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.js +38 -0
  169. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.js.map +1 -0
  170. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.js +40 -0
  171. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.js.map +1 -0
  172. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.js +78 -0
  173. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.js.map +1 -0
  174. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.js +43 -0
  175. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.js.map +1 -0
  176. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.js +26 -0
  177. package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.js.map +1 -0
  178. package/dist/match-lock-file/util-types/json-schema/JSONSchemaCaster.js +45 -0
  179. package/dist/match-lock-file/util-types/json-schema/JSONSchemaCaster.js.map +1 -0
  180. package/dist/match-lock-file/util-types/json-schema/defineKeyword.js +30 -0
  181. package/dist/match-lock-file/util-types/json-schema/defineKeyword.js.map +1 -0
  182. package/dist/match-lock-file/util-types/json-schema/index.js +21 -0
  183. package/dist/match-lock-file/util-types/json-schema/index.js.map +1 -0
  184. package/dist/match-lock-file/util-types/json-schema/safe-keyword.js +3 -0
  185. package/dist/match-lock-file/util-types/json-schema/safe-keyword.js.map +1 -0
  186. package/dist/match-lock-file/util-types/json-schema/schema-types.js +3 -0
  187. package/dist/match-lock-file/util-types/json-schema/schema-types.js.map +1 -0
  188. package/package.json +49 -0
  189. package/src/index.ts +3 -0
  190. package/src/match-lock-file/config-types.ts +10 -0
  191. package/src/match-lock-file/index.ts +4 -0
  192. package/src/match-lock-file/match-config/index.ts +2 -0
  193. package/src/match-lock-file/match-config/version-0/pieces/caster-runtypes/index.ts +99 -0
  194. package/src/match-lock-file/match-config/version-0/pieces/caster-runtypes/util-casters.ts +155 -0
  195. package/src/match-lock-file/match-config/version-0/pieces/index.ts +3 -0
  196. package/src/match-lock-file/match-config/version-0/pieces/types.ts +49 -0
  197. package/src/match-lock-file/match-config/version-0/pieces/validate/definition/assetCount.ts +33 -0
  198. package/src/match-lock-file/match-config/version-0/pieces/validate/definition/assetType.ts +22 -0
  199. package/src/match-lock-file/match-config/version-0/pieces/validate/definition/index.ts +30 -0
  200. package/src/match-lock-file/match-config/version-0/pieces/validate/definition/pathVariables.ts +39 -0
  201. package/src/match-lock-file/match-config/version-0/pieces/validate/index.ts +4 -0
  202. package/src/match-lock-file/match-config/version-0/pieces/validate/sha.ts +23 -0
  203. package/src/match-lock-file/match-config/version-0/pieces/validate/version.ts +66 -0
  204. package/src/match-lock-file/match-config/version-0/restriction/casters.ts +52 -0
  205. package/src/match-lock-file/match-config/version-0/restriction/index.ts +4 -0
  206. package/src/match-lock-file/match-config/version-0/restriction/types.ts +42 -0
  207. package/src/match-lock-file/match-config/version-0/restriction/validate/index.ts +15 -0
  208. package/src/match-lock-file/match-config/version-0/restriction/validate/piece/index.ts +46 -0
  209. package/src/match-lock-file/match-config/version-0/restriction/validate/sha.ts +19 -0
  210. package/src/match-lock-file/match-config/version-0/selection/casters.ts +105 -0
  211. package/src/match-lock-file/match-config/version-0/selection/validate/count.ts +16 -0
  212. package/src/match-lock-file/match-config/version-0/selection/validate/index.ts +40 -0
  213. package/src/match-lock-file/match-config/version-0/selection/validate/scriptMeta.ts +26 -0
  214. package/src/match-lock-file/match-config/version-1/draft/index.ts +52 -0
  215. package/src/match-lock-file/match-config/version-1/draft/roster-piece-info.ts +33 -0
  216. package/src/match-lock-file/match-config/version-1/draft/selection-script-info.ts +16 -0
  217. package/src/match-lock-file/match-config/version-1/index.ts +7 -0
  218. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.ts +46 -0
  219. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.ts +48 -0
  220. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.ts +6 -0
  221. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.ts +42 -0
  222. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.ts +26 -0
  223. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.ts +34 -0
  224. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.ts +47 -0
  225. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.ts +22 -0
  226. package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.ts +14 -0
  227. package/src/match-lock-file/match-config/version-1/lock/engine/index.ts +3 -0
  228. package/src/match-lock-file/match-config/version-1/lock/engine/validate/constants.ts +7 -0
  229. package/src/match-lock-file/match-config/version-1/lock/engine/validate/error.ts +21 -0
  230. package/src/match-lock-file/match-config/version-1/lock/engine/validate/index.ts +18 -0
  231. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.ts +41 -0
  232. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.ts +55 -0
  233. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.ts +21 -0
  234. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.ts +28 -0
  235. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.ts +46 -0
  236. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.ts +37 -0
  237. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.ts +21 -0
  238. package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.ts +117 -0
  239. package/src/match-lock-file/match-config/version-1/lock/index.ts +51 -0
  240. package/src/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.ts +97 -0
  241. package/src/match-lock-file/match-config/version-1/lock/piece-meta/index.ts +3 -0
  242. package/src/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.ts +114 -0
  243. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.ts +25 -0
  244. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.ts +33 -0
  245. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.ts +33 -0
  246. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.ts +103 -0
  247. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.ts +59 -0
  248. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.ts +71 -0
  249. package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.ts +22 -0
  250. package/src/match-lock-file/match-config/version-1/lock/rosters/index.ts +3 -0
  251. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.ts +9 -0
  252. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/human.ts +22 -0
  253. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/id.ts +20 -0
  254. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/index.ts +83 -0
  255. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.ts +40 -0
  256. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.ts +30 -0
  257. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/utils.ts +17 -0
  258. package/src/match-lock-file/match-config/version-1/lock/rosters/validate/version.ts +22 -0
  259. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.ts +53 -0
  260. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.ts +54 -0
  261. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.ts +11 -0
  262. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.ts +58 -0
  263. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.ts +37 -0
  264. package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.ts +11 -0
  265. package/src/match-lock-file/match-config/version-1/lock/selection/index.ts +3 -0
  266. package/src/match-lock-file/match-config/version-1/lock/selection/validate/index.ts +37 -0
  267. package/src/match-lock-file/match-config/version-1/lock/selection/validate/script.ts +28 -0
  268. package/src/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.ts +69 -0
  269. package/src/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.ts +18 -0
  270. package/src/match-lock-file/match-config/version-1/piece-info/file-paths.ts +2 -0
  271. package/src/match-lock-file/match-config/version-1/piece-info/index.ts +14 -0
  272. package/src/match-lock-file/match-config/version-1/piece-info/keywords.ts +39 -0
  273. package/src/match-lock-file/match-config/version-1/piece-info/schema.ts +29 -0
  274. package/src/match-lock-file/match-config/version-1/shared/Identity.ts +14 -0
  275. package/src/match-lock-file/match-config/version-1/shared/SelectedPiece.ts +49 -0
  276. package/src/match-lock-file/match-config/version-1/shared/count.ts +47 -0
  277. package/src/match-lock-file/match-config/version-1/shared/index.ts +9 -0
  278. package/src/match-lock-file/match-config/version-1/usage/calculatePieceVersion.ts +85 -0
  279. package/src/match-lock-file/match-config/version-1/usage/empty-configs.ts +61 -0
  280. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/constants.ts +6 -0
  281. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.ts +88 -0
  282. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.ts +42 -0
  283. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/index.ts +4 -0
  284. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/types.ts +5 -0
  285. package/src/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.ts +34 -0
  286. package/src/match-lock-file/match-config/version-1/usage/index.ts +6 -0
  287. package/src/match-lock-file/match-config/version-1/usage/publish/SemVer.ts +67 -0
  288. package/src/match-lock-file/match-config/version-1/usage/publish/diffLocks.ts +66 -0
  289. package/src/match-lock-file/match-config/version-1/usage/publish/index.ts +2 -0
  290. package/src/match-lock-file/match-config/version-1/usage/validate-select/constants.ts +9 -0
  291. package/src/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.ts +61 -0
  292. package/src/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.ts +54 -0
  293. package/src/match-lock-file/match-config/version-1/usage/validate-select/index.ts +98 -0
  294. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.ts +49 -0
  295. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.ts +39 -0
  296. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/include-mandatory-require.ts +44 -0
  297. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.ts +101 -0
  298. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.ts +51 -0
  299. package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.ts +36 -0
  300. package/src/match-lock-file/util-types/json-schema/JSONSchemaCaster.ts +52 -0
  301. package/src/match-lock-file/util-types/json-schema/checkVersion.ts +9 -0
  302. package/src/match-lock-file/util-types/json-schema/defineKeyword.ts +50 -0
  303. package/src/match-lock-file/util-types/json-schema/index.ts +4 -0
  304. package/src/match-lock-file/util-types/json-schema/safe-keyword.ts +27 -0
  305. package/src/match-lock-file/util-types/json-schema/schema-types.ts +5 -0
  306. package/tests/engine/assets.spec.ts +147 -0
  307. package/tests/engine/official-selections.spec.ts +67 -0
  308. package/tests/engine/requirements.spec.ts +43 -0
  309. package/tests/piece-info/cast.spec.ts +20 -0
  310. package/tests/piece-info/rosterlock.piece-info.json +15 -0
  311. package/tests/piece-meta/cast.spec.ts +60 -0
  312. package/tests/rosters/path-variables.spec.ts +52 -0
  313. package/tests/selection/cast-result.spec.ts +72 -0
  314. package/tsconfig.json +20 -0
@@ -0,0 +1,47 @@
1
+ import { JSONSchemaType } from "ajv";
2
+ import { RosterLockV1Config } from "@roster-lock/types";
3
+ type RosterLockEngineConfig = RosterLockV1Config["engine"];
4
+
5
+
6
+ import { assetsSchema, assetKeywords } from "./asset";
7
+ import { requirementsSchema, requirementKeywords } from "./requirements";
8
+ import { pathVariablesSchema, pathVariableKeywords } from "./variables";
9
+ import { officialSelectionsSchema, officialSelectionsKeywords } from "./officialSelections";
10
+
11
+ const pieceDefinitionSchema: JSONSchemaType<
12
+ RosterLockEngineConfig["pieceDefinitions"][string]
13
+ > = {
14
+ type: "object",
15
+ required: ["selectionStrategy", "requires", "pathVariables", "assets"],
16
+ additionalProperties: false,
17
+ properties: {
18
+ selectionStrategy: { type: "string", enum: ["mandatory", "personal", "shared", "on demand"] },
19
+ pathVariables: pathVariablesSchema,
20
+ requires: requirementsSchema,
21
+ assets: assetsSchema,
22
+ },
23
+ }
24
+
25
+ export const engineSchema: JSONSchemaType<RosterLockEngineConfig> = {
26
+ type: "object",
27
+ required: ["name", "version", "pieceDefinitions"],
28
+ additionalProperties: false,
29
+ properties: {
30
+ name: { type: "string" },
31
+ version: { type: "string" },
32
+ pieceDefinitions: {
33
+ type: "object",
34
+ required: [],
35
+ additionalProperties: pieceDefinitionSchema
36
+ },
37
+ officialSelections: { ...officialSelectionsSchema, nullable: true },
38
+ }
39
+ }
40
+
41
+ export const engineKeywords = [
42
+ ...pathVariableKeywords,
43
+ ...requirementKeywords,
44
+ ...assetKeywords,
45
+ ...officialSelectionsKeywords,
46
+ ]
47
+
@@ -0,0 +1,22 @@
1
+
2
+ import { JSONSchemaType } from "ajv";
3
+ import { pathVariableListSchemaValidator, pathVariableNameSchemaValidator } from "./keywords";
4
+ import { RosterLockV1Config } from "@roster-lock/types";
5
+ type RosterLockEngineConfig = RosterLockV1Config["engine"];
6
+
7
+ export const pathVariableKeywords = [
8
+ pathVariableListSchemaValidator,
9
+ pathVariableNameSchemaValidator,
10
+ ]
11
+
12
+
13
+ export const pathVariablesSchema: JSONSchemaType<
14
+ RosterLockEngineConfig["pieceDefinitions"][string]["pathVariables"]
15
+ > = {
16
+ [pathVariableListSchemaValidator.keyword]: true,
17
+ type: "array",
18
+ items: {
19
+ [pathVariableNameSchemaValidator.keyword]: true,
20
+ type: "string",
21
+ },
22
+ }
@@ -0,0 +1,14 @@
1
+ import { defineKeyword } from "../../../../../../util-types/json-schema";
2
+
3
+ import { validatePathVariables, validatePathVariableName } from "../../validate/piece/path-variables";
4
+ export const pathVariableListSchemaValidator = defineKeyword({
5
+ keyword: "enginePathVariableList",
6
+ type: "array",
7
+ validate: validatePathVariables
8
+ })
9
+
10
+ export const pathVariableNameSchemaValidator = defineKeyword({
11
+ keyword: "enginePathVariableName",
12
+ type: "string",
13
+ validate: validatePathVariableName
14
+ })
@@ -0,0 +1,3 @@
1
+
2
+ export * from "./validate";
3
+ export * from "./caster-json-schema";
@@ -0,0 +1,7 @@
1
+
2
+
3
+ export class ShouldntHappenError extends Error {
4
+ constructor(message: string){
5
+ super(message);
6
+ }
7
+ }
@@ -0,0 +1,21 @@
1
+
2
+
3
+ export class ValidationErrorPath extends Error {
4
+ path = "/";
5
+ constructor(message: string){
6
+ super(message);
7
+ }
8
+ addPathPrefix(part: string){
9
+ this.path = `/${part}${this.path}`;
10
+ }
11
+ addPathSuffix(part: string){
12
+ this.path = `${this.path}/${part}`;
13
+ }
14
+ static convertError(e: unknown){
15
+ if(!(e instanceof Error)) throw e;
16
+ if(!(e instanceof ValidationErrorPath)){
17
+ e = new ValidationErrorPath(e.message);
18
+ }
19
+ return e as ValidationErrorPath;
20
+ }
21
+ }
@@ -0,0 +1,18 @@
1
+
2
+ import { validatePieceDefinition } from "./piece";
3
+ import { RosterLockV1Config } from "@roster-lock/types";
4
+
5
+ export * from "./piece";
6
+ import { ValidationErrorPath } from "./error";
7
+
8
+ export function validateEngineConfig(engine: RosterLockV1Config["engine"]){
9
+ for(const [pieceType, definition] of Object.entries(engine.pieceDefinitions)){
10
+ try {
11
+ validatePieceDefinition(pieceType, definition, engine);
12
+ }catch(e){
13
+ const eTyped = ValidationErrorPath.convertError(e);
14
+ eTyped.addPathPrefix(`pieceDefinitions/${pieceType}`);
15
+ throw e;
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,41 @@
1
+
2
+ const WINDOWS_RESERVED_NAMES = [
3
+ 'CON', 'PRN', 'AUX', 'NUL',
4
+ 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
5
+ 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
6
+ ];
7
+
8
+ export function isValidPathComponent(component: string) {
9
+ // Empty components are invalid
10
+ if(component.length === 0){
11
+ throw new Error("Filepath component is empty");
12
+ }
13
+
14
+ // Check component length (most filesystems have per-component limits)
15
+ if(component.length > 255){
16
+ throw new Error("Filepath component is too long");
17
+ }
18
+
19
+ // Reserved names on Windows (even on other platforms, better to be safe)
20
+ const upperComponent = component.toUpperCase();
21
+ const baseName = upperComponent.split('.')[0]; // Remove extension for check
22
+ if(WINDOWS_RESERVED_NAMES.includes(baseName)){
23
+ throw new Error("Filepath component is a reserved name");
24
+ }
25
+
26
+ // Must not start or end with spaces (problematic on Windows)
27
+ // Note: Leading dots are actually valid (hidden files on Unix)
28
+ if(component.startsWith(' ') || component.endsWith(' ')){
29
+ throw new Error("Filepath component has leading/trailing spaces");
30
+ }
31
+
32
+ // Must not end with dots (problematic on Windows)
33
+ if(component.endsWith('.')){
34
+ throw new Error("Filepath component ends with a dot");
35
+ }
36
+
37
+ // Must not be just dots
38
+ if(/^\.+$/.test(component)){
39
+ throw new Error("Filepath component is just dots");
40
+ }
41
+ }
@@ -0,0 +1,55 @@
1
+
2
+ import { isValidPathComponent } from "./filepath-component";
3
+ export function isValidFilePath(path: string) {
4
+ // Comprehensive validation for file paths
5
+ if(path.length === 0){
6
+ throw new Error("Filepath is empty");
7
+ }
8
+
9
+ // Check path length limits (most filesystems have limits)
10
+ if(path.length > 4096){
11
+ throw new Error("Filepath is too long");
12
+ }
13
+
14
+ // Only forward slashes allowed - reject backslashes for cross-platform consistency
15
+ if(path.includes('\\')){
16
+ throw new Error("Filepath contains backslash - use forward slashes only");
17
+ }
18
+
19
+ // Check for invalid characters across different platforms
20
+ // Windows: < > : " | ? * and control characters (0x00-0x1f)
21
+ // Unix/Linux: null character (0x00) and forward slash in filenames
22
+ // We'll be restrictive and block characters that are problematic on any major platform
23
+ const invalidChars = /[<>:"|?*\x00-\x1f\x7f]/;
24
+ if(invalidChars.test(path)){
25
+ throw new Error("Filepath contains invalid characters");
26
+ }
27
+
28
+ // Check for relative path traversal attempts
29
+ if(
30
+ path.includes('../') ||
31
+ path.includes('/..') ||
32
+ path === '..' ||
33
+ path.startsWith('../') ||
34
+ path.endsWith('/..')
35
+ ){
36
+ throw new Error("Filepath contains invalid traversal");
37
+ }
38
+
39
+ // Must not end with a slash (indicating a directory)
40
+ if(path.endsWith('/')){
41
+ throw new Error("Filepath ends with a slash");
42
+ }
43
+
44
+ // Split into path components and validate each
45
+ const components = path.split('/');
46
+ for(const component of components){
47
+ isValidPathComponent(component);
48
+ }
49
+
50
+ // Must have at least one component (the filename)
51
+ if(components.length === 0){
52
+ throw new Error("Filepath has no components");
53
+ }
54
+ }
55
+
@@ -0,0 +1,21 @@
1
+ import isGlob from "is-glob";
2
+
3
+ export { validatePathVariablesInGlob } from "./pathvariables";
4
+ import { replacePathVariablesWithGlob } from "./pathvariables";
5
+ import { isValidFilePath } from "./filepath";
6
+ export function validateGlobItem(pattern: string) {
7
+ // First, check if the glob uses any undefined path variables
8
+ pattern = replacePathVariablesWithGlob(pattern);
9
+
10
+ // Check for absolute paths (we want relative paths only)
11
+ if(pattern.startsWith('/') || /^[a-zA-Z]:/.test(pattern)){
12
+ throw new Error("File pattern is absolute");
13
+ }
14
+
15
+ // If it's a valid glob pattern, accept it
16
+ if(isGlob(pattern)) return;
17
+
18
+ // If it's not a glob, check if it's a valid file path
19
+ isValidFilePath(pattern);
20
+ }
21
+
@@ -0,0 +1,28 @@
1
+
2
+ export const PATH_VARIABLE_VALUE_VALIDATION = {
3
+ minLength: 1,
4
+ maxLength: 64,
5
+ charset: 'a-zA-Z0-9_\\- ',
6
+ };
7
+
8
+ export function validatePathVariablesInGlob(
9
+ glob: string, pathVariables: Array<string>
10
+ ){
11
+ const pathVariableRegex = /<([a-zA-Z0-9_\\-]+)>/g;
12
+ let match: RegExpExecArray | null;
13
+ while((match = pathVariableRegex.exec(glob)) !== null){
14
+ const variable = match[1];
15
+ if(!pathVariables.includes(variable)){
16
+ throw new Error(`Glob ${glob} uses undefined path variable ${variable}`);
17
+ }
18
+ }
19
+ }
20
+
21
+ export function replacePathVariablesWithGlob(
22
+ glob: string
23
+ ){
24
+ return glob.replaceAll(
25
+ /<([a-zA-Z0-9_\\-]+)>/g,
26
+ `[[${PATH_VARIABLE_VALUE_VALIDATION.charset}]+]{${PATH_VARIABLE_VALUE_VALIDATION.minLength},${PATH_VARIABLE_VALUE_VALIDATION.maxLength}}`
27
+ );
28
+ }
@@ -0,0 +1,46 @@
1
+ import { RosterLockV1Config } from "@roster-lock/types";
2
+ type RosterLockEngineConfig = RosterLockV1Config["engine"];
3
+ type EngineAssetDefinition = RosterLockEngineConfig["pieceDefinitions"][string]["assets"][number];
4
+
5
+ import { validateCount } from "../../../../../shared/count";
6
+
7
+ export function validateAsset(
8
+ pieceAssetDefinition: RosterLockEngineConfig["pieceDefinitions"][string]["assets"][0],
9
+ definition: RosterLockEngineConfig["pieceDefinitions"][string]
10
+ ){
11
+ validateAssetName(pieceAssetDefinition.name, definition.assets);
12
+ validateCount(pieceAssetDefinition.count);
13
+ validateGlobList(pieceAssetDefinition.glob);
14
+ for(const g of pieceAssetDefinition.glob){
15
+ validatePathVariablesInGlob(g, definition.pathVariables);
16
+ validateGlobItem(g);
17
+ }
18
+ }
19
+
20
+ export function validateAssetName(
21
+ name: EngineAssetDefinition["name"], assets: RosterLockEngineConfig["pieceDefinitions"][string]["assets"]
22
+ ){
23
+ if(name === ""){
24
+ throw new Error("Name is empty");
25
+ }
26
+ if(name !== name.trim()){
27
+ throw new Error("Name contains a trailing or leading space");
28
+ }
29
+ if(assets.filter((a) => a.name === name).length > 1){
30
+ throw new Error("Duplicate name");
31
+ }
32
+ }
33
+
34
+ import { validatePathVariablesInGlob, validateGlobItem } from "./glob";
35
+ export function validateGlobList(
36
+ glob: EngineAssetDefinition["glob"],
37
+ ){
38
+ if(glob.length === 0){
39
+ throw new Error("Expecting at least 1 glob");
40
+ }
41
+ if(new Set(glob).size !== glob.length){
42
+ throw new Error("Has duplicate globs");
43
+ }
44
+ }
45
+
46
+ export { validatePathVariablesInGlob, validateGlobItem };
@@ -0,0 +1,37 @@
1
+ import { RosterLockV1Config } from "@roster-lock/types";
2
+ type RosterLockEngineConfig = RosterLockV1Config["engine"];
3
+
4
+ export * from "./requirements";
5
+ export * from "./path-variables";
6
+ export * from "./assets";
7
+ import { validatePathVariableName, validatePathVariables } from "./path-variables";
8
+ import { validateAsset } from "./assets";
9
+ import {
10
+ validatePieceInCycles, validatePieceRequirementList, validatePieceRequirementIsResolved
11
+ } from "./requirements";
12
+ import { ValidationErrorPath } from "../error";
13
+
14
+ export function validatePieceDefinition(
15
+ pieceType: string, definition: RosterLockEngineConfig["pieceDefinitions"][string], engine: RosterLockEngineConfig
16
+ ){
17
+ validatePieceRequirementList(definition.requires);
18
+ for(const requiredPieceType of definition.requires){
19
+ validatePieceRequirementIsResolved(requiredPieceType, engine);
20
+ }
21
+ validatePathVariables(definition.pathVariables);
22
+ for(const variable of definition.pathVariables){
23
+ validatePathVariableName(variable);
24
+ }
25
+ for(const asset of definition.assets){
26
+ try {
27
+ validateAsset(asset, definition);
28
+ }catch(e){
29
+ const eTyped = ValidationErrorPath.convertError(e);
30
+ eTyped.addPathPrefix(`assets/${asset.name}`);
31
+ throw e;
32
+ }
33
+ }
34
+ validatePieceInCycles(pieceType, engine);
35
+ }
36
+
37
+
@@ -0,0 +1,21 @@
1
+
2
+ export function validatePathVariables(variables: Array<string>){
3
+ if(new Set(variables).size !== variables.length){
4
+ throw new Error(`Duplicate path variables`);
5
+ }
6
+ }
7
+
8
+ // Note: [^CHARS] specifies we're looking for characters that are NOT in the set
9
+ const INVALID_PATH_VARIABLE_CHARS = /[^a-zA-Z0-9_]/;
10
+ export function validatePathVariableName(variable: string){
11
+ if(variable.length === 0){
12
+ throw new Error(`Path variable is empty`);
13
+ }
14
+ if(variable.length > 64){
15
+ throw new Error(`Path variable ${variable} is too long`);
16
+ }
17
+ const match = variable.match(INVALID_PATH_VARIABLE_CHARS)
18
+ if(match){
19
+ throw new Error(`Path variable ${variable} contains invalid character: "${match[0]}"`);
20
+ }
21
+ }
@@ -0,0 +1,117 @@
1
+ import { findAllCycles, getCyclesUsingKey } from "@roster-lock/utils";
2
+ import { RosterLockV1Config } from "@roster-lock/types";
3
+ type RosterLockEngineConfig = RosterLockV1Config["engine"];
4
+
5
+
6
+ export class CycleError extends Error {
7
+ constructor(public cycles: Array<Array<string>>){
8
+ super(`Piece requirements form a cycle`);
9
+ }
10
+ getCyclesOfPiece(pieceType: string){
11
+ return getCyclesUsingKey(pieceType, this.cycles);
12
+ }
13
+ }
14
+
15
+ export function validatePieceRequirementCycles(engine: RosterLockEngineConfig){
16
+ const pieceTypes = Object.keys(engine.pieceDefinitions);
17
+ const cycles = findAllCycles(pieceTypes, (pieceType) => engine.pieceDefinitions[pieceType].requires);
18
+ if(cycles.length > 0) throw new CycleError(cycles);
19
+ }
20
+
21
+ export function validatePieceInCycles(pieceType: string, engine: RosterLockEngineConfig){
22
+ const pieceTypes = Object.keys(engine.pieceDefinitions);
23
+ const cycles = findAllCycles(pieceTypes, (pieceType) => engine.pieceDefinitions[pieceType].requires);
24
+ if(cycles.length === 0) return;
25
+ const pieceCycles = getCyclesUsingKey(pieceType, cycles);
26
+ if(pieceCycles.length === 0) return;
27
+ throw new CycleError(pieceCycles);
28
+ }
29
+
30
+ export function validatePieceRequirementList(
31
+ requires: Array<string>
32
+ ){
33
+ if(requires.length === 0) return;
34
+ if(new Set(requires).size !== requires.length)
35
+ throw new Error(`Duplicate requires`);
36
+ }
37
+
38
+ export function validatePieceRequirementIsResolved(
39
+ requiredPieceType: RosterLockEngineConfig["pieceDefinitions"][string]["requires"][0],
40
+ engine: RosterLockEngineConfig
41
+ ){
42
+ const requiredDefinition = engine.pieceDefinitions[requiredPieceType];
43
+ if(!requiredDefinition){
44
+ throw new Error(`Non-existant piece ${requiredPieceType} required`);
45
+ }
46
+ if(requiredDefinition.selectionStrategy !== "on demand"){
47
+ throw new Error(`Non on-demand piece ${requiredPieceType} required`);
48
+ }
49
+ }
50
+
51
+
52
+ //
53
+ // This version tries to use the minimum amount of loops possible
54
+ // Ensure that pieces not on demand can't be required by another non on demand piece
55
+ // Ensure all on demand pieces are required by another piece
56
+ export function eachPieceRequirementIsResolved_COMPLEX(engine: RosterLockEngineConfig){
57
+ const notOnDemandPieceTypes = new Set<string>();
58
+ const unusedOnDemandPieceTypes = new Set<string>();
59
+ const usedOnDemandPieceTypes = new Set<string>();
60
+ const expectedRequires = new Set<string>();
61
+ for(const [pieceType, definition] of Object.entries(engine.pieceDefinitions)){
62
+ // If the piece is on demand, we don't need to resolve it
63
+ if(definition.selectionStrategy === "on demand"){
64
+ if(usedOnDemandPieceTypes.has(pieceType)) continue;
65
+ expectedRequires.delete(pieceType);
66
+ unusedOnDemandPieceTypes.add(pieceType);
67
+
68
+ if(definition.requires.length === 0) continue;
69
+ if(new Set(definition.requires).size !== definition.requires.length)
70
+ throw new Error(`Piece ${pieceType} has duplicate requires`);
71
+ continue;
72
+ }
73
+
74
+ // If the piece is not on demand, It can't be required
75
+ if(expectedRequires.has(pieceType)){
76
+ throw new Error(`Piece ${pieceType} is required by another piece but is not an on demand piece`);
77
+ }
78
+ notOnDemandPieceTypes.add(pieceType);
79
+
80
+ // If we have no requirements, we're done
81
+ if(definition.requires.length === 0) continue;
82
+ if(new Set(definition.requires).size !== definition.requires.length)
83
+ throw new Error(`Piece ${pieceType} has duplicate requires`);
84
+
85
+ checkRequires(pieceType, definition);
86
+ }
87
+
88
+ if(expectedRequires.size > 0){
89
+ throw new Error(`The following pieces are required but not resolved: ${Array.from(expectedRequires).join(", ")}`);
90
+ }
91
+
92
+ function checkRequires(pieceType: string, definition: RosterLockEngineConfig["pieceDefinitions"][string]){
93
+
94
+ // Check each required piece type
95
+ for(const requiredPieceType of definition.requires){
96
+ // If the required piece type was already resolved, we're ok
97
+ if(notOnDemandPieceTypes.has(requiredPieceType)){
98
+ throw new Error(`Piece ${requiredPieceType} is required by another piece but is not an on demand piece`);
99
+ }
100
+
101
+ // If the required piece type was already used, we're ok
102
+ if(usedOnDemandPieceTypes.has(requiredPieceType)) continue;
103
+
104
+ // If the required piece type is on demand but wasn't used, we need to resolve it
105
+ if(unusedOnDemandPieceTypes.has(requiredPieceType)){
106
+ unusedOnDemandPieceTypes.delete(requiredPieceType);
107
+ usedOnDemandPieceTypes.add(requiredPieceType);
108
+ checkRequires(requiredPieceType, engine.pieceDefinitions[requiredPieceType]);
109
+ continue;
110
+ }
111
+
112
+ // Otherwise the on demand piece is not defined yet, we expect to find it later
113
+ expectedRequires.add(requiredPieceType);
114
+ }
115
+ }
116
+ }
117
+
@@ -0,0 +1,51 @@
1
+
2
+ import { JSONSchemaType } from "ajv";
3
+ import { JSONSchemaCaster } from "../../../util-types/json-schema";
4
+ import { engineKeywords, engineSchema } from "./engine";
5
+ export * from "./engine";
6
+ import { rosterKeywords, rostersSchema } from "./rosters";
7
+ export * from "./rosters";
8
+ import { selectionKeywords, selectionConfigSchema } from "./selection";
9
+ export * from "./selection";
10
+ import { pieceMetaKeywords, pieceMetaSchema } from "./piece-meta";
11
+ export * from "./piece-meta";
12
+ import { sharedKeywords } from "../shared";
13
+
14
+ import { RosterLockV1Config } from "@roster-lock/types";
15
+
16
+ import { buildIdentity } from "../shared";
17
+
18
+ export const RosterLockV1Schema: JSONSchemaType<RosterLockV1Config> = {
19
+ type: "object",
20
+ required: [
21
+ "configIdentity",
22
+ "author", "title", "version",
23
+ "engine", "rosters", "selection", "pieceMeta"
24
+ ],
25
+ additionalProperties: false,
26
+ properties: {
27
+ configIdentity: buildIdentity("lock", 1),
28
+
29
+ author: { type: "string" },
30
+ title: { type: "string" },
31
+ version: { type: "string" },
32
+
33
+ engine: engineSchema,
34
+ rosters: rostersSchema,
35
+ selection: selectionConfigSchema,
36
+ pieceMeta: pieceMetaSchema,
37
+ },
38
+ };
39
+
40
+ export const RosterLockV1SchemaKeywords = [
41
+ ...sharedKeywords,
42
+ ...engineKeywords,
43
+ ...rosterKeywords,
44
+ ...selectionKeywords,
45
+ ...pieceMetaKeywords,
46
+ ];
47
+
48
+
49
+ export const ROSTERLOCK_V1_CASTER_JSONSCHEMA = new JSONSchemaCaster<
50
+ RosterLockV1Config
51
+ >(RosterLockV1Schema,RosterLockV1SchemaKeywords);
@@ -0,0 +1,97 @@
1
+
2
+ import { JSONSchemaType } from "ajv";
3
+ import { defineKeyword } from "../../../../../util-types/json-schema";
4
+ import { RosterLockV1Config, SelectionPieceMeta, JSONShallowObject } from "@roster-lock/types";
5
+
6
+ import { validateMetaDefaultValue, validateMetaForPiece } from "../validate";
7
+
8
+ export const metaDefaultValueSchemaValidator = defineKeyword({
9
+ keyword: "metaDefaultValue",
10
+ type: "object",
11
+ validate: (defaultMeta: JSONShallowObject, { pieceMeta }: RosterLockV1Config, path)=>{
12
+ const pathParts = path.split("/");
13
+ // /pieceMeta/pieceType/defaultMeta
14
+ const pieceType = pathParts[2];
15
+ const sharedPieceMeta = pieceMeta[pieceType];
16
+ if(!sharedPieceMeta){
17
+ throw new Error(`Piece type ${pieceType} does not have shared piece meta`);
18
+ }
19
+ validateMetaDefaultValue(sharedPieceMeta.schema, defaultMeta);
20
+ },
21
+ });
22
+
23
+
24
+ export const metaPieceValueSchemaValidator = defineKeyword({
25
+ keyword: "metaPieceValue",
26
+ type: "object",
27
+ validate: (pieceValue: JSONShallowObject, { pieceMeta, rosters }: RosterLockV1Config, path)=>{
28
+ const pathParts = path.split("/");
29
+ // /pieceMeta/pieceType/values/pieceId
30
+ const pieceType = pathParts[2];
31
+ const pieceId = pathParts[4]?.replace(/~1/g, "/").replace(/~0/g, "~");
32
+ const sharedPieceMeta = pieceMeta[pieceType];
33
+ if(!sharedPieceMeta){
34
+ throw new Error(`Piece type ${pieceType} does not have shared piece meta`);
35
+ }
36
+ const roster = rosters[pieceType];
37
+ if(!roster){
38
+ throw new Error(`Piece type ${pieceType} does not have a roster`);
39
+ }
40
+ validateMetaForPiece(sharedPieceMeta.schema, pieceId, pieceValue, roster);
41
+ },
42
+ });
43
+
44
+ const shallowObjectSchema = {
45
+ type: "object",
46
+ required: [],
47
+ additionalProperties: {
48
+ anyOf: [
49
+ { type: "string" },
50
+ { type: "number" },
51
+ { type: "boolean" },
52
+ { type: "array", items: { type: "string" } },
53
+ { type: "array", items: { type: "number" } },
54
+ { type: "array", items: { type: "boolean" } },
55
+ ],
56
+ },
57
+ } as const;
58
+
59
+
60
+ export const selectionPieceMetaSchema: JSONSchemaType<SelectionPieceMeta<JSONShallowObject>> = {
61
+ type: "object",
62
+ required: ["schema","defaultMeta", "values"],
63
+ additionalProperties: false,
64
+ properties: {
65
+ schema: {
66
+ type: "object",
67
+ required: [],
68
+ additionalProperties: {
69
+ type: "string",
70
+ enum: ["boolean", "number", "string", "boolean[]", "number[]", "string[]"],
71
+ },
72
+ },
73
+ defaultMeta: {
74
+ ...shallowObjectSchema,
75
+ [metaDefaultValueSchemaValidator.keyword]: true,
76
+ },
77
+ values: {
78
+ type: "object",
79
+ required: [],
80
+ additionalProperties: {
81
+ ...shallowObjectSchema,
82
+ [metaPieceValueSchemaValidator.keyword]: true,
83
+ }
84
+ },
85
+ },
86
+ };
87
+
88
+ export const pieceMetaSchema: JSONSchemaType<RosterLockV1Config["pieceMeta"]> = {
89
+ type: "object",
90
+ required: [],
91
+ additionalProperties: selectionPieceMetaSchema,
92
+ };
93
+
94
+ export const pieceMetaKeywords = [
95
+ metaDefaultValueSchemaValidator,
96
+ metaPieceValueSchemaValidator,
97
+ ];
@@ -0,0 +1,3 @@
1
+
2
+ export * from "./validate";
3
+ export * from "./caster-json-schema";