dabke 0.78.2 → 0.80.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.
- package/CHANGELOG.md +34 -0
- package/README.md +68 -31
- package/dist/client.types.d.ts +58 -0
- package/dist/client.types.d.ts.map +1 -1
- package/dist/client.types.js.map +1 -1
- package/dist/cpsat/model-builder.d.ts +13 -2
- package/dist/cpsat/model-builder.d.ts.map +1 -1
- package/dist/cpsat/model-builder.js.map +1 -1
- package/dist/cpsat/response.d.ts +12 -3
- package/dist/cpsat/response.d.ts.map +1 -1
- package/dist/cpsat/response.js.map +1 -1
- package/dist/cpsat/rules/assign-together.d.ts +7 -0
- package/dist/cpsat/rules/assign-together.d.ts.map +1 -1
- package/dist/cpsat/rules/assign-together.js +1 -0
- package/dist/cpsat/rules/assign-together.js.map +1 -1
- package/dist/cpsat/rules/employee-assignment-priority.d.ts +11 -37
- package/dist/cpsat/rules/employee-assignment-priority.d.ts.map +1 -1
- package/dist/cpsat/rules/employee-assignment-priority.js +12 -104
- package/dist/cpsat/rules/employee-assignment-priority.js.map +1 -1
- package/dist/cpsat/rules/location-preference.d.ts +12 -10
- package/dist/cpsat/rules/location-preference.d.ts.map +1 -1
- package/dist/cpsat/rules/location-preference.js +16 -14
- package/dist/cpsat/rules/location-preference.js.map +1 -1
- package/dist/cpsat/rules/max-consecutive-days.d.ts +12 -13
- package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
- package/dist/cpsat/rules/max-consecutive-days.js +11 -12
- package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
- package/dist/cpsat/rules/max-hours-day.d.ts +12 -28
- package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
- package/dist/cpsat/rules/max-hours-day.js +12 -95
- package/dist/cpsat/rules/max-hours-day.js.map +1 -1
- package/dist/cpsat/rules/max-hours-week.d.ts +14 -34
- package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
- package/dist/cpsat/rules/max-hours-week.js +12 -103
- package/dist/cpsat/rules/max-hours-week.js.map +1 -1
- package/dist/cpsat/rules/max-shifts-day.d.ts +14 -39
- package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
- package/dist/cpsat/rules/max-shifts-day.js +14 -106
- package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
- package/dist/cpsat/rules/min-consecutive-days.d.ts +12 -13
- package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
- package/dist/cpsat/rules/min-consecutive-days.js +11 -12
- package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
- package/dist/cpsat/rules/min-hours-day.d.ts +12 -13
- package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
- package/dist/cpsat/rules/min-hours-day.js +11 -12
- package/dist/cpsat/rules/min-hours-day.js.map +1 -1
- package/dist/cpsat/rules/min-hours-week.d.ts +13 -13
- package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
- package/dist/cpsat/rules/min-hours-week.js +10 -14
- package/dist/cpsat/rules/min-hours-week.js.map +1 -1
- package/dist/cpsat/rules/min-rest-between-shifts.d.ts +13 -14
- package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
- package/dist/cpsat/rules/min-rest-between-shifts.js +11 -12
- package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
- package/dist/cpsat/rules/resolver.d.ts +2 -2
- package/dist/cpsat/rules/resolver.d.ts.map +1 -1
- package/dist/cpsat/rules/resolver.js +55 -30
- package/dist/cpsat/rules/resolver.js.map +1 -1
- package/dist/cpsat/rules/scope.types.d.ts +267 -0
- package/dist/cpsat/rules/scope.types.d.ts.map +1 -0
- package/dist/cpsat/rules/scope.types.js +325 -0
- package/dist/cpsat/rules/scope.types.js.map +1 -0
- package/dist/cpsat/rules/time-off.d.ts +21 -25
- package/dist/cpsat/rules/time-off.d.ts.map +1 -1
- package/dist/cpsat/rules/time-off.js +20 -110
- package/dist/cpsat/rules/time-off.js.map +1 -1
- package/dist/cpsat/semantic-time.d.ts +2 -0
- package/dist/cpsat/semantic-time.d.ts.map +1 -1
- package/dist/cpsat/semantic-time.js +2 -4
- package/dist/cpsat/semantic-time.js.map +1 -1
- package/dist/cpsat/types.d.ts +22 -6
- package/dist/cpsat/types.d.ts.map +1 -1
- package/dist/cpsat/utils.d.ts +1 -1
- package/dist/cpsat/utils.js +1 -1
- package/dist/cpsat/validation-reporter.js +1 -1
- package/dist/cpsat/validation-reporter.js.map +1 -1
- package/dist/datetime.utils.d.ts +14 -14
- package/dist/datetime.utils.d.ts.map +1 -1
- package/dist/datetime.utils.js +26 -27
- package/dist/datetime.utils.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/llms.d.ts +1 -1
- package/dist/llms.d.ts.map +1 -1
- package/dist/llms.js +1 -1
- package/dist/llms.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/solver-container.js +3 -1
- package/dist/testing/solver-container.js.map +1 -1
- package/dist/types.d.ts +18 -20
- package/dist/types.d.ts.map +1 -1
- package/llms.txt +516 -263
- package/package.json +25 -25
- package/src/client.types.ts +58 -0
- package/src/cpsat/model-builder.ts +19 -7
- package/src/cpsat/response.ts +12 -3
- package/src/cpsat/rules/assign-together.ts +7 -0
- package/src/cpsat/rules/employee-assignment-priority.ts +28 -128
- package/src/cpsat/rules/location-preference.ts +24 -17
- package/src/cpsat/rules/max-consecutive-days.ts +19 -15
- package/src/cpsat/rules/max-hours-day.ts +29 -119
- package/src/cpsat/rules/max-hours-week.ts +42 -135
- package/src/cpsat/rules/max-shifts-day.ts +31 -130
- package/src/cpsat/rules/min-consecutive-days.ts +19 -15
- package/src/cpsat/rules/min-hours-day.ts +19 -15
- package/src/cpsat/rules/min-hours-week.ts +28 -26
- package/src/cpsat/rules/min-rest-between-shifts.ts +21 -17
- package/src/cpsat/rules/resolver.ts +66 -45
- package/src/cpsat/rules/scope.types.ts +534 -0
- package/src/cpsat/rules/time-off.ts +48 -145
- package/src/cpsat/semantic-time.ts +10 -8
- package/src/cpsat/types.ts +22 -6
- package/src/cpsat/utils.ts +1 -1
- package/src/cpsat/validation-reporter.ts +1 -1
- package/src/datetime.utils.ts +27 -29
- package/src/index.ts +11 -7
- package/src/llms.ts +1 -1
- package/src/testing/index.ts +1 -1
- package/src/testing/solver-container.ts +3 -3
- package/src/types.ts +27 -31
- package/dist/cpsat/rules/scoping.d.ts +0 -129
- package/dist/cpsat/rules/scoping.d.ts.map +0 -1
- package/dist/cpsat/rules/scoping.js +0 -190
- package/dist/cpsat/rules/scoping.js.map +0 -1
- package/src/cpsat/rules/scoping.ts +0 -340
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe scoping for rule configurations.
|
|
3
|
+
*
|
|
4
|
+
* Uses the `?: never` pattern to enforce mutual exclusivity at compile time:
|
|
5
|
+
* when one scope field is present, the others in the same dimension are typed
|
|
6
|
+
* as `never`, making it a `tsc` error to provide them.
|
|
7
|
+
*
|
|
8
|
+
* Array scope fields use non-empty tuple types (`[T, ...T[]]`) so that
|
|
9
|
+
* empty arrays are compile-time errors.
|
|
10
|
+
*
|
|
11
|
+
* Two dimensions of scoping:
|
|
12
|
+
* - **Entity scope**: who the rule applies to (employees, roles, or skills)
|
|
13
|
+
* - **Time scope**: when the rule applies (date range, specific dates, day of week, or recurring)
|
|
14
|
+
*
|
|
15
|
+
* Each rule declares which scopes it supports via the `entityScope()`,
|
|
16
|
+
* `timeScope()`, and `requiredTimeScope()` builder functions.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // time-off: entity optional, time required
|
|
21
|
+
* const TimeOffSchema = z.object({ priority: PrioritySchema })
|
|
22
|
+
* .and(entityScope(["employees", "roles", "skills"]))
|
|
23
|
+
* .and(requiredTimeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
|
|
24
|
+
*
|
|
25
|
+
* // max-hours-week: both optional
|
|
26
|
+
* const MaxHoursWeekSchema = z.object({ hours: z.number(), priority: PrioritySchema })
|
|
27
|
+
* .and(entityScope(["employees", "roles", "skills"]))
|
|
28
|
+
* .and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
|
|
29
|
+
*
|
|
30
|
+
* // max-consecutive-days: only employee scoping, no time
|
|
31
|
+
* const MaxConsecutiveDaysSchema = z.object({ days: z.number(), priority: PrioritySchema })
|
|
32
|
+
* .and(entityScope(["employees"]));
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
import * as z from "zod";
|
|
36
|
+
import { type DayOfWeek } from "../../types.js";
|
|
37
|
+
import type { SchedulingEmployee } from "../types.js";
|
|
38
|
+
export type EntityKey = "employees" | "roles" | "skills";
|
|
39
|
+
export type TimeKey = "dateRange" | "specificDates" | "dayOfWeek" | "recurring";
|
|
40
|
+
/**
|
|
41
|
+
* The field shape when an entity scope variant is active (selected).
|
|
42
|
+
* Each variant adds a single field with a non-empty array.
|
|
43
|
+
*/
|
|
44
|
+
type ActiveEntityFields = {
|
|
45
|
+
employees: {
|
|
46
|
+
employeeIds: NonEmptyArray<string>;
|
|
47
|
+
};
|
|
48
|
+
roles: {
|
|
49
|
+
roleIds: NonEmptyArray<string>;
|
|
50
|
+
};
|
|
51
|
+
skills: {
|
|
52
|
+
skillIds: NonEmptyArray<string>;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The field shape when an entity scope variant is inactive (not selected).
|
|
57
|
+
* The field is typed as `?: never` so it cannot be provided.
|
|
58
|
+
*/
|
|
59
|
+
type InactiveEntityFields = {
|
|
60
|
+
employees: {
|
|
61
|
+
employeeIds?: never;
|
|
62
|
+
};
|
|
63
|
+
roles: {
|
|
64
|
+
roleIds?: never;
|
|
65
|
+
};
|
|
66
|
+
skills: {
|
|
67
|
+
skillIds?: never;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
type NonEmptyArray<T> = [T, ...T[]];
|
|
71
|
+
/** Recurring calendar period for time scoping. */
|
|
72
|
+
export interface RecurringPeriod {
|
|
73
|
+
name: string;
|
|
74
|
+
startMonth: number;
|
|
75
|
+
startDay: number;
|
|
76
|
+
endMonth: number;
|
|
77
|
+
endDay: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The field shape when a time scope variant is active (selected).
|
|
81
|
+
*/
|
|
82
|
+
type ActiveTimeFields = {
|
|
83
|
+
dateRange: {
|
|
84
|
+
dateRange: {
|
|
85
|
+
start: string;
|
|
86
|
+
end: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
specificDates: {
|
|
90
|
+
specificDates: NonEmptyArray<string>;
|
|
91
|
+
};
|
|
92
|
+
dayOfWeek: {
|
|
93
|
+
dayOfWeek: NonEmptyArray<DayOfWeek>;
|
|
94
|
+
};
|
|
95
|
+
recurring: {
|
|
96
|
+
recurringPeriods: NonEmptyArray<RecurringPeriod>;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* The field shape when a time scope variant is inactive (not selected).
|
|
101
|
+
*/
|
|
102
|
+
type InactiveTimeFields = {
|
|
103
|
+
dateRange: {
|
|
104
|
+
dateRange?: never;
|
|
105
|
+
};
|
|
106
|
+
specificDates: {
|
|
107
|
+
specificDates?: never;
|
|
108
|
+
};
|
|
109
|
+
dayOfWeek: {
|
|
110
|
+
dayOfWeek?: never;
|
|
111
|
+
};
|
|
112
|
+
recurring: {
|
|
113
|
+
recurringPeriods?: never;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Merges all values of an object type into an intersection.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* MergeValues<{ a: { x: 1 }; b: { y: 2 } }> = { x: 1 } & { y: 2 }
|
|
121
|
+
*/
|
|
122
|
+
type MergeValues<T> = {
|
|
123
|
+
[K in keyof T]: (x: T[K]) => void;
|
|
124
|
+
} extends {
|
|
125
|
+
[K in keyof T]: (x: infer U) => void;
|
|
126
|
+
} ? U : never;
|
|
127
|
+
/**
|
|
128
|
+
* Exactly one of the specified keys must be present.
|
|
129
|
+
* The active key's field is required; all others are `?: never`.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ExclusiveOne<ActiveEntityFields, InactiveEntityFields, "employees" | "roles">
|
|
133
|
+
* =
|
|
134
|
+
* | { employeeIds: [string, ...string[]]; roleIds?: never }
|
|
135
|
+
* | { roleIds: [string, ...string[]]; employeeIds?: never }
|
|
136
|
+
*/
|
|
137
|
+
export type ExclusiveOne<Active extends Record<string, object>, Inactive extends Record<string, object>, Keys extends keyof Active & keyof Inactive> = {
|
|
138
|
+
[K in Keys]: Active[K] & MergeValues<Pick<Inactive, Exclude<Keys, K>>>;
|
|
139
|
+
}[Keys];
|
|
140
|
+
/**
|
|
141
|
+
* At most one of the specified keys may be present (or none).
|
|
142
|
+
* Same as {@link ExclusiveOne} plus the case where all fields are `?: never`.
|
|
143
|
+
*/
|
|
144
|
+
export type MaybeOne<Active extends Record<string, object>, Inactive extends Record<string, object>, Keys extends keyof Active & keyof Inactive> = ExclusiveOne<Active, Inactive, Keys> | MergeValues<Pick<Inactive, Keys>>;
|
|
145
|
+
/** Entity scope type for a subset of entity keys (at most one). */
|
|
146
|
+
export type EntityScopeType<K extends EntityKey> = MaybeOne<ActiveEntityFields, InactiveEntityFields, K>;
|
|
147
|
+
/** Time scope type for a subset of time keys (at most one, optional). */
|
|
148
|
+
export type OptionalTimeScopeType<K extends TimeKey> = MaybeOne<ActiveTimeFields, InactiveTimeFields, K>;
|
|
149
|
+
/** Time scope type for a subset of time keys (exactly one, required). */
|
|
150
|
+
export type RequiredTimeScopeType<K extends TimeKey> = ExclusiveOne<ActiveTimeFields, InactiveTimeFields, K>;
|
|
151
|
+
/**
|
|
152
|
+
* Creates a Zod schema for optional entity scoping (at most one of the
|
|
153
|
+
* specified entity variants).
|
|
154
|
+
*
|
|
155
|
+
* The returned schema accepts flat fields (`employeeIds`, `roleIds`, `skillIds`)
|
|
156
|
+
* but the TypeScript type enforces mutual exclusivity via `?: never`.
|
|
157
|
+
*
|
|
158
|
+
* @param keys - Which entity scope variants to support
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* // Supports all entity scopes
|
|
163
|
+
* entityScope(["employees", "roles", "skills"])
|
|
164
|
+
*
|
|
165
|
+
* // Only employee scoping
|
|
166
|
+
* entityScope(["employees"])
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export declare function entityScope<const K extends readonly EntityKey[]>(keys: K): z.ZodType<EntityScopeType<K[number]>>;
|
|
170
|
+
/**
|
|
171
|
+
* Creates a Zod schema for optional time scoping (at most one of the
|
|
172
|
+
* specified time variants, or none).
|
|
173
|
+
*
|
|
174
|
+
* @param keys - Which time scope variants to support
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* // Supports all time scopes, all optional
|
|
179
|
+
* timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"])
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export declare function timeScope<const K extends readonly TimeKey[]>(keys: K): z.ZodType<OptionalTimeScopeType<K[number]>>;
|
|
183
|
+
/**
|
|
184
|
+
* Creates a Zod schema for required time scoping (exactly one of the
|
|
185
|
+
* specified time variants must be present).
|
|
186
|
+
*
|
|
187
|
+
* @param keys - Which time scope variants to support
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* // Exactly one time scope required (for time-off)
|
|
192
|
+
* requiredTimeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"])
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
export declare function requiredTimeScope<const K extends readonly TimeKey[]>(keys: K): z.ZodType<RequiredTimeScopeType<K[number]>>;
|
|
196
|
+
/**
|
|
197
|
+
* Parsed entity scope from a flat config.
|
|
198
|
+
* Used internally by scope resolution functions.
|
|
199
|
+
*/
|
|
200
|
+
export type ParsedEntityScope = {
|
|
201
|
+
type: "global";
|
|
202
|
+
} | {
|
|
203
|
+
type: "employees";
|
|
204
|
+
employeeIds: string[];
|
|
205
|
+
} | {
|
|
206
|
+
type: "roles";
|
|
207
|
+
roleIds: string[];
|
|
208
|
+
} | {
|
|
209
|
+
type: "skills";
|
|
210
|
+
skillIds: string[];
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Parsed time scope from a flat config.
|
|
214
|
+
* Used internally by scope resolution functions.
|
|
215
|
+
*/
|
|
216
|
+
export type ParsedTimeScope = {
|
|
217
|
+
type: "none";
|
|
218
|
+
} | {
|
|
219
|
+
type: "dateRange";
|
|
220
|
+
start: string;
|
|
221
|
+
end: string;
|
|
222
|
+
} | {
|
|
223
|
+
type: "specificDates";
|
|
224
|
+
dates: string[];
|
|
225
|
+
} | {
|
|
226
|
+
type: "dayOfWeek";
|
|
227
|
+
days: DayOfWeek[];
|
|
228
|
+
} | {
|
|
229
|
+
type: "recurring";
|
|
230
|
+
periods: RecurringPeriod[];
|
|
231
|
+
};
|
|
232
|
+
/** Input shape accepted by {@link parseEntityScope}. */
|
|
233
|
+
export interface EntityScopeInput {
|
|
234
|
+
employeeIds?: string[];
|
|
235
|
+
roleIds?: string[];
|
|
236
|
+
skillIds?: string[];
|
|
237
|
+
[key: string]: unknown;
|
|
238
|
+
}
|
|
239
|
+
/** Input shape accepted by {@link parseTimeScope}. */
|
|
240
|
+
export interface TimeScopeInput {
|
|
241
|
+
dateRange?: {
|
|
242
|
+
start: string;
|
|
243
|
+
end: string;
|
|
244
|
+
};
|
|
245
|
+
specificDates?: string[];
|
|
246
|
+
dayOfWeek?: DayOfWeek[];
|
|
247
|
+
recurringPeriods?: RecurringPeriod[];
|
|
248
|
+
[key: string]: unknown;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Extracts the entity scope from a parsed flat config.
|
|
252
|
+
*/
|
|
253
|
+
export declare function parseEntityScope(config: EntityScopeInput): ParsedEntityScope;
|
|
254
|
+
/**
|
|
255
|
+
* Extracts the time scope from a parsed flat config.
|
|
256
|
+
*/
|
|
257
|
+
export declare function parseTimeScope(config: TimeScopeInput): ParsedTimeScope;
|
|
258
|
+
/**
|
|
259
|
+
* Resolves which employees a rule applies to based on entity scope.
|
|
260
|
+
*/
|
|
261
|
+
export declare function resolveEmployeesFromScope(scope: ParsedEntityScope, employees: SchedulingEmployee[]): SchedulingEmployee[];
|
|
262
|
+
/**
|
|
263
|
+
* Resolves which days a rule applies to based on time scope.
|
|
264
|
+
*/
|
|
265
|
+
export declare function resolveActiveDaysFromScope(scope: ParsedTimeScope, allDays: string[]): string[];
|
|
266
|
+
export {};
|
|
267
|
+
//# sourceMappingURL=scope.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.types.d.ts","sourceRoot":"","sources":["../../../src/cpsat/rules/scope.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe scoping for rule configurations.
|
|
3
|
+
*
|
|
4
|
+
* Uses the `?: never` pattern to enforce mutual exclusivity at compile time:
|
|
5
|
+
* when one scope field is present, the others in the same dimension are typed
|
|
6
|
+
* as `never`, making it a `tsc` error to provide them.
|
|
7
|
+
*
|
|
8
|
+
* Array scope fields use non-empty tuple types (`[T, ...T[]]`) so that
|
|
9
|
+
* empty arrays are compile-time errors.
|
|
10
|
+
*
|
|
11
|
+
* Two dimensions of scoping:
|
|
12
|
+
* - **Entity scope**: who the rule applies to (employees, roles, or skills)
|
|
13
|
+
* - **Time scope**: when the rule applies (date range, specific dates, day of week, or recurring)
|
|
14
|
+
*
|
|
15
|
+
* Each rule declares which scopes it supports via the `entityScope()`,
|
|
16
|
+
* `timeScope()`, and `requiredTimeScope()` builder functions.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // time-off: entity optional, time required
|
|
21
|
+
* const TimeOffSchema = z.object({ priority: PrioritySchema })
|
|
22
|
+
* .and(entityScope(["employees", "roles", "skills"]))
|
|
23
|
+
* .and(requiredTimeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
|
|
24
|
+
*
|
|
25
|
+
* // max-hours-week: both optional
|
|
26
|
+
* const MaxHoursWeekSchema = z.object({ hours: z.number(), priority: PrioritySchema })
|
|
27
|
+
* .and(entityScope(["employees", "roles", "skills"]))
|
|
28
|
+
* .and(timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"]));
|
|
29
|
+
*
|
|
30
|
+
* // max-consecutive-days: only employee scoping, no time
|
|
31
|
+
* const MaxConsecutiveDaysSchema = z.object({ days: z.number(), priority: PrioritySchema })
|
|
32
|
+
* .and(entityScope(["employees"]));
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
import * as z from "zod";
|
|
36
|
+
import { DayOfWeekSchema } from "../../types.js";
|
|
37
|
+
import { parseDayString } from "../utils.js";
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Zod Schemas for Individual Fields
|
|
40
|
+
// ============================================================================
|
|
41
|
+
const recurringPeriodSchema = z.object({
|
|
42
|
+
name: z.string(),
|
|
43
|
+
startMonth: z.number(),
|
|
44
|
+
startDay: z.number(),
|
|
45
|
+
endMonth: z.number(),
|
|
46
|
+
endDay: z.number(),
|
|
47
|
+
});
|
|
48
|
+
const entityFieldSchemas = {
|
|
49
|
+
employees: { employeeIds: z.array(z.string()).nonempty() },
|
|
50
|
+
roles: { roleIds: z.array(z.string()).nonempty() },
|
|
51
|
+
skills: { skillIds: z.array(z.string()).nonempty() },
|
|
52
|
+
};
|
|
53
|
+
const timeFieldSchemas = {
|
|
54
|
+
dateRange: {
|
|
55
|
+
dateRange: z.object({
|
|
56
|
+
start: z.iso.date(),
|
|
57
|
+
end: z.iso.date(),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
specificDates: { specificDates: z.array(z.iso.date()).nonempty() },
|
|
61
|
+
dayOfWeek: { dayOfWeek: z.array(DayOfWeekSchema).nonempty() },
|
|
62
|
+
recurring: { recurringPeriods: z.array(recurringPeriodSchema).nonempty() },
|
|
63
|
+
};
|
|
64
|
+
/** Maps entity keys to their field names. */
|
|
65
|
+
const entityFieldNames = {
|
|
66
|
+
employees: "employeeIds",
|
|
67
|
+
roles: "roleIds",
|
|
68
|
+
skills: "skillIds",
|
|
69
|
+
};
|
|
70
|
+
/** Maps time keys to their field names. */
|
|
71
|
+
const timeFieldNames = {
|
|
72
|
+
dateRange: "dateRange",
|
|
73
|
+
specificDates: "specificDates",
|
|
74
|
+
dayOfWeek: "dayOfWeek",
|
|
75
|
+
recurring: "recurringPeriods",
|
|
76
|
+
};
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// Scope Builder Functions
|
|
79
|
+
// ============================================================================
|
|
80
|
+
/**
|
|
81
|
+
* Creates a Zod schema for optional entity scoping (at most one of the
|
|
82
|
+
* specified entity variants).
|
|
83
|
+
*
|
|
84
|
+
* The returned schema accepts flat fields (`employeeIds`, `roleIds`, `skillIds`)
|
|
85
|
+
* but the TypeScript type enforces mutual exclusivity via `?: never`.
|
|
86
|
+
*
|
|
87
|
+
* @param keys - Which entity scope variants to support
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* // Supports all entity scopes
|
|
92
|
+
* entityScope(["employees", "roles", "skills"])
|
|
93
|
+
*
|
|
94
|
+
* // Only employee scoping
|
|
95
|
+
* entityScope(["employees"])
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function entityScope(keys) {
|
|
99
|
+
const shape = {};
|
|
100
|
+
for (const key of keys) {
|
|
101
|
+
for (const [fieldName, fieldSchema] of Object.entries(entityFieldSchemas[key])) {
|
|
102
|
+
shape[fieldName] = fieldSchema.optional();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const schema = z.object(shape).check((payload) => {
|
|
106
|
+
const values = payload.value;
|
|
107
|
+
const activeFields = keys.filter((key) => {
|
|
108
|
+
const fieldName = entityFieldNames[key];
|
|
109
|
+
const value = values[fieldName];
|
|
110
|
+
return Array.isArray(value) && value.length > 0;
|
|
111
|
+
});
|
|
112
|
+
if (activeFields.length > 1) {
|
|
113
|
+
const fieldNamesList = keys.map((k) => entityFieldNames[k]).join("/");
|
|
114
|
+
payload.issues.push({
|
|
115
|
+
code: "custom",
|
|
116
|
+
message: `Only one of ${fieldNamesList} is allowed`,
|
|
117
|
+
input: payload.value,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return schema;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Creates a Zod schema for optional time scoping (at most one of the
|
|
125
|
+
* specified time variants, or none).
|
|
126
|
+
*
|
|
127
|
+
* @param keys - Which time scope variants to support
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // Supports all time scopes, all optional
|
|
132
|
+
* timeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"])
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export function timeScope(keys) {
|
|
136
|
+
const shape = {};
|
|
137
|
+
for (const key of keys) {
|
|
138
|
+
for (const [fieldName, fieldSchema] of Object.entries(timeFieldSchemas[key])) {
|
|
139
|
+
shape[fieldName] = fieldSchema.optional();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const schema = z.object(shape).check((payload) => {
|
|
143
|
+
const values = payload.value;
|
|
144
|
+
const activeFields = keys.filter((key) => {
|
|
145
|
+
const fieldName = timeFieldNames[key];
|
|
146
|
+
const value = values[fieldName];
|
|
147
|
+
if (!value)
|
|
148
|
+
return false;
|
|
149
|
+
if (fieldName === "dateRange")
|
|
150
|
+
return true;
|
|
151
|
+
return Array.isArray(value) && value.length > 0;
|
|
152
|
+
});
|
|
153
|
+
if (activeFields.length > 1) {
|
|
154
|
+
const fieldNamesList = keys.map((k) => timeFieldNames[k]).join("/");
|
|
155
|
+
payload.issues.push({
|
|
156
|
+
code: "custom",
|
|
157
|
+
message: `Only one of ${fieldNamesList} is allowed`,
|
|
158
|
+
input: payload.value,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return schema;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Creates a Zod schema for required time scoping (exactly one of the
|
|
166
|
+
* specified time variants must be present).
|
|
167
|
+
*
|
|
168
|
+
* @param keys - Which time scope variants to support
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* // Exactly one time scope required (for time-off)
|
|
173
|
+
* requiredTimeScope(["dateRange", "specificDates", "dayOfWeek", "recurring"])
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export function requiredTimeScope(keys) {
|
|
177
|
+
const shape = {};
|
|
178
|
+
for (const key of keys) {
|
|
179
|
+
for (const [fieldName, fieldSchema] of Object.entries(timeFieldSchemas[key])) {
|
|
180
|
+
shape[fieldName] = fieldSchema.optional();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const schema = z.object(shape).check((payload) => {
|
|
184
|
+
const values = payload.value;
|
|
185
|
+
const activeFields = keys.filter((key) => {
|
|
186
|
+
const fieldName = timeFieldNames[key];
|
|
187
|
+
const value = values[fieldName];
|
|
188
|
+
if (!value)
|
|
189
|
+
return false;
|
|
190
|
+
if (fieldName === "dateRange")
|
|
191
|
+
return true;
|
|
192
|
+
return Array.isArray(value) && value.length > 0;
|
|
193
|
+
});
|
|
194
|
+
if (activeFields.length === 0) {
|
|
195
|
+
const fieldNamesList = keys.map((k) => timeFieldNames[k]).join(", ");
|
|
196
|
+
payload.issues.push({
|
|
197
|
+
code: "custom",
|
|
198
|
+
message: `Must provide time scoping (${fieldNamesList})`,
|
|
199
|
+
input: payload.value,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (activeFields.length > 1) {
|
|
203
|
+
const fieldNamesList = keys.map((k) => timeFieldNames[k]).join("/");
|
|
204
|
+
payload.issues.push({
|
|
205
|
+
code: "custom",
|
|
206
|
+
message: `Only one of ${fieldNamesList} is allowed`,
|
|
207
|
+
input: payload.value,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return schema;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Extracts the entity scope from a parsed flat config.
|
|
215
|
+
*/
|
|
216
|
+
export function parseEntityScope(config) {
|
|
217
|
+
if (config.employeeIds && config.employeeIds.length > 0) {
|
|
218
|
+
return { type: "employees", employeeIds: config.employeeIds };
|
|
219
|
+
}
|
|
220
|
+
if (config.roleIds && config.roleIds.length > 0) {
|
|
221
|
+
return { type: "roles", roleIds: config.roleIds };
|
|
222
|
+
}
|
|
223
|
+
if (config.skillIds && config.skillIds.length > 0) {
|
|
224
|
+
return { type: "skills", skillIds: config.skillIds };
|
|
225
|
+
}
|
|
226
|
+
return { type: "global" };
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Extracts the time scope from a parsed flat config.
|
|
230
|
+
*/
|
|
231
|
+
export function parseTimeScope(config) {
|
|
232
|
+
if (config.dateRange) {
|
|
233
|
+
return { type: "dateRange", start: config.dateRange.start, end: config.dateRange.end };
|
|
234
|
+
}
|
|
235
|
+
if (config.specificDates && config.specificDates.length > 0) {
|
|
236
|
+
return { type: "specificDates", dates: config.specificDates };
|
|
237
|
+
}
|
|
238
|
+
if (config.dayOfWeek && config.dayOfWeek.length > 0) {
|
|
239
|
+
return { type: "dayOfWeek", days: config.dayOfWeek };
|
|
240
|
+
}
|
|
241
|
+
if (config.recurringPeriods && config.recurringPeriods.length > 0) {
|
|
242
|
+
return { type: "recurring", periods: config.recurringPeriods };
|
|
243
|
+
}
|
|
244
|
+
return { type: "none" };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Resolves which employees a rule applies to based on entity scope.
|
|
248
|
+
*/
|
|
249
|
+
export function resolveEmployeesFromScope(scope, employees) {
|
|
250
|
+
switch (scope.type) {
|
|
251
|
+
case "employees": {
|
|
252
|
+
const idSet = new Set(scope.employeeIds);
|
|
253
|
+
return employees.filter((e) => idSet.has(e.id));
|
|
254
|
+
}
|
|
255
|
+
case "roles":
|
|
256
|
+
return employees.filter((e) => e.roleIds.some((r) => scope.roleIds.includes(r)));
|
|
257
|
+
case "skills":
|
|
258
|
+
return employees.filter((e) => e.skillIds?.some((s) => scope.skillIds.includes(s)));
|
|
259
|
+
case "global":
|
|
260
|
+
default:
|
|
261
|
+
return employees;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Resolves which days a rule applies to based on time scope.
|
|
266
|
+
*/
|
|
267
|
+
export function resolveActiveDaysFromScope(scope, allDays) {
|
|
268
|
+
switch (scope.type) {
|
|
269
|
+
case "none":
|
|
270
|
+
return allDays;
|
|
271
|
+
case "dateRange":
|
|
272
|
+
return allDays.filter((day) => day >= scope.start && day <= scope.end);
|
|
273
|
+
case "specificDates":
|
|
274
|
+
return allDays.filter((day) => scope.dates.includes(day));
|
|
275
|
+
case "dayOfWeek": {
|
|
276
|
+
const targetDays = new Set(scope.days);
|
|
277
|
+
return allDays.filter((day) => {
|
|
278
|
+
const date = parseDayString(day);
|
|
279
|
+
const dayName = getDayOfWeekName(date.getUTCDay());
|
|
280
|
+
return targetDays.has(dayName);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
case "recurring":
|
|
284
|
+
return allDays.filter((day) => {
|
|
285
|
+
const date = parseDayString(day);
|
|
286
|
+
const month = date.getUTCMonth() + 1;
|
|
287
|
+
const dayOfMonth = date.getUTCDate();
|
|
288
|
+
return scope.periods.some((period) => isDateInRecurringPeriod(month, dayOfMonth, period));
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function getDayOfWeekName(dayIndex) {
|
|
293
|
+
const names = {
|
|
294
|
+
0: "sunday",
|
|
295
|
+
1: "monday",
|
|
296
|
+
2: "tuesday",
|
|
297
|
+
3: "wednesday",
|
|
298
|
+
4: "thursday",
|
|
299
|
+
5: "friday",
|
|
300
|
+
6: "saturday",
|
|
301
|
+
};
|
|
302
|
+
return names[dayIndex % 7] ?? "sunday";
|
|
303
|
+
}
|
|
304
|
+
function isDateInRecurringPeriod(month, dayOfMonth, period) {
|
|
305
|
+
const { startMonth, startDay, endMonth, endDay } = period;
|
|
306
|
+
if (startMonth <= endMonth) {
|
|
307
|
+
if (month < startMonth || month > endMonth)
|
|
308
|
+
return false;
|
|
309
|
+
if (month === startMonth && dayOfMonth < startDay)
|
|
310
|
+
return false;
|
|
311
|
+
if (month === endMonth && dayOfMonth > endDay)
|
|
312
|
+
return false;
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
if (month > endMonth && month < startMonth)
|
|
317
|
+
return false;
|
|
318
|
+
if (month === startMonth && dayOfMonth < startDay)
|
|
319
|
+
return false;
|
|
320
|
+
if (month === endMonth && dayOfMonth > endDay)
|
|
321
|
+
return false;
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=scope.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.types.js","sourceRoot":"","sources":["../../../src/cpsat/rules/scope.types.ts"],"names":[],"mappings":"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"}
|