scschedule 2.1.1 → 3.0.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/README.md +142 -41
- package/dist/cleanupExpiredOverridesFromSchedule.d.ts +4 -0
- package/dist/cleanupExpiredOverridesFromSchedule.js +4 -0
- package/dist/constants.d.ts +1 -3
- package/dist/constants.js +1 -3
- package/dist/getAvailableRangesFromSchedule.d.ts +10 -0
- package/dist/getAvailableRangesFromSchedule.js +19 -0
- package/dist/getNextAvailableFromSchedule.d.ts +9 -8
- package/dist/getNextAvailableFromSchedule.js +14 -8
- package/dist/getNextUnavailableFromSchedule.d.ts +19 -9
- package/dist/getNextUnavailableFromSchedule.js +124 -63
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/internal/getApplicableRuleForDate.d.ts +11 -11
- package/dist/internal/getApplicableRuleForDate.js +11 -7
- package/dist/internal/index.d.ts +1 -3
- package/dist/internal/index.js +1 -3
- package/dist/internal/validateNoEmptyWeekdays.js +2 -1
- package/dist/internal/validateNoOverlappingRules.js +5 -4
- package/dist/internal/validateNoOverlappingTimesInRule.js +2 -1
- package/dist/internal/validateNoSpilloverConflictsAtOverrideBoundaries.d.ts +4 -2
- package/dist/internal/validateNoSpilloverConflictsAtOverrideBoundaries.js +71 -54
- package/dist/internal/validateNonEmptyTimes.js +2 -1
- package/dist/internal/validateScDateFormats.js +2 -1
- package/dist/isScheduleAvailable.d.ts +9 -0
- package/dist/isScheduleAvailable.js +19 -2
- package/dist/types.d.ts +12 -18
- package/dist/validateSchedule.d.ts +4 -2
- package/dist/validateSchedule.js +4 -4
- package/package.json +2 -2
- package/dist/internal/isValidTimezone.d.ts +0 -4
- package/dist/internal/isValidTimezone.js +0 -12
- package/dist/internal/validateTimezone.d.ts +0 -5
- package/dist/internal/validateTimezone.js +0 -16
|
@@ -2,5 +2,14 @@ import type { STimestamp } from 'scdate';
|
|
|
2
2
|
import type { Schedule } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Checks if a schedule is available at the specified timestamp.
|
|
5
|
+
*
|
|
6
|
+
* When `weekly` is `true`, the schedule is always available (unless an
|
|
7
|
+
* override applies). Otherwise, checks whether the timestamp falls within any
|
|
8
|
+
* matching time range for the day, including cross-midnight spillover from the
|
|
9
|
+
* previous day.
|
|
10
|
+
*
|
|
11
|
+
* @param schedule The schedule to check availability against.
|
|
12
|
+
* @param timestamp The timestamp to check.
|
|
13
|
+
* @returns True if the schedule is available at the given timestamp.
|
|
5
14
|
*/
|
|
6
15
|
export declare const isScheduleAvailable: (schedule: Schedule, timestamp: STimestamp | string) => boolean;
|
|
@@ -3,6 +3,15 @@ import { getApplicableRuleForDate } from './internal/getApplicableRuleForDate.js
|
|
|
3
3
|
import { isTimeInTimeRange } from './internal/isTimeInTimeRange.js';
|
|
4
4
|
/**
|
|
5
5
|
* Checks if a schedule is available at the specified timestamp.
|
|
6
|
+
*
|
|
7
|
+
* When `weekly` is `true`, the schedule is always available (unless an
|
|
8
|
+
* override applies). Otherwise, checks whether the timestamp falls within any
|
|
9
|
+
* matching time range for the day, including cross-midnight spillover from the
|
|
10
|
+
* previous day.
|
|
11
|
+
*
|
|
12
|
+
* @param schedule The schedule to check availability against.
|
|
13
|
+
* @param timestamp The timestamp to check.
|
|
14
|
+
* @returns True if the schedule is available at the given timestamp.
|
|
6
15
|
*/
|
|
7
16
|
export const isScheduleAvailable = (schedule, timestamp) => {
|
|
8
17
|
const date = getDateFromTimestamp(timestamp);
|
|
@@ -10,6 +19,10 @@ export const isScheduleAvailable = (schedule, timestamp) => {
|
|
|
10
19
|
const weekday = getWeekdayFromDate(date);
|
|
11
20
|
// Get the applicable rules for this date
|
|
12
21
|
const { rules } = getApplicableRuleForDate(schedule, date.date);
|
|
22
|
+
// If weekly is true, always available (unless overridden)
|
|
23
|
+
if (rules === true) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
13
26
|
// Check if any rule's time ranges include this timestamp (same-day check)
|
|
14
27
|
const matchesSameDay = rules.some((rule) => {
|
|
15
28
|
// Check if this weekday is in the rule
|
|
@@ -25,8 +38,12 @@ export const isScheduleAvailable = (schedule, timestamp) => {
|
|
|
25
38
|
// Also check previous day's rules for cross-midnight spillover
|
|
26
39
|
const previousDate = addDaysToDate(date, -1);
|
|
27
40
|
const previousWeekday = getWeekdayFromDate(previousDate);
|
|
28
|
-
const
|
|
29
|
-
|
|
41
|
+
const previousResult = getApplicableRuleForDate(schedule, previousDate.date);
|
|
42
|
+
// If previous day was always available, no cross-midnight rules to check
|
|
43
|
+
if (previousResult.rules === true) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return previousResult.rules.some((rule) => {
|
|
30
47
|
// Check if previous day's weekday is in the rule
|
|
31
48
|
if (!doesWeekdaysIncludeWeekday(rule.weekdays, previousWeekday)) {
|
|
32
49
|
return false;
|
package/dist/types.d.ts
CHANGED
|
@@ -60,20 +60,19 @@ export interface OverrideScheduleRule {
|
|
|
60
60
|
rules: WeeklyScheduleRule[];
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
* Represents a complete availability schedule. A schedule consists of
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* Indefinite override (with only from date) 3. Weekly schedule
|
|
63
|
+
* Represents a complete availability schedule. A schedule consists of base
|
|
64
|
+
* weekly recurring patterns and optional date-specific overrides. Priority
|
|
65
|
+
* order for determining availability: 1. Specific override (with both from and
|
|
66
|
+
* to dates) 2. Indefinite override (with only from date) 3. Weekly schedule
|
|
68
67
|
*/
|
|
69
68
|
export interface Schedule {
|
|
70
69
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* Base recurring weekly schedule patterns.
|
|
71
|
+
* - `true`: available 24/7 (overrides can close windows)
|
|
72
|
+
* - `WeeklyScheduleRule[]`: available during defined time ranges
|
|
73
|
+
* - `[]`: never available (overrides can open windows)
|
|
73
74
|
*/
|
|
74
|
-
|
|
75
|
-
/** Base recurring weekly schedule patterns */
|
|
76
|
-
weekly: WeeklyScheduleRule[];
|
|
75
|
+
weekly: WeeklyScheduleRule[] | true;
|
|
77
76
|
/**
|
|
78
77
|
* Date-specific exceptions to the weekly schedule. Overrides take precedence
|
|
79
78
|
* over weekly rules.
|
|
@@ -95,11 +94,6 @@ export interface AvailabilityRange {
|
|
|
95
94
|
* property to narrow the type and access error-specific fields.
|
|
96
95
|
*/
|
|
97
96
|
export type ValidationError = {
|
|
98
|
-
/** The timezone string is not a valid IANA timezone identifier */
|
|
99
|
-
issue: ValidationIssue.InvalidTimezone;
|
|
100
|
-
/** The invalid timezone string that was provided */
|
|
101
|
-
timezone: string;
|
|
102
|
-
} | {
|
|
103
97
|
/** Two or more specific overrides have identical date ranges */
|
|
104
98
|
issue: ValidationIssue.DuplicateOverrides;
|
|
105
99
|
/** Indexes of the two duplicate overrides */
|
|
@@ -225,7 +219,7 @@ export type ValidationError = {
|
|
|
225
219
|
} | {
|
|
226
220
|
/**
|
|
227
221
|
* Cross-midnight spillover from override's last day conflicts with next
|
|
228
|
-
* day's time ranges
|
|
222
|
+
* day's time ranges or weekly: true availability
|
|
229
223
|
*/
|
|
230
224
|
issue: ValidationIssue.SpilloverConflictOverrideIntoNext;
|
|
231
225
|
/** Index of the override whose last day causes spillover */
|
|
@@ -235,8 +229,8 @@ export type ValidationError = {
|
|
|
235
229
|
/** The override rule index causing the spillover */
|
|
236
230
|
overrideRuleIndex: number;
|
|
237
231
|
/**
|
|
238
|
-
* The next day's rule that conflicts
|
|
239
|
-
*
|
|
232
|
+
* The next day's rule that conflicts. When all three fields are
|
|
233
|
+
* undefined, the next day is weekly: true (fully available).
|
|
240
234
|
*/
|
|
241
235
|
nextDayWeeklyRuleIndex?: number;
|
|
242
236
|
nextDayOverrideIndex?: number;
|
|
@@ -3,13 +3,15 @@ import type { Schedule, ValidationResult } from './types.js';
|
|
|
3
3
|
* Validates a schedule configuration and returns all validation errors found.
|
|
4
4
|
*
|
|
5
5
|
* Validation is performed in two phases:
|
|
6
|
-
* 1. Structural validation (
|
|
7
|
-
*
|
|
6
|
+
* 1. Structural validation (formats, date order, empty weekdays, non-empty
|
|
7
|
+
* times, weekday-date mismatch) - runs on original schedule
|
|
8
8
|
* 2. Semantic validation (overlaps, conflicts) - runs on normalized schedule
|
|
9
9
|
* after filtering weekdays to actual dates
|
|
10
10
|
*
|
|
11
11
|
* If structural errors are found, validation stops early and returns only
|
|
12
12
|
* those errors. This provides better user experience and avoids crashes from
|
|
13
13
|
* invalid data during normalization.
|
|
14
|
+
*
|
|
15
|
+
* @param schedule The schedule to validate.
|
|
14
16
|
*/
|
|
15
17
|
export declare const validateSchedule: (schedule: Schedule) => ValidationResult;
|
package/dist/validateSchedule.js
CHANGED
|
@@ -8,26 +8,26 @@ import { validateNonEmptyTimes } from './internal/validateNonEmptyTimes.js';
|
|
|
8
8
|
import { validateOverrideDateOrder } from './internal/validateOverrideDateOrder.js';
|
|
9
9
|
import { validateOverrideWeekdaysMatchDates } from './internal/validateOverrideWeekdaysMatchDates.js';
|
|
10
10
|
import { validateScDateFormats } from './internal/validateScDateFormats.js';
|
|
11
|
-
import { validateTimezone } from './internal/validateTimezone.js';
|
|
12
11
|
/**
|
|
13
12
|
* Validates a schedule configuration and returns all validation errors found.
|
|
14
13
|
*
|
|
15
14
|
* Validation is performed in two phases:
|
|
16
|
-
* 1. Structural validation (
|
|
17
|
-
*
|
|
15
|
+
* 1. Structural validation (formats, date order, empty weekdays, non-empty
|
|
16
|
+
* times, weekday-date mismatch) - runs on original schedule
|
|
18
17
|
* 2. Semantic validation (overlaps, conflicts) - runs on normalized schedule
|
|
19
18
|
* after filtering weekdays to actual dates
|
|
20
19
|
*
|
|
21
20
|
* If structural errors are found, validation stops early and returns only
|
|
22
21
|
* those errors. This provides better user experience and avoids crashes from
|
|
23
22
|
* invalid data during normalization.
|
|
23
|
+
*
|
|
24
|
+
* @param schedule The schedule to validate.
|
|
24
25
|
*/
|
|
25
26
|
export const validateSchedule = (schedule) => {
|
|
26
27
|
// Phase 1: Structural validation
|
|
27
28
|
// Note: Order matters - date formats and order must be validated before
|
|
28
29
|
// weekday matching (which calls filterWeekdaysForDates)
|
|
29
30
|
const structuralErrors = [
|
|
30
|
-
...validateTimezone(schedule),
|
|
31
31
|
...validateScDateFormats(schedule),
|
|
32
32
|
...validateOverrideDateOrder(schedule),
|
|
33
33
|
...validateNoEmptyWeekdays(schedule),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scschedule",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"test": "vitest run"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"scdate": "
|
|
23
|
+
"scdate": "3.0.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@eslint/js": "^9.39.2",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checks if a string is a valid IANA timezone identifier.
|
|
3
|
-
*/
|
|
4
|
-
export const isValidTimezone = (timezone) => {
|
|
5
|
-
try {
|
|
6
|
-
const validTimezones = Intl.supportedValuesOf('timeZone');
|
|
7
|
-
return validTimezones.includes(timezone);
|
|
8
|
-
}
|
|
9
|
-
catch {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ValidationIssue } from '../constants.js';
|
|
2
|
-
import { isValidTimezone } from './isValidTimezone.js';
|
|
3
|
-
/**
|
|
4
|
-
* Validates that a schedule's timezone is a valid IANA timezone identifier.
|
|
5
|
-
*/
|
|
6
|
-
export const validateTimezone = (schedule) => {
|
|
7
|
-
if (!isValidTimezone(schedule.timezone)) {
|
|
8
|
-
return [
|
|
9
|
-
{
|
|
10
|
-
issue: ValidationIssue.InvalidTimezone,
|
|
11
|
-
timezone: schedule.timezone,
|
|
12
|
-
},
|
|
13
|
-
];
|
|
14
|
-
}
|
|
15
|
-
return [];
|
|
16
|
-
};
|