dabke 0.83.0 → 0.84.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 (330) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +22 -27
  3. package/dist/client.d.ts +39 -3
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/client.schemas.d.ts +118 -18
  7. package/dist/client.schemas.d.ts.map +1 -1
  8. package/dist/client.schemas.js +110 -6
  9. package/dist/client.schemas.js.map +1 -1
  10. package/dist/client.types.d.ts +63 -7
  11. package/dist/client.types.d.ts.map +1 -1
  12. package/dist/client.types.js.map +1 -1
  13. package/dist/cpsat/cost.d.ts +5 -2
  14. package/dist/cpsat/cost.d.ts.map +1 -1
  15. package/dist/cpsat/cost.js +13 -6
  16. package/dist/cpsat/cost.js.map +1 -1
  17. package/dist/cpsat/model-builder.d.ts +42 -61
  18. package/dist/cpsat/model-builder.d.ts.map +1 -1
  19. package/dist/cpsat/model-builder.js +451 -56
  20. package/dist/cpsat/model-builder.js.map +1 -1
  21. package/dist/cpsat/response.d.ts +19 -7
  22. package/dist/cpsat/response.d.ts.map +1 -1
  23. package/dist/cpsat/response.js +48 -9
  24. package/dist/cpsat/response.js.map +1 -1
  25. package/dist/cpsat/rule-descriptor.d.ts +250 -0
  26. package/dist/cpsat/rule-descriptor.d.ts.map +1 -0
  27. package/dist/cpsat/rule-descriptor.js +51 -0
  28. package/dist/cpsat/rule-descriptor.js.map +1 -0
  29. package/dist/cpsat/rules/artifacts.d.ts +9 -0
  30. package/dist/cpsat/rules/artifacts.d.ts.map +1 -0
  31. package/dist/cpsat/rules/artifacts.js +31 -0
  32. package/dist/cpsat/rules/artifacts.js.map +1 -0
  33. package/dist/cpsat/rules/assign-together.d.ts +18 -20
  34. package/dist/cpsat/rules/assign-together.d.ts.map +1 -1
  35. package/dist/cpsat/rules/assign-together.js +90 -54
  36. package/dist/cpsat/rules/assign-together.js.map +1 -1
  37. package/dist/cpsat/rules/assigned-day.d.ts +12 -0
  38. package/dist/cpsat/rules/assigned-day.d.ts.map +1 -0
  39. package/dist/cpsat/rules/assigned-day.js +43 -0
  40. package/dist/cpsat/rules/assigned-day.js.map +1 -0
  41. package/dist/cpsat/rules/assignment-priority.d.ts +15 -29
  42. package/dist/cpsat/rules/assignment-priority.d.ts.map +1 -1
  43. package/dist/cpsat/rules/assignment-priority.js +47 -50
  44. package/dist/cpsat/rules/assignment-priority.js.map +1 -1
  45. package/dist/cpsat/rules/assignment-terms.d.ts +6 -0
  46. package/dist/cpsat/rules/assignment-terms.d.ts.map +1 -0
  47. package/dist/cpsat/rules/assignment-terms.js +19 -0
  48. package/dist/cpsat/rules/assignment-terms.js.map +1 -0
  49. package/dist/cpsat/rules/concurrent-intervals.d.ts +19 -0
  50. package/dist/cpsat/rules/concurrent-intervals.d.ts.map +1 -0
  51. package/dist/cpsat/rules/concurrent-intervals.js +57 -0
  52. package/dist/cpsat/rules/concurrent-intervals.js.map +1 -0
  53. package/dist/cpsat/rules/cost-utils.d.ts +1 -3
  54. package/dist/cpsat/rules/cost-utils.d.ts.map +1 -1
  55. package/dist/cpsat/rules/cost-utils.js +0 -7
  56. package/dist/cpsat/rules/cost-utils.js.map +1 -1
  57. package/dist/cpsat/rules/day-cost-multiplier.d.ts +10 -10
  58. package/dist/cpsat/rules/day-cost-multiplier.d.ts.map +1 -1
  59. package/dist/cpsat/rules/day-cost-multiplier.js +88 -77
  60. package/dist/cpsat/rules/day-cost-multiplier.js.map +1 -1
  61. package/dist/cpsat/rules/day-cost-surcharge.d.ts +10 -10
  62. package/dist/cpsat/rules/day-cost-surcharge.d.ts.map +1 -1
  63. package/dist/cpsat/rules/day-cost-surcharge.js +76 -65
  64. package/dist/cpsat/rules/day-cost-surcharge.js.map +1 -1
  65. package/dist/cpsat/rules/index.d.ts +30 -24
  66. package/dist/cpsat/rules/index.d.ts.map +1 -1
  67. package/dist/cpsat/rules/index.js +30 -24
  68. package/dist/cpsat/rules/index.js.map +1 -1
  69. package/dist/cpsat/rules/location-preference.d.ts +14 -21
  70. package/dist/cpsat/rules/location-preference.d.ts.map +1 -1
  71. package/dist/cpsat/rules/location-preference.js +45 -45
  72. package/dist/cpsat/rules/location-preference.js.map +1 -1
  73. package/dist/cpsat/rules/max-concurrent-assignments.d.ts +46 -0
  74. package/dist/cpsat/rules/max-concurrent-assignments.d.ts.map +1 -0
  75. package/dist/cpsat/rules/max-concurrent-assignments.js +121 -0
  76. package/dist/cpsat/rules/max-concurrent-assignments.js.map +1 -0
  77. package/dist/cpsat/rules/max-consecutive-days.d.ts +18 -17
  78. package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
  79. package/dist/cpsat/rules/max-consecutive-days.js +67 -66
  80. package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
  81. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts +45 -0
  82. package/dist/cpsat/rules/max-days-of-week-per-period.d.ts.map +1 -0
  83. package/dist/cpsat/rules/max-days-of-week-per-period.js +95 -0
  84. package/dist/cpsat/rules/max-days-of-week-per-period.js.map +1 -0
  85. package/dist/cpsat/rules/max-days-week.d.ts +17 -31
  86. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -1
  87. package/dist/cpsat/rules/max-days-week.js +69 -81
  88. package/dist/cpsat/rules/max-days-week.js.map +1 -1
  89. package/dist/cpsat/rules/max-hours-day.d.ts +14 -31
  90. package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
  91. package/dist/cpsat/rules/max-hours-day.js +56 -72
  92. package/dist/cpsat/rules/max-hours-day.js.map +1 -1
  93. package/dist/cpsat/rules/max-hours-week.d.ts +15 -31
  94. package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
  95. package/dist/cpsat/rules/max-hours-week.js +60 -75
  96. package/dist/cpsat/rules/max-hours-week.js.map +1 -1
  97. package/dist/cpsat/rules/max-shifts-day.d.ts +17 -33
  98. package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
  99. package/dist/cpsat/rules/max-shifts-day.js +57 -73
  100. package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
  101. package/dist/cpsat/rules/min-consecutive-days.d.ts +18 -18
  102. package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
  103. package/dist/cpsat/rules/min-consecutive-days.js +123 -94
  104. package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
  105. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts +35 -0
  106. package/dist/cpsat/rules/min-days-of-week-per-period.d.ts.map +1 -0
  107. package/dist/cpsat/rules/min-days-of-week-per-period.js +108 -0
  108. package/dist/cpsat/rules/min-days-of-week-per-period.js.map +1 -0
  109. package/dist/cpsat/rules/min-days-week.d.ts +13 -26
  110. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -1
  111. package/dist/cpsat/rules/min-days-week.js +85 -74
  112. package/dist/cpsat/rules/min-days-week.js.map +1 -1
  113. package/dist/cpsat/rules/min-hours-day.d.ts +14 -17
  114. package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
  115. package/dist/cpsat/rules/min-hours-day.js +72 -54
  116. package/dist/cpsat/rules/min-hours-day.js.map +1 -1
  117. package/dist/cpsat/rules/min-hours-week.d.ts +15 -18
  118. package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
  119. package/dist/cpsat/rules/min-hours-week.js +75 -57
  120. package/dist/cpsat/rules/min-hours-week.js.map +1 -1
  121. package/dist/cpsat/rules/min-rest-between-shifts.d.ts +14 -17
  122. package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
  123. package/dist/cpsat/rules/min-rest-between-shifts.js +148 -138
  124. package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
  125. package/dist/cpsat/rules/minimize-cost.d.ts +2 -18
  126. package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
  127. package/dist/cpsat/rules/minimize-cost.js +151 -163
  128. package/dist/cpsat/rules/minimize-cost.js.map +1 -1
  129. package/dist/cpsat/rules/must-assign.d.ts +5 -42
  130. package/dist/cpsat/rules/must-assign.d.ts.map +1 -1
  131. package/dist/cpsat/rules/must-assign.js +43 -75
  132. package/dist/cpsat/rules/must-assign.js.map +1 -1
  133. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts +6 -10
  134. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
  135. package/dist/cpsat/rules/overtime-daily-multiplier.js +118 -112
  136. package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
  137. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts +6 -11
  138. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
  139. package/dist/cpsat/rules/overtime-daily-surcharge.js +104 -99
  140. package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
  141. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +9 -21
  142. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
  143. package/dist/cpsat/rules/overtime-tiered-multiplier.js +181 -199
  144. package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
  145. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts +13 -12
  146. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
  147. package/dist/cpsat/rules/overtime-weekly-multiplier.js +143 -143
  148. package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
  149. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts +7 -11
  150. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
  151. package/dist/cpsat/rules/overtime-weekly-surcharge.js +124 -119
  152. package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
  153. package/dist/cpsat/rules/pattern-eligibility.d.ts +6 -0
  154. package/dist/cpsat/rules/pattern-eligibility.d.ts.map +1 -0
  155. package/dist/cpsat/rules/pattern-eligibility.js +16 -0
  156. package/dist/cpsat/rules/pattern-eligibility.js.map +1 -0
  157. package/dist/cpsat/rules/pattern-time.d.ts +5 -0
  158. package/dist/cpsat/rules/pattern-time.d.ts.map +1 -0
  159. package/dist/cpsat/rules/pattern-time.js +20 -0
  160. package/dist/cpsat/rules/pattern-time.js.map +1 -0
  161. package/dist/cpsat/rules/registry.d.ts +217 -30
  162. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  163. package/dist/cpsat/rules/registry.js +98 -34
  164. package/dist/cpsat/rules/registry.js.map +1 -1
  165. package/dist/cpsat/rules/resolver.d.ts +9 -7
  166. package/dist/cpsat/rules/resolver.d.ts.map +1 -1
  167. package/dist/cpsat/rules/resolver.js +19 -18
  168. package/dist/cpsat/rules/resolver.js.map +1 -1
  169. package/dist/cpsat/rules/role-preference.d.ts +24 -0
  170. package/dist/cpsat/rules/role-preference.d.ts.map +1 -0
  171. package/dist/cpsat/rules/role-preference.js +72 -0
  172. package/dist/cpsat/rules/role-preference.js.map +1 -0
  173. package/dist/cpsat/rules/rules.types.d.ts +90 -17
  174. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  175. package/dist/cpsat/rules/scope.types.d.ts +24 -11
  176. package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
  177. package/dist/cpsat/rules/scope.types.js +14 -19
  178. package/dist/cpsat/rules/scope.types.js.map +1 -1
  179. package/dist/cpsat/rules/target-days-week.d.ts +31 -0
  180. package/dist/cpsat/rules/target-days-week.d.ts.map +1 -0
  181. package/dist/cpsat/rules/target-days-week.js +80 -0
  182. package/dist/cpsat/rules/target-days-week.js.map +1 -0
  183. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts +33 -0
  184. package/dist/cpsat/rules/target-peak-concurrent-assignments.d.ts.map +1 -0
  185. package/dist/cpsat/rules/target-peak-concurrent-assignments.js +146 -0
  186. package/dist/cpsat/rules/target-peak-concurrent-assignments.js.map +1 -0
  187. package/dist/cpsat/rules/time-cost-surcharge.d.ts +15 -14
  188. package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
  189. package/dist/cpsat/rules/time-cost-surcharge.js +82 -96
  190. package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
  191. package/dist/cpsat/rules/time-off.d.ts +21 -57
  192. package/dist/cpsat/rules/time-off.d.ts.map +1 -1
  193. package/dist/cpsat/rules/time-off.js +114 -127
  194. package/dist/cpsat/rules/time-off.js.map +1 -1
  195. package/dist/cpsat/rules/variables.d.ts +4 -0
  196. package/dist/cpsat/rules/variables.d.ts.map +1 -0
  197. package/dist/cpsat/rules/variables.js +10 -0
  198. package/dist/cpsat/rules/variables.js.map +1 -0
  199. package/dist/cpsat/rules.d.ts +20 -3
  200. package/dist/cpsat/rules.d.ts.map +1 -1
  201. package/dist/cpsat/rules.js +19 -2
  202. package/dist/cpsat/rules.js.map +1 -1
  203. package/dist/cpsat/semantic-time.d.ts +7 -6
  204. package/dist/cpsat/semantic-time.d.ts.map +1 -1
  205. package/dist/cpsat/semantic-time.js +15 -28
  206. package/dist/cpsat/semantic-time.js.map +1 -1
  207. package/dist/cpsat/types.d.ts +47 -4
  208. package/dist/cpsat/types.d.ts.map +1 -1
  209. package/dist/cpsat/types.js +24 -1
  210. package/dist/cpsat/types.js.map +1 -1
  211. package/dist/cpsat/utils.d.ts +23 -6
  212. package/dist/cpsat/utils.d.ts.map +1 -1
  213. package/dist/cpsat/utils.js +76 -15
  214. package/dist/cpsat/utils.js.map +1 -1
  215. package/dist/cpsat/validation-reporter.d.ts +6 -2
  216. package/dist/cpsat/validation-reporter.d.ts.map +1 -1
  217. package/dist/cpsat/validation-reporter.js +122 -10
  218. package/dist/cpsat/validation-reporter.js.map +1 -1
  219. package/dist/cpsat/validation.types.d.ts +21 -10
  220. package/dist/cpsat/validation.types.d.ts.map +1 -1
  221. package/dist/datetime.utils.d.ts +7 -13
  222. package/dist/datetime.utils.d.ts.map +1 -1
  223. package/dist/datetime.utils.js +29 -36
  224. package/dist/datetime.utils.js.map +1 -1
  225. package/dist/index.d.ts +12 -8
  226. package/dist/index.d.ts.map +1 -1
  227. package/dist/index.js +8 -3
  228. package/dist/index.js.map +1 -1
  229. package/dist/schedule/cost.d.ts +48 -60
  230. package/dist/schedule/cost.d.ts.map +1 -1
  231. package/dist/schedule/cost.js +15 -51
  232. package/dist/schedule/cost.js.map +1 -1
  233. package/dist/schedule/coverage.d.ts +57 -28
  234. package/dist/schedule/coverage.d.ts.map +1 -1
  235. package/dist/schedule/coverage.js +24 -1
  236. package/dist/schedule/coverage.js.map +1 -1
  237. package/dist/schedule/definition.d.ts +138 -19
  238. package/dist/schedule/definition.d.ts.map +1 -1
  239. package/dist/schedule/definition.js +99 -90
  240. package/dist/schedule/definition.js.map +1 -1
  241. package/dist/schedule/index.d.ts +4 -4
  242. package/dist/schedule/index.d.ts.map +1 -1
  243. package/dist/schedule/index.js +2 -2
  244. package/dist/schedule/index.js.map +1 -1
  245. package/dist/schedule/rules.d.ts +438 -113
  246. package/dist/schedule/rules.d.ts.map +1 -1
  247. package/dist/schedule/rules.js +310 -108
  248. package/dist/schedule/rules.js.map +1 -1
  249. package/dist/schedule/shift-patterns.d.ts +0 -17
  250. package/dist/schedule/shift-patterns.d.ts.map +1 -1
  251. package/dist/schedule/shift-patterns.js +0 -17
  252. package/dist/schedule/shift-patterns.js.map +1 -1
  253. package/dist/schedule/time-periods.d.ts +37 -27
  254. package/dist/schedule/time-periods.d.ts.map +1 -1
  255. package/dist/schedule/time-periods.js +37 -27
  256. package/dist/schedule/time-periods.js.map +1 -1
  257. package/dist/types.d.ts +67 -3
  258. package/dist/types.d.ts.map +1 -1
  259. package/dist/types.js +64 -0
  260. package/dist/types.js.map +1 -1
  261. package/package.json +8 -9
  262. package/solver/src/solver/models.py +41 -4
  263. package/solver/src/solver/solver.py +546 -157
  264. package/solver/tests/test_solver.py +363 -7
  265. package/src/client.schemas.ts +127 -10
  266. package/src/client.ts +3 -0
  267. package/src/client.types.ts +73 -7
  268. package/src/cpsat/cost.ts +17 -7
  269. package/src/cpsat/model-builder.ts +614 -129
  270. package/src/cpsat/response.ts +57 -13
  271. package/src/cpsat/rule-descriptor.ts +311 -0
  272. package/src/cpsat/rules/artifacts.ts +56 -0
  273. package/src/cpsat/rules/assign-together.ts +104 -69
  274. package/src/cpsat/rules/assigned-day.ts +70 -0
  275. package/src/cpsat/rules/assignment-priority.ts +54 -58
  276. package/src/cpsat/rules/assignment-terms.ts +43 -0
  277. package/src/cpsat/rules/concurrent-intervals.ts +93 -0
  278. package/src/cpsat/rules/cost-utils.ts +1 -9
  279. package/src/cpsat/rules/day-cost-multiplier.ts +101 -81
  280. package/src/cpsat/rules/day-cost-surcharge.ts +91 -70
  281. package/src/cpsat/rules/index.ts +30 -24
  282. package/src/cpsat/rules/location-preference.ts +47 -52
  283. package/src/cpsat/rules/max-concurrent-assignments.ts +170 -0
  284. package/src/cpsat/rules/max-consecutive-days.ts +74 -91
  285. package/src/cpsat/rules/max-days-of-week-per-period.ts +127 -0
  286. package/src/cpsat/rules/max-days-week.ts +89 -115
  287. package/src/cpsat/rules/max-hours-day.ts +64 -84
  288. package/src/cpsat/rules/max-hours-week.ts +74 -90
  289. package/src/cpsat/rules/max-shifts-day.ts +65 -85
  290. package/src/cpsat/rules/min-consecutive-days.ts +161 -127
  291. package/src/cpsat/rules/min-days-of-week-per-period.ts +144 -0
  292. package/src/cpsat/rules/min-days-week.ts +93 -91
  293. package/src/cpsat/rules/min-hours-day.ts +79 -58
  294. package/src/cpsat/rules/min-hours-week.ts +87 -62
  295. package/src/cpsat/rules/min-rest-between-shifts.ts +191 -178
  296. package/src/cpsat/rules/minimize-cost.ts +175 -188
  297. package/src/cpsat/rules/must-assign.ts +44 -81
  298. package/src/cpsat/rules/overtime-daily-multiplier.ts +158 -140
  299. package/src/cpsat/rules/overtime-daily-surcharge.ts +141 -126
  300. package/src/cpsat/rules/overtime-tiered-multiplier.ts +234 -253
  301. package/src/cpsat/rules/overtime-weekly-multiplier.ts +183 -175
  302. package/src/cpsat/rules/overtime-weekly-surcharge.ts +161 -150
  303. package/src/cpsat/rules/pattern-eligibility.ts +26 -0
  304. package/src/cpsat/rules/pattern-time.ts +30 -0
  305. package/src/cpsat/rules/registry.ts +140 -62
  306. package/src/cpsat/rules/resolver.ts +58 -30
  307. package/src/cpsat/rules/role-preference.ts +92 -0
  308. package/src/cpsat/rules/rules.types.ts +89 -17
  309. package/src/cpsat/rules/scope.types.ts +31 -26
  310. package/src/cpsat/rules/target-days-week.ts +105 -0
  311. package/src/cpsat/rules/target-peak-concurrent-assignments.ts +212 -0
  312. package/src/cpsat/rules/time-cost-surcharge.ts +116 -122
  313. package/src/cpsat/rules/time-off.ts +154 -163
  314. package/src/cpsat/rules/variables.ts +11 -0
  315. package/src/cpsat/rules.ts +43 -17
  316. package/src/cpsat/semantic-time.ts +29 -43
  317. package/src/cpsat/types.ts +53 -4
  318. package/src/cpsat/utils.ts +92 -20
  319. package/src/cpsat/validation-reporter.ts +170 -19
  320. package/src/cpsat/validation.types.ts +22 -11
  321. package/src/datetime.utils.ts +45 -44
  322. package/src/index.ts +64 -12
  323. package/src/schedule/cost.ts +40 -61
  324. package/src/schedule/coverage.ts +57 -28
  325. package/src/schedule/definition.ts +565 -76
  326. package/src/schedule/index.ts +23 -3
  327. package/src/schedule/rules.ts +631 -132
  328. package/src/schedule/shift-patterns.ts +0 -17
  329. package/src/schedule/time-periods.ts +37 -27
  330. package/src/types.ts +114 -2
@@ -1,19 +1,21 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
3
- import type { Term } from "../types.js";
2
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
3
  import { priorityToPenalty } from "../utils.js";
5
4
  import {
6
5
  PrioritySchema,
7
6
  entityScope,
8
- timeScope,
9
7
  parseEntityScope,
10
8
  parseTimeScope,
11
- resolveMembersFromScope,
12
9
  resolveActiveDaysFromScope,
10
+ resolveMembersFromScope,
13
11
  ruleGroup,
12
+ timeScope,
14
13
  } from "./scope.types.js";
14
+ import { assignmentTermsForDay } from "./assignment-terms.js";
15
+ import { patternDurationMinutes } from "./pattern-time.js";
16
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
15
17
 
16
- const MaxHoursDaySchema = z
18
+ export const MaxHoursDaySchema = z
17
19
  .object({
18
20
  hours: z.number().min(0),
19
21
  priority: PrioritySchema,
@@ -22,92 +24,70 @@ const MaxHoursDaySchema = z
22
24
  .and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
23
25
 
24
26
  /**
25
- * Configuration for {@link createMaxHoursDayRule}.
26
- *
27
- * - `hours` (required): maximum hours allowed per day
28
- * - `priority` (required): how strictly the solver enforces this rule
29
- *
30
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
31
- * Time scoping (at most one, optional): `dateRange`, `specificDates`, `dayOfWeek`, `recurringPeriods`
27
+ * Configuration for {@link maxHoursDayRuleDescriptor}.
32
28
  */
33
29
  export type MaxHoursDayConfig = z.infer<typeof MaxHoursDaySchema>;
34
30
 
35
31
  /**
36
- * Limits how many hours a person can work in a single day.
37
- *
38
- * @param config - See {@link MaxHoursDayConfig}
39
- * @example Limit everyone to 8 hours per day
40
- * ```ts
41
- * createMaxHoursDayRule({
42
- * hours: 8,
43
- * priority: "MANDATORY",
44
- * });
45
- * ```
32
+ * Low-level descriptor for the `max-hours-day` rule.
46
33
  *
47
- * @example Students limited to 4 hours on weekdays during term
48
- * ```ts
49
- * createMaxHoursDayRule({
50
- * roleIds: ["student"],
51
- * hours: 4,
52
- * dayOfWeek: ["monday", "tuesday", "wednesday", "thursday", "friday"],
53
- * priority: "MANDATORY",
54
- * });
55
- * ```
34
+ * @category Rules
56
35
  */
57
- export function createMaxHoursDayRule(config: MaxHoursDayConfig): CompilationRule {
58
- const parsed = MaxHoursDaySchema.parse(config);
59
- const entityScopeValue = parseEntityScope(parsed);
60
- const timeScopeValue = parseTimeScope(parsed);
61
- const { hours, priority } = parsed;
62
- const maxMinutes = hours * 60;
63
- const group = ruleGroup(
64
- `max-hours-day:${hours}`,
65
- `Max ${hours}h per day`,
66
- entityScopeValue,
67
- timeScopeValue,
68
- );
69
-
70
- return {
71
- compile(b) {
72
- const targetMembers = resolveMembersFromScope(entityScopeValue, b.members);
73
- const activeDays = resolveActiveDaysFromScope(timeScopeValue, b.days);
74
-
75
- if (targetMembers.length === 0 || activeDays.length === 0) return;
36
+ export const maxHoursDayRuleDescriptor = defineRuleDescriptor({
37
+ name: "max-hours-day",
38
+ schema: MaxHoursDaySchema,
39
+ compile(config, ctx) {
40
+ const entityScopeValue = parseEntityScope(config);
41
+ const timeScopeValue = parseTimeScope(config);
42
+ const { hours, priority } = config;
43
+ const maxMinutes = hours * 60;
44
+ const group = ruleGroup(
45
+ `max-hours-day:${hours}`,
46
+ `Max ${hours}h per day`,
47
+ entityScopeValue,
48
+ timeScopeValue,
49
+ );
50
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
51
+ const activeDays = resolveActiveDaysFromScope(timeScopeValue, [...ctx.days]);
76
52
 
77
- for (const emp of targetMembers) {
78
- for (const day of activeDays) {
79
- const terms: Term[] = [];
80
- for (const pattern of b.shiftPatterns) {
81
- if (!b.canAssign(emp, pattern)) continue;
82
- if (!b.patternAvailableOnDay(pattern, day)) continue;
83
- terms.push({
84
- var: b.assignment(emp.id, pattern.id, day),
85
- coeff: b.patternDuration(pattern.id),
86
- });
87
- }
53
+ const artifacts = targetMembers.flatMap((member) =>
54
+ activeDays.flatMap((day) => {
55
+ const terms = assignmentTermsForDay(member, day, ctx.shiftPatterns, patternDurationMinutes);
56
+ if (terms.length === 0) return [];
88
57
 
89
- if (terms.length === 0) continue;
58
+ const description = `${member.id} max ${hours}h on ${day.iso}`;
59
+ const context = { memberIds: [member.id], days: [day.iso] };
60
+ const constraintId = `max-hours-day:${member.id}:${day.iso}`;
90
61
 
91
- const constraintId = `max-hours-day:${emp.id}:${day}`;
62
+ return [
63
+ priority === "MANDATORY"
64
+ ? hardConstraint({
65
+ group,
66
+ description,
67
+ context,
68
+ validation: reportValidation(constraintId),
69
+ terms,
70
+ comparator: "<=",
71
+ targetValue: maxMinutes,
72
+ })
73
+ : softConstraint({
74
+ group,
75
+ description,
76
+ context,
77
+ validation: reportValidation(),
78
+ terms,
79
+ comparator: "<=",
80
+ targetValue: maxMinutes,
81
+ penalty: priorityToPenalty(priority),
82
+ constraintId,
83
+ }),
84
+ ];
85
+ }),
86
+ );
92
87
 
93
- if (priority === "MANDATORY") {
94
- b.addLinear(terms, "<=", maxMinutes);
95
- } else {
96
- b.addSoftLinear(terms, "<=", maxMinutes, priorityToPenalty(priority), constraintId);
97
- b.reporter.trackConstraint({
98
- id: constraintId,
99
- type: "rule",
100
- rule: "max-hours-day",
101
- description: `${emp.id} max ${hours}h on ${day}`,
102
- targetValue: maxMinutes,
103
- comparator: "<=",
104
- day,
105
- context: { memberIds: [emp.id], days: [day] },
106
- group,
107
- });
108
- }
109
- }
110
- }
111
- },
112
- };
113
- }
88
+ return {
89
+ rule: "max-hours-day",
90
+ artifacts,
91
+ };
92
+ },
93
+ });
@@ -1,18 +1,20 @@
1
1
  import * as z from "zod";
2
2
  import { DayOfWeekSchema } from "../../types.js";
3
- import type { CompilationRule } from "../model-builder.js";
4
- import type { Term } from "../types.js";
3
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
5
4
  import { priorityToPenalty, splitIntoWeeks } from "../utils.js";
6
5
  import {
7
6
  PrioritySchema,
8
7
  entityScope,
9
- timeScope,
10
8
  parseEntityScope,
11
9
  parseTimeScope,
12
- resolveMembersFromScope,
13
10
  resolveActiveDaysFromScope,
11
+ resolveMembersFromScope,
14
12
  ruleGroup,
13
+ timeScope,
15
14
  } from "./scope.types.js";
15
+ import { assignmentTermsForDays } from "./assignment-terms.js";
16
+ import { patternDurationMinutes } from "./pattern-time.js";
17
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
16
18
 
17
19
  const MaxHoursWeekBase = z.object({
18
20
  hours: z.number().min(0),
@@ -20,102 +22,84 @@ const MaxHoursWeekBase = z.object({
20
22
  weekStartsOn: DayOfWeekSchema.optional(),
21
23
  });
22
24
 
23
- const MaxHoursWeekSchema = MaxHoursWeekBase.and(entityScope(["members", "roles", "skills"])).and(
24
- timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]),
25
- );
25
+ export const MaxHoursWeekSchema = MaxHoursWeekBase.and(
26
+ entityScope(["members", "roles", "skills"]),
27
+ ).and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
26
28
 
27
29
  /**
28
- * Configuration for {@link createMaxHoursWeekRule}.
29
- *
30
- * - `hours` (required): maximum hours allowed per scheduling week
31
- * - `priority` (required): how strictly the solver enforces this rule
32
- * - `weekStartsOn` (optional): which day starts the week; defaults to {@link ModelBuilder.weekStartsOn}
33
- *
34
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
35
- * Time scoping (at most one, optional): `dateRange`, `specificDates`, `dayOfWeek`, `recurringPeriods`
30
+ * Configuration for {@link maxHoursWeekRuleDescriptor}.
36
31
  */
37
32
  export type MaxHoursWeekConfig = z.infer<typeof MaxHoursWeekSchema>;
38
33
 
39
34
  /**
40
- * Caps total hours a person can work within each scheduling week.
41
- *
42
- * @param config - See {@link MaxHoursWeekConfig}
43
- * @example Limit everyone to 40 hours per week
44
- * ```ts
45
- * createMaxHoursWeekRule({ hours: 40, priority: "HIGH" });
46
- * ```
35
+ * Low-level descriptor for the `max-hours-week` rule.
47
36
  *
48
- * @example Students limited to 20 hours during term time
49
- * ```ts
50
- * createMaxHoursWeekRule({
51
- * roleIds: ["student"],
52
- * hours: 20,
53
- * recurringPeriods: [
54
- * { name: "fall-term", startMonth: 9, startDay: 1, endMonth: 12, endDay: 15 },
55
- * ],
56
- * priority: "MANDATORY",
57
- * });
58
- * ```
37
+ * @category Rules
59
38
  */
60
- export function createMaxHoursWeekRule(config: MaxHoursWeekConfig): CompilationRule {
61
- const parsed = MaxHoursWeekSchema.parse(config);
62
- const entityScopeValue = parseEntityScope(parsed);
63
- const timeScopeValue = parseTimeScope(parsed);
64
- const { hours, priority, weekStartsOn } = parsed;
65
- const maxMinutes = hours * 60;
66
- const group = ruleGroup(
67
- `max-hours-week:${hours}`,
68
- `Max ${hours}h per week`,
69
- entityScopeValue,
70
- timeScopeValue,
71
- );
72
-
73
- return {
74
- compile(b) {
75
- const targetMembers = resolveMembersFromScope(entityScopeValue, b.members);
76
- const activeDays = resolveActiveDaysFromScope(timeScopeValue, b.days);
39
+ export const maxHoursWeekRuleDescriptor = defineRuleDescriptor({
40
+ name: "max-hours-week",
41
+ schema: MaxHoursWeekSchema,
42
+ compile(config, ctx) {
43
+ const entityScopeValue = parseEntityScope(config);
44
+ const timeScopeValue = parseTimeScope(config);
45
+ const { hours, priority, weekStartsOn } = config;
46
+ const maxMinutes = hours * 60;
47
+ const group = ruleGroup(
48
+ `max-hours-week:${hours}`,
49
+ `Max ${hours}h per week`,
50
+ entityScopeValue,
51
+ timeScopeValue,
52
+ );
53
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
54
+ const activeDays = resolveActiveDaysFromScope(timeScopeValue, [...ctx.days]);
55
+ const weeks = splitIntoWeeks(activeDays, weekStartsOn ?? ctx.weekStartsOn);
77
56
 
78
- if (targetMembers.length === 0 || activeDays.length === 0) return;
57
+ const artifacts = targetMembers.flatMap((member) =>
58
+ weeks.flatMap((weekDays) => {
59
+ const weekStart = weekDays[0];
60
+ if (!weekStart) return [];
79
61
 
80
- const weeks = splitIntoWeeks(activeDays, weekStartsOn ?? b.weekStartsOn);
62
+ const terms = assignmentTermsForDays(
63
+ member,
64
+ weekDays,
65
+ ctx.shiftPatterns,
66
+ patternDurationMinutes,
67
+ );
68
+ if (terms.length === 0) return [];
81
69
 
82
- for (const emp of targetMembers) {
83
- for (const weekDays of weeks) {
84
- const terms: Term[] = [];
85
- for (const day of weekDays) {
86
- for (const pattern of b.shiftPatterns) {
87
- if (!b.canAssign(emp, pattern)) continue;
88
- if (!b.patternAvailableOnDay(pattern, day)) continue;
89
- terms.push({
90
- var: b.assignment(emp.id, pattern.id, day),
91
- coeff: b.patternDuration(pattern.id),
92
- });
93
- }
94
- }
70
+ const description = `${member.id} max ${hours}h in week starting ${weekStart.iso}`;
71
+ const context = { memberIds: [member.id], days: weekDays.map((day) => day.iso) };
72
+ const constraintId = `max-hours-week:${member.id}:${weekStart.iso}`;
95
73
 
96
- if (terms.length === 0) continue;
74
+ return [
75
+ priority === "MANDATORY"
76
+ ? hardConstraint({
77
+ group,
78
+ description,
79
+ context,
80
+ validation: reportValidation(constraintId),
81
+ terms,
82
+ comparator: "<=",
83
+ targetValue: maxMinutes,
84
+ })
85
+ : softConstraint({
86
+ group,
87
+ description,
88
+ context,
89
+ validation: reportValidation(),
90
+ terms,
91
+ comparator: "<=",
92
+ targetValue: maxMinutes,
93
+ penalty: priorityToPenalty(priority),
94
+ constraintId,
95
+ }),
96
+ ];
97
+ }),
98
+ );
97
99
 
98
- const weekLabel = weekDays[0]!;
99
- const constraintId = `max-hours-week:${emp.id}:${weekLabel}`;
100
-
101
- if (priority === "MANDATORY") {
102
- b.addLinear(terms, "<=", maxMinutes);
103
- } else {
104
- b.addSoftLinear(terms, "<=", maxMinutes, priorityToPenalty(priority), constraintId);
105
- b.reporter.trackConstraint({
106
- id: constraintId,
107
- type: "rule",
108
- rule: "max-hours-week",
109
- description: `${emp.id} max ${hours}h in week starting ${weekLabel}`,
110
- targetValue: maxMinutes,
111
- comparator: "<=",
112
- day: weekLabel,
113
- context: { memberIds: [emp.id], days: weekDays },
114
- group,
115
- });
116
- }
117
- }
118
- }
119
- },
120
- };
121
- }
100
+ return {
101
+ rule: "max-hours-week",
102
+ artifacts,
103
+ };
104
+ },
105
+ });
@@ -1,19 +1,20 @@
1
1
  import * as z from "zod";
2
- import type { CompilationRule } from "../model-builder.js";
3
- import type { Term } from "../types.js";
2
+ import { defineRuleDescriptor } from "../rule-descriptor.js";
4
3
  import { priorityToPenalty } from "../utils.js";
5
4
  import {
6
5
  PrioritySchema,
7
6
  entityScope,
8
- timeScope,
9
7
  parseEntityScope,
10
8
  parseTimeScope,
11
- resolveMembersFromScope,
12
9
  resolveActiveDaysFromScope,
10
+ resolveMembersFromScope,
13
11
  ruleGroup,
12
+ timeScope,
14
13
  } from "./scope.types.js";
14
+ import { assignmentTermsForDay } from "./assignment-terms.js";
15
+ import { hardConstraint, reportValidation, softConstraint } from "./artifacts.js";
15
16
 
16
- const MaxShiftsDaySchema = z
17
+ export const MaxShiftsDaySchema = z
17
18
  .object({
18
19
  shifts: z.number().int().min(1),
19
20
  priority: PrioritySchema,
@@ -22,94 +23,73 @@ const MaxShiftsDaySchema = z
22
23
  .and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
23
24
 
24
25
  /**
25
- * Configuration for {@link createMaxShiftsDayRule}.
26
- *
27
- * - `shifts` (required): maximum number of shifts per day (at least 1)
28
- * - `priority` (required): how strictly the solver enforces this rule
29
- *
30
- * Entity scoping (at most one): `memberIds`, `roleIds`, `skillIds`
31
- * Time scoping (at most one, optional): `dateRange`, `specificDates`, `dayOfWeek`, `recurringPeriods`
26
+ * Configuration for {@link maxShiftsDayRuleDescriptor}.
32
27
  */
33
28
  export type MaxShiftsDayConfig = z.infer<typeof MaxShiftsDaySchema>;
34
29
 
35
30
  /**
36
- * Limits how many shifts a person can work in a single day.
37
- *
38
- * Controls the maximum number of distinct shift assignments per day,
39
- * regardless of shift duration. For limiting total hours worked, use `max-hours-day`.
31
+ * Low-level descriptor for the `max-shifts-day` rule.
40
32
  *
41
- * @param config - See {@link MaxShiftsDayConfig}
42
- * @example Limit to one shift per day
43
- * ```ts
44
- * createMaxShiftsDayRule({
45
- * shifts: 1,
46
- * priority: "MANDATORY",
47
- * });
48
- * ```
33
+ * @remarks
34
+ * This rule limits distinct assignments per day, regardless of their duration.
35
+ * Use {@link maxHoursDayRuleDescriptor} to limit assigned time instead.
49
36
  *
50
- * @example Students can work 2 shifts on weekends only
51
- * ```ts
52
- * createMaxShiftsDayRule({
53
- * roleIds: ["student"],
54
- * shifts: 2,
55
- * dayOfWeek: ["saturday", "sunday"],
56
- * priority: "MANDATORY",
57
- * });
58
- * ```
37
+ * @category Rules
59
38
  */
60
- export function createMaxShiftsDayRule(config: MaxShiftsDayConfig): CompilationRule {
61
- const parsed = MaxShiftsDaySchema.parse(config);
62
- const entityScopeValue = parseEntityScope(parsed);
63
- const timeScopeValue = parseTimeScope(parsed);
64
- const { shifts, priority } = parsed;
65
- const group = ruleGroup(
66
- `max-shifts-day:${shifts}`,
67
- `Max ${shifts} shift${shifts === 1 ? "" : "s"} per day`,
68
- entityScopeValue,
69
- timeScopeValue,
70
- );
71
-
72
- return {
73
- compile(b) {
74
- const targetMembers = resolveMembersFromScope(entityScopeValue, b.members);
75
- const activeDays = resolveActiveDaysFromScope(timeScopeValue, b.days);
76
-
77
- if (targetMembers.length === 0 || activeDays.length === 0) return;
39
+ export const maxShiftsDayRuleDescriptor = defineRuleDescriptor({
40
+ name: "max-shifts-day",
41
+ schema: MaxShiftsDaySchema,
42
+ compile(config, ctx) {
43
+ const entityScopeValue = parseEntityScope(config);
44
+ const timeScopeValue = parseTimeScope(config);
45
+ const { shifts, priority } = config;
46
+ const group = ruleGroup(
47
+ `max-shifts-day:${shifts}`,
48
+ `Max ${shifts} shift${shifts === 1 ? "" : "s"} per day`,
49
+ entityScopeValue,
50
+ timeScopeValue,
51
+ );
52
+ const targetMembers = resolveMembersFromScope(entityScopeValue, [...ctx.members]);
53
+ const activeDays = resolveActiveDaysFromScope(timeScopeValue, [...ctx.days]);
78
54
 
79
- for (const emp of targetMembers) {
80
- for (const day of activeDays) {
81
- const terms: Term[] = [];
82
- for (const pattern of b.shiftPatterns) {
83
- if (!b.canAssign(emp, pattern)) continue;
84
- if (!b.patternAvailableOnDay(pattern, day)) continue;
85
- terms.push({
86
- var: b.assignment(emp.id, pattern.id, day),
87
- coeff: 1,
88
- });
89
- }
55
+ const artifacts = targetMembers.flatMap((member) =>
56
+ activeDays.flatMap((day) => {
57
+ const terms = assignmentTermsForDay(member, day, ctx.shiftPatterns, () => 1);
58
+ if (terms.length === 0) return [];
90
59
 
91
- if (terms.length === 0) continue;
60
+ const description = `${member.id} max ${shifts} shift${shifts === 1 ? "" : "s"} on ${day.iso}`;
61
+ const context = { memberIds: [member.id], days: [day.iso] };
62
+ const constraintId = `max-shifts-day:${member.id}:${day.iso}`;
92
63
 
93
- const constraintId = `max-shifts-day:${emp.id}:${day}`;
64
+ return [
65
+ priority === "MANDATORY"
66
+ ? hardConstraint({
67
+ group,
68
+ description,
69
+ context,
70
+ validation: reportValidation(constraintId),
71
+ terms,
72
+ comparator: "<=",
73
+ targetValue: shifts,
74
+ })
75
+ : softConstraint({
76
+ group,
77
+ description,
78
+ context,
79
+ validation: reportValidation(),
80
+ terms,
81
+ comparator: "<=",
82
+ targetValue: shifts,
83
+ penalty: priorityToPenalty(priority),
84
+ constraintId,
85
+ }),
86
+ ];
87
+ }),
88
+ );
94
89
 
95
- if (priority === "MANDATORY") {
96
- b.addLinear(terms, "<=", shifts);
97
- } else {
98
- b.addSoftLinear(terms, "<=", shifts, priorityToPenalty(priority), constraintId);
99
- b.reporter.trackConstraint({
100
- id: constraintId,
101
- type: "rule",
102
- rule: "max-shifts-day",
103
- description: `${emp.id} max ${shifts} shift${shifts === 1 ? "" : "s"} on ${day}`,
104
- targetValue: shifts,
105
- comparator: "<=",
106
- day,
107
- context: { memberIds: [emp.id], days: [day] },
108
- group,
109
- });
110
- }
111
- }
112
- }
113
- },
114
- };
115
- }
90
+ return {
91
+ rule: "max-shifts-day",
92
+ artifacts,
93
+ };
94
+ },
95
+ });