@kensio/quando 0.1.0-beta.0 → 0.2.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 (69) hide show
  1. package/README.md +125 -4
  2. package/dist/build.d.ts +54 -0
  3. package/dist/build.d.ts.map +1 -0
  4. package/dist/build.js +77 -0
  5. package/dist/build.js.map +1 -0
  6. package/dist/cascade.d.ts +86 -0
  7. package/dist/cascade.d.ts.map +1 -0
  8. package/dist/cascade.js +40 -0
  9. package/dist/cascade.js.map +1 -0
  10. package/dist/context.d.ts +44 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +9 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/day-rules.d.ts +23 -0
  15. package/dist/day-rules.d.ts.map +1 -0
  16. package/dist/day-rules.js +102 -0
  17. package/dist/day-rules.js.map +1 -0
  18. package/dist/index.d.ts +26 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +17 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/interpret.d.ts +31 -0
  23. package/dist/interpret.d.ts.map +1 -0
  24. package/dist/interpret.js +99 -0
  25. package/dist/interpret.js.map +1 -0
  26. package/dist/interval-stream.d.ts +11 -4
  27. package/dist/interval-stream.d.ts.map +1 -1
  28. package/dist/interval-stream.js.map +1 -1
  29. package/dist/parse-fields.d.ts +30 -0
  30. package/dist/parse-fields.d.ts.map +1 -0
  31. package/dist/parse-fields.js +93 -0
  32. package/dist/parse-fields.js.map +1 -0
  33. package/dist/parse.d.ts +22 -0
  34. package/dist/parse.d.ts.map +1 -0
  35. package/dist/parse.js +115 -0
  36. package/dist/parse.js.map +1 -0
  37. package/dist/plain-forms.d.ts +22 -0
  38. package/dist/plain-forms.d.ts.map +1 -0
  39. package/dist/plain-forms.js +54 -0
  40. package/dist/plain-forms.js.map +1 -0
  41. package/dist/query.d.ts +67 -0
  42. package/dist/query.d.ts.map +1 -0
  43. package/dist/query.js +121 -0
  44. package/dist/query.js.map +1 -0
  45. package/dist/resolve.d.ts +25 -0
  46. package/dist/resolve.d.ts.map +1 -0
  47. package/dist/resolve.js +80 -0
  48. package/dist/resolve.js.map +1 -0
  49. package/dist/rota.d.ts +49 -0
  50. package/dist/rota.d.ts.map +1 -0
  51. package/dist/rota.js +47 -0
  52. package/dist/rota.js.map +1 -0
  53. package/dist/rule.d.ts +73 -0
  54. package/dist/rule.d.ts.map +1 -0
  55. package/dist/rule.js +20 -0
  56. package/dist/rule.js.map +1 -0
  57. package/dist/schedule.d.ts +69 -0
  58. package/dist/schedule.d.ts.map +1 -0
  59. package/dist/schedule.js +85 -0
  60. package/dist/schedule.js.map +1 -0
  61. package/dist/time-rules.d.ts +18 -0
  62. package/dist/time-rules.d.ts.map +1 -0
  63. package/dist/time-rules.js +55 -0
  64. package/dist/time-rules.js.map +1 -0
  65. package/dist/valued-stream.d.ts +42 -0
  66. package/dist/valued-stream.d.ts.map +1 -0
  67. package/dist/valued-stream.js +77 -0
  68. package/dist/valued-stream.js.map +1 -0
  69. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,YAAY,EACV,OAAO,EACP,OAAO,EACP,UAAU,EACV,SAAS,EACT,cAAc,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,aAAa,EACb,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EACL,GAAG,EACH,MAAM,EACN,GAAG,EACH,KAAK,EACL,UAAU,EACV,MAAM,EACN,KAAK,EACL,GAAG,EACH,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,YAAY,EACV,OAAO,EACP,aAAa,EACb,KAAK,EACL,cAAc,EACd,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE5E,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -2,8 +2,14 @@
2
2
  * Quando: declarative temporal rules for schedules, deadlines, constraints and
3
3
  * exceptions.
4
4
  *
5
- * What exists so far is the interval core the algebra everything else is
6
- * built from. Rules, cascades and queries are still to come.
5
+ * What exists so far is the interval core, the rule language on top of it, and
6
+ * the two ends of "rules are data": a builder that writes one, and a parser
7
+ * that reads one back from whatever a database or a form actually held.
8
+ * Queries sit on top: is it open now, how much working time is in this window,
9
+ * when does it next open, and where do you get to after three hours that only
10
+ * count while it is open. Cascades sit beside them: ordered layers that carry
11
+ * values, resolved by precedence, for the questions a boolean schedule cannot
12
+ * answer.
7
13
  *
8
14
  * Requires a runtime with `Temporal`: Node 26 or later, or a browser that
9
15
  * implements it.
@@ -14,4 +20,13 @@
14
20
  export { compareEnds, compareStarts, contains, duration, isEmpty, startsAtOrBeforeEnd, startsBeforeEnd, } from "./interval.js";
15
21
  export { clip, complement, intersect, union } from "./interval-stream.js";
16
22
  export { take } from "./stream.js";
23
+ export { WEEKDAYS } from "./rule.js";
24
+ export { intervals } from "./interpret.js";
25
+ export { all, always, any, dates, daysOfWeek, inZone, never, not, timeOfDay, weekdays, weekends, } from "./build.js";
26
+ export { parseRule } from "./parse.js";
27
+ export { cascade, isCascade, layer, replace, whenever } from "./cascade.js";
28
+ export { resolve } from "./resolve.js";
29
+ export { schedule } from "./schedule.js";
30
+ export { rota } from "./rota.js";
31
+ export { activeAt, advanceBy, elapsed, next } from "./query.js";
17
32
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,eAAe,GAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EACL,WAAW,EACX,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,mBAAmB,EACnB,eAAe,GAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAgBnC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,OAAO,EACL,GAAG,EACH,MAAM,EACN,GAAG,EACH,KAAK,EACL,UAAU,EACV,MAAM,EACN,KAAK,EACL,GAAG,EACH,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI5E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAKvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Reading a rule as the times it covers.
3
+ *
4
+ * One function over the whole rule language rather than a method on each rule
5
+ * type, which is what lets the next operation over rules — describing them,
6
+ * validating them, drawing them — be another function here rather than another
7
+ * method everywhere.
8
+ *
9
+ * Everything is clipped to the context's window. That is not tidiness: a
10
+ * composition whose answer is empty has nothing to discover that from, so the
11
+ * only thing that makes it terminate is its sources running out. Clipping at
12
+ * the leaves is what makes them run out.
13
+ */
14
+ import { type Context } from "./context.js";
15
+ import { type IntervalStream } from "./interval-stream.js";
16
+ import type { Rule } from "./rule.js";
17
+ /**
18
+ * The intervals a rule covers within a context, in order and coalesced.
19
+ *
20
+ * The stream is lazy, and endless when the context has no end and the rule
21
+ * recurs — which is the point. Take what you need from it.
22
+ *
23
+ * Every interval comes back in the context's zone. The algebra compares
24
+ * instants, so a sweep is free to take one interval's start and another's end,
25
+ * and those two may have been written in different zones — a London rule read
26
+ * from a Tokyo context would otherwise hand back an interval whose two halves
27
+ * disagree about what time it is. The instants are unaffected either way; this
28
+ * only settles which zone reads them back.
29
+ */
30
+ export declare function intervals(rule: Rule, context: Context): IntervalStream;
31
+ //# sourceMappingURL=interpret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpret.d.ts","sourceRoot":"","sources":["../src/interpret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,cAAc,CAAC;AACtD,OAAO,EAIL,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUtC;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,CAEtE"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Reading a rule as the times it covers.
3
+ *
4
+ * One function over the whole rule language rather than a method on each rule
5
+ * type, which is what lets the next operation over rules — describing them,
6
+ * validating them, drawing them — be another function here rather than another
7
+ * method everywhere.
8
+ *
9
+ * Everything is clipped to the context's window. That is not tidiness: a
10
+ * composition whose answer is empty has nothing to discover that from, so the
11
+ * only thing that makes it terminate is its sources running out. Clipping at
12
+ * the leaves is what makes them run out.
13
+ */
14
+ import { windowOf } from "./context.js";
15
+ import { clip, complement, intersect, union, } from "./interval-stream.js";
16
+ import { dateIntervals, weekdayIntervals } from "./day-rules.js";
17
+ import { timeOfDayIntervals } from "./time-rules.js";
18
+ /** All of time, before the window narrows it. */
19
+ const UNBOUNDED = [{ start: undefined, end: undefined }];
20
+ /** No time at all. */
21
+ const EMPTY = [];
22
+ /**
23
+ * The intervals a rule covers within a context, in order and coalesced.
24
+ *
25
+ * The stream is lazy, and endless when the context has no end and the rule
26
+ * recurs — which is the point. Take what you need from it.
27
+ *
28
+ * Every interval comes back in the context's zone. The algebra compares
29
+ * instants, so a sweep is free to take one interval's start and another's end,
30
+ * and those two may have been written in different zones — a London rule read
31
+ * from a Tokyo context would otherwise hand back an interval whose two halves
32
+ * disagree about what time it is. The instants are unaffected either way; this
33
+ * only settles which zone reads them back.
34
+ */
35
+ export function intervals(rule, context) {
36
+ return readIn(evaluate(rule, context), context.from.timeZoneId);
37
+ }
38
+ function* readIn(stream, zone) {
39
+ for (const interval of stream) {
40
+ yield {
41
+ start: interval.start?.withTimeZone(zone),
42
+ end: interval.end?.withTimeZone(zone),
43
+ };
44
+ }
45
+ }
46
+ function evaluate(rule, context) {
47
+ const window = windowOf(context);
48
+ switch (rule.type) {
49
+ case "always": {
50
+ return clip(UNBOUNDED, window);
51
+ }
52
+ case "never": {
53
+ return EMPTY;
54
+ }
55
+ case "daysOfWeek": {
56
+ return clip(weekdayIntervals(context, rule.days, rule.zone), window);
57
+ }
58
+ case "dates": {
59
+ return clip(dateIntervals(context, rule.dates, rule.zone), window);
60
+ }
61
+ case "timeOfDay": {
62
+ return clip(timeOfDayIntervals(context, rule.from, rule.to, rule.zone), window);
63
+ }
64
+ case "all": {
65
+ return everyOf(rule.rules, context);
66
+ }
67
+ case "any": {
68
+ return anyOf(rule.rules, context);
69
+ }
70
+ case "not": {
71
+ // Re-clipped, because a complement is unbounded at both ends by nature
72
+ // and would otherwise reach outside the window it was asked about.
73
+ return clip(complement(evaluate(rule.rule, context)), window);
74
+ }
75
+ default: {
76
+ // Compiles only while every rule type above is handled. Adding one to the
77
+ // union makes this the error that says so.
78
+ const unreachable = rule;
79
+ return unreachable;
80
+ }
81
+ }
82
+ }
83
+ /** Intersection, starting from all of time so that no rules means no limits. */
84
+ function everyOf(rules, context) {
85
+ let covered = clip(UNBOUNDED, windowOf(context));
86
+ for (const rule of rules) {
87
+ covered = intersect(covered, evaluate(rule, context));
88
+ }
89
+ return covered;
90
+ }
91
+ /** Union, starting from nothing so that no rules means no times. */
92
+ function anyOf(rules, context) {
93
+ let covered = EMPTY;
94
+ for (const rule of rules) {
95
+ covered = union(covered, evaluate(rule, context));
96
+ }
97
+ return covered;
98
+ }
99
+ //# sourceMappingURL=interpret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpret.js","sourceRoot":"","sources":["../src/interpret.ts"],"names":[],"mappings":"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"}
@@ -13,10 +13,17 @@ import { type Interval } from "./interval.js";
13
13
  /**
14
14
  * A lazy sequence of intervals.
15
15
  *
16
- * **Contract, which every producer must uphold:** intervals arrive sorted by
17
- * start, do not overlap, and are already coalesced — no two touching intervals
18
- * where one would do. The sweeps below are single-pass and rely on it; a
19
- * producer that breaks it produces wrong answers rather than errors.
16
+ * **Contract, which every producer must uphold:** intervals arrive in
17
+ * *ascending* order of start, do not overlap, and are already coalesced — no
18
+ * two touching intervals where one would do. The sweeps below are single-pass
19
+ * and rely on all three; a producer that breaks one produces wrong answers
20
+ * rather than errors.
21
+ *
22
+ * Ascending is stated rather than implied because the opposite is a real thing
23
+ * to want later: "when did this last open" wants to walk backwards. A
24
+ * descending stream would satisfy every other clause here while being read
25
+ * wrongly by all of it, so if one is ever added it needs to be a distinct type
26
+ * rather than a stream that happens to run the other way.
20
27
  */
21
28
  export type IntervalStream = Iterable<Interval>;
22
29
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"interval-stream.d.ts","sourceRoot":"","sources":["../src/interval-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAIL,KAAK,QAAQ,EAMd,MAAM,eAAe,CAAC;AAGvB;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAiB,SAAS,CACxB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,cAAc,GACpB,cAAc,CAwBhB;AAED;;;;;GAKG;AACH,wBAAiB,KAAK,CACpB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,cAAc,GACpB,cAAc,CAgChB;AA8BD;;;;;;GAMG;AACH,wBAAiB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAyClE;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,GAAG,cAAc,CAM7E"}
1
+ {"version":3,"file":"interval-stream.d.ts","sourceRoot":"","sources":["../src/interval-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAIL,KAAK,QAAQ,EAMd,MAAM,eAAe,CAAC;AAGvB;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAEhD;;;;;;;GAOG;AACH,wBAAiB,SAAS,CACxB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,cAAc,GACpB,cAAc,CAwBhB;AAED;;;;;GAKG;AACH,wBAAiB,KAAK,CACpB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,cAAc,GACpB,cAAc,CAgChB;AA8BD;;;;;;GAMG;AACH,wBAAiB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAyClE;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,GAAG,cAAc,CAM7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"interval-stream.js","sourceRoot":"","sources":["../src/interval-stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interval-stream.js","sourceRoot":"","sources":["../src/interval-stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Checking one field of an incoming rule document.
3
+ *
4
+ * Each of these either returns the value at the type it claims to be, or
5
+ * throws saying what was found instead and where. The `path` threaded through
6
+ * them is what turns "not a date" into
7
+ * `rule.rules[1].rules[0].dates[0]: "not a date" is not a date`.
8
+ */
9
+ import { type Weekday } from "./rule.js";
10
+ export declare function fail(path: string, problem: string): never;
11
+ /** What a value looks like, for an error message. */
12
+ export declare function shapeOf(value: unknown): string;
13
+ export declare function asRecord(value: unknown, path: string): Record<string, unknown>;
14
+ export declare function asString(value: unknown, path: string): string;
15
+ export declare function asStrings(value: unknown, path: string): string[];
16
+ export declare function asDays(value: unknown, path: string): Weekday[];
17
+ /** Checked by construction, so a malformed time is caught where it is written. */
18
+ export declare function asTime(value: unknown, path: string): string;
19
+ export declare function asDates(value: unknown, path: string): string[];
20
+ /**
21
+ * A zone is checked here rather than left to fail at query time, because a
22
+ * mistyped one in a stored rule should be a problem when the rule is read, not
23
+ * hours later when something asks a question of it.
24
+ */
25
+ export declare function asZone(value: unknown, path: string): string;
26
+ /** Present or absent, never present-and-undefined. */
27
+ export declare function zonePart(node: Record<string, unknown>, path: string): {
28
+ zone?: string;
29
+ };
30
+ //# sourceMappingURL=parse-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-fields.d.ts","sourceRoot":"","sources":["../src/parse-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAInD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,CAEzD;AAED,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQ9C;AAED,wBAAgB,QAAQ,CACtB,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAShE;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAS9D;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAY9D;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAGnB"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Checking one field of an incoming rule document.
3
+ *
4
+ * Each of these either returns the value at the type it claims to be, or
5
+ * throws saying what was found instead and where. The `path` threaded through
6
+ * them is what turns "not a date" into
7
+ * `rule.rules[1].rules[0].dates[0]: "not a date" is not a date`.
8
+ */
9
+ import { WEEKDAYS } from "./rule.js";
10
+ const WEEKDAY_NAMES = new Set(WEEKDAYS);
11
+ export function fail(path, problem) {
12
+ throw new TypeError(`${path}: ${problem}`);
13
+ }
14
+ /** What a value looks like, for an error message. */
15
+ export function shapeOf(value) {
16
+ if (value === null) {
17
+ return "null";
18
+ }
19
+ if (Array.isArray(value)) {
20
+ return "an array";
21
+ }
22
+ return typeof value;
23
+ }
24
+ export function asRecord(value, path) {
25
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
26
+ return fail(path, `expected a rule object, found ${shapeOf(value)}`);
27
+ }
28
+ return value;
29
+ }
30
+ export function asString(value, path) {
31
+ return typeof value === "string"
32
+ ? value
33
+ : fail(path, `expected a string, found ${shapeOf(value)}`);
34
+ }
35
+ export function asStrings(value, path) {
36
+ if (!Array.isArray(value)) {
37
+ return fail(path, `expected an array, found ${shapeOf(value)}`);
38
+ }
39
+ return value.map((item, index) => typeof item === "string"
40
+ ? item
41
+ : fail(`${path}[${index}]`, `expected a string, found ${shapeOf(item)}`));
42
+ }
43
+ export function asDays(value, path) {
44
+ return asStrings(value, path).map((day, index) => WEEKDAY_NAMES.has(day)
45
+ ? day
46
+ : fail(`${path}[${index}]`, `"${day}" is not a day of the week. Expected one of ${WEEKDAYS.join(", ")}`));
47
+ }
48
+ /** Checked by construction, so a malformed time is caught where it is written. */
49
+ export function asTime(value, path) {
50
+ const time = asString(value, path);
51
+ try {
52
+ Temporal.PlainTime.from(time);
53
+ }
54
+ catch {
55
+ return fail(path, `"${time}" is not a time of day. Expected something like "09:00"`);
56
+ }
57
+ return time;
58
+ }
59
+ export function asDates(value, path) {
60
+ return asStrings(value, path).map((date, index) => {
61
+ try {
62
+ Temporal.PlainDate.from(date);
63
+ }
64
+ catch {
65
+ return fail(`${path}[${index}]`, `"${date}" is not a date. Expected something like "2026-03-14"`);
66
+ }
67
+ return date;
68
+ });
69
+ }
70
+ /**
71
+ * A zone is checked here rather than left to fail at query time, because a
72
+ * mistyped one in a stored rule should be a problem when the rule is read, not
73
+ * hours later when something asks a question of it.
74
+ */
75
+ export function asZone(value, path) {
76
+ const zone = asString(value, path);
77
+ try {
78
+ Temporal.PlainDate.from("2000-01-01").toZonedDateTime({
79
+ timeZone: zone,
80
+ plainTime: "00:00",
81
+ });
82
+ }
83
+ catch {
84
+ return fail(path, `"${zone}" is not a known time zone`);
85
+ }
86
+ return zone;
87
+ }
88
+ /** Present or absent, never present-and-undefined. */
89
+ export function zonePart(node, path) {
90
+ const zone = node["zone"];
91
+ return zone === undefined ? {} : { zone: asZone(zone, `${path}.zone`) };
92
+ }
93
+ //# sourceMappingURL=parse-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-fields.js","sourceRoot":"","sources":["../src/parse-fields.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Turning arbitrary JSON back into a rule.
3
+ *
4
+ * This is the boundary. Rules are meant to be stored, sent and edited, so what
5
+ * comes back is whatever a database row, an API body or a form actually holds
6
+ * — and the useful thing to do with a bad one is say precisely what is wrong
7
+ * and where, rather than fail somewhere further in with the reason lost.
8
+ *
9
+ * Shape and vocabulary are checked here: is it an object, is the type one that
10
+ * exists, are those really days of the week, does that parse as a time. What a
11
+ * rule *means* is not — `interpret.ts` owns that, and duplicating it here would
12
+ * only give the two somewhere to disagree.
13
+ */
14
+ import type { Rule } from "./rule.js";
15
+ /**
16
+ * A rule from unknown JSON, or a `TypeError` saying what is wrong and where.
17
+ *
18
+ * The `path` is what appears in front of every message, so a rule nested six
19
+ * deep reports as `rule.rules[2].rules[0].days[3]` rather than as a puzzle.
20
+ */
21
+ export declare function parseRule(value: unknown, path?: string): Rule;
22
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAwDtC;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,IAAI,CA+D7D"}
package/dist/parse.js ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Turning arbitrary JSON back into a rule.
3
+ *
4
+ * This is the boundary. Rules are meant to be stored, sent and edited, so what
5
+ * comes back is whatever a database row, an API body or a form actually holds
6
+ * — and the useful thing to do with a bad one is say precisely what is wrong
7
+ * and where, rather than fail somewhere further in with the reason lost.
8
+ *
9
+ * Shape and vocabulary are checked here: is it an object, is the type one that
10
+ * exists, are those really days of the week, does that parse as a time. What a
11
+ * rule *means* is not — `interpret.ts` owns that, and duplicating it here would
12
+ * only give the two somewhere to disagree.
13
+ */
14
+ import { asDates, asDays, asRecord, asTime, fail, shapeOf, zonePart, } from "./parse-fields.js";
15
+ /**
16
+ * Every rule type, and the fields it is allowed to carry. One table rather than
17
+ * two, so the list of known types and the list of known fields cannot drift.
18
+ */
19
+ const FIELDS = new Map([
20
+ ["always", []],
21
+ ["never", []],
22
+ ["daysOfWeek", ["days", "zone"]],
23
+ ["timeOfDay", ["from", "to", "zone"]],
24
+ ["dates", ["dates", "zone"]],
25
+ ["all", ["rules"]],
26
+ ["any", ["rules"]],
27
+ ["not", ["rule"]],
28
+ ]);
29
+ /**
30
+ * Refuses a field the rule type does not have.
31
+ *
32
+ * Quietly ignoring one is the worse option by some distance. A document
33
+ * carrying `"zonee"` would parse as a perfectly valid rule with no zone, which
34
+ * is a *different schedule* — read in whatever zone the query happened to use —
35
+ * and nothing would have said so. The same goes for a `zone` on a rule type
36
+ * that has no business with one.
37
+ *
38
+ * The cost is that a document written by a later version of Quando, carrying a
39
+ * field this one has not heard of, is rejected rather than tolerated. That is
40
+ * the right way round: a field exists to change what a rule means, so ignoring
41
+ * an unknown one is agreeing to get the answer wrong quietly.
42
+ */
43
+ function checkFields(node, type, allowed, path) {
44
+ for (const field of Object.keys(node)) {
45
+ if (field !== "type" && !allowed.includes(field)) {
46
+ fail(`${path}.${field}`, allowed.length === 0
47
+ ? `is not a field of a ${type} rule, which takes none`
48
+ : `is not a field of a ${type} rule. Expected ${allowed.join(", ")}`);
49
+ }
50
+ }
51
+ }
52
+ function asRules(value, path) {
53
+ if (!Array.isArray(value)) {
54
+ return fail(path, `expected an array of rules, found ${shapeOf(value)}`);
55
+ }
56
+ return value.map((rule, index) => parseRule(rule, `${path}[${index}]`));
57
+ }
58
+ /**
59
+ * A rule from unknown JSON, or a `TypeError` saying what is wrong and where.
60
+ *
61
+ * The `path` is what appears in front of every message, so a rule nested six
62
+ * deep reports as `rule.rules[2].rules[0].days[3]` rather than as a puzzle.
63
+ */
64
+ export function parseRule(value, path = "rule") {
65
+ const node = asRecord(value, path);
66
+ const type = node["type"];
67
+ if (typeof type !== "string") {
68
+ return fail(`${path}.type`, `expected a string, found ${shapeOf(type)}`);
69
+ }
70
+ const allowed = FIELDS.get(type);
71
+ if (allowed === undefined) {
72
+ return fail(`${path}.type`, `"${type}" is not a rule type. Expected one of ${[...FIELDS.keys()].join(", ")}`);
73
+ }
74
+ checkFields(node, type, allowed, path);
75
+ switch (type) {
76
+ case "always": {
77
+ return { type: "always" };
78
+ }
79
+ case "never": {
80
+ return { type: "never" };
81
+ }
82
+ case "daysOfWeek": {
83
+ return {
84
+ type: "daysOfWeek",
85
+ days: asDays(node["days"], `${path}.days`),
86
+ ...zonePart(node, path),
87
+ };
88
+ }
89
+ case "dates": {
90
+ return {
91
+ type: "dates",
92
+ dates: asDates(node["dates"], `${path}.dates`),
93
+ ...zonePart(node, path),
94
+ };
95
+ }
96
+ case "timeOfDay": {
97
+ return {
98
+ type: "timeOfDay",
99
+ from: asTime(node["from"], `${path}.from`),
100
+ to: asTime(node["to"], `${path}.to`),
101
+ ...zonePart(node, path),
102
+ };
103
+ }
104
+ case "all": {
105
+ return { type: "all", rules: asRules(node["rules"], `${path}.rules`) };
106
+ }
107
+ case "any": {
108
+ return { type: "any", rules: asRules(node["rules"], `${path}.rules`) };
109
+ }
110
+ default: {
111
+ return { type: "not", rule: parseRule(node["rule"], `${path}.rule`) };
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,OAAO,EACP,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAA4B;IAChD,CAAC,QAAQ,EAAE,EAAE,CAAC;IACd,CAAC,OAAO,EAAE,EAAE,CAAC;IACb,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC;IAClB,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC;CAClB,CAAC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,SAAS,WAAW,CAClB,IAA6B,EAC7B,IAAY,EACZ,OAA0B,EAC1B,IAAY;IAEZ,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,CACF,GAAG,IAAI,IAAI,KAAK,EAAE,EAClB,OAAO,CAAC,MAAM,KAAK,CAAC;gBAClB,CAAC,CAAC,uBAAuB,IAAI,yBAAyB;gBACtD,CAAC,CAAC,uBAAuB,IAAI,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAAc,EAAE,IAAY;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,IAAI,EAAE,qCAAqC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,IAAI,GAAG,MAAM;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAE1B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,GAAG,IAAI,OAAO,EAAE,4BAA4B,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CACT,GAAG,IAAI,OAAO,EACd,IAAI,IAAI,yCAAyC,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjF,CAAC;IACJ,CAAC;IACD,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAEvC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,EAAE,CAAC;YACd,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,CAAC;QAED,KAAK,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,KAAK,YAAY,EAAE,CAAC;YAClB,OAAO;gBACL,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,OAAO,CAAC;gBAC1C,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;aACxB,CAAC;QACJ,CAAC;QAED,KAAK,OAAO,EAAE,CAAC;YACb,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC;gBAC9C,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;aACxB,CAAC;QACJ,CAAC;QAED,KAAK,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,OAAO,CAAC;gBAC1C,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC;gBACpC,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;aACxB,CAAC;QACJ,CAAC;QAED,KAAK,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC;QACzE,CAAC;QAED,KAAK,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,EAAE,CAAC;QACzE,CAAC;QAED,SAAS,CAAC;YACR,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The plain forms the domain layer accepts in place of rules.
3
+ *
4
+ * `"09:00-17:00"` instead of `timeOfDay("09:00", "17:00")`, and `"2026-03-11"`
5
+ * instead of `dates("2026-03-11")`. Both are what someone writing a schedule
6
+ * by hand would type, and neither is ambiguous: a rule is an object and these
7
+ * are strings, so nothing has to guess which was meant.
8
+ *
9
+ * These check what they are given, which the rule layer deliberately does not
10
+ * — `timeOfDay` accepts any string and complains when the rule is evaluated,
11
+ * because parsing shape and deciding meaning are kept apart there. This layer
12
+ * exists to be written by hand, and a hand-written mistake is worth catching
13
+ * where it was written rather than at the first query.
14
+ */
15
+ import type { Rule } from "./rule.js";
16
+ /** A rule, a `"09:00-17:00"` window, or a whole day given as a date. */
17
+ export type PlainRule = Rule | string;
18
+ /** A wall-clock window from `"09:00-17:00"`, or a rule left as it is. */
19
+ export declare function asHours(hours: PlainRule): Rule;
20
+ /** Whole days from `"2026-03-11"`, or a rule left as it is. */
21
+ export declare function asDays(scope: PlainRule): Rule;
22
+ //# sourceMappingURL=plain-forms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plain-forms.d.ts","sourceRoot":"","sources":["../src/plain-forms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC;AAStC,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAoB9C;AAED,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAe7C"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The plain forms the domain layer accepts in place of rules.
3
+ *
4
+ * `"09:00-17:00"` instead of `timeOfDay("09:00", "17:00")`, and `"2026-03-11"`
5
+ * instead of `dates("2026-03-11")`. Both are what someone writing a schedule
6
+ * by hand would type, and neither is ambiguous: a rule is an object and these
7
+ * are strings, so nothing has to guess which was meant.
8
+ *
9
+ * These check what they are given, which the rule layer deliberately does not
10
+ * — `timeOfDay` accepts any string and complains when the rule is evaluated,
11
+ * because parsing shape and deciding meaning are kept apart there. This layer
12
+ * exists to be written by hand, and a hand-written mistake is worth catching
13
+ * where it was written rather than at the first query.
14
+ */
15
+ import { dates, timeOfDay } from "./build.js";
16
+ function badRange(range, problem) {
17
+ throw new RangeError(`"${range}" is not a range of times: ${problem}. ` +
18
+ `Expected something like "09:00-17:00".`);
19
+ }
20
+ /** A wall-clock window from `"09:00-17:00"`, or a rule left as it is. */
21
+ export function asHours(hours) {
22
+ if (typeof hours !== "string") {
23
+ return hours;
24
+ }
25
+ const parts = hours.split("-");
26
+ if (parts.length !== 2) {
27
+ badRange(hours, `it has ${parts.length - 1} dashes rather than one`);
28
+ }
29
+ const [from = "", to = ""] = parts.map((part) => part.trim());
30
+ for (const time of [from, to]) {
31
+ try {
32
+ Temporal.PlainTime.from(time);
33
+ }
34
+ catch {
35
+ badRange(hours, `"${time}" is not a time of day`);
36
+ }
37
+ }
38
+ return timeOfDay(from, to);
39
+ }
40
+ /** Whole days from `"2026-03-11"`, or a rule left as it is. */
41
+ export function asDays(scope) {
42
+ if (typeof scope !== "string") {
43
+ return scope;
44
+ }
45
+ try {
46
+ Temporal.PlainDate.from(scope);
47
+ }
48
+ catch {
49
+ throw new RangeError(`"${scope}" is not a date. Expected something like "2026-03-11", ` +
50
+ `or a rule such as weekdays().`);
51
+ }
52
+ return dates(scope);
53
+ }
54
+ //# sourceMappingURL=plain-forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plain-forms.js","sourceRoot":"","sources":["../src/plain-forms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAM9C,SAAS,QAAQ,CAAC,KAAa,EAAE,OAAe;IAC9C,MAAM,IAAI,UAAU,CAClB,IAAI,KAAK,8BAA8B,OAAO,IAAI;QAChD,wCAAwC,CAC3C,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,OAAO,CAAC,KAAgB;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC,MAAM,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,CAAC,KAAK,EAAE,IAAI,IAAI,wBAAwB,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,MAAM,CAAC,KAAgB;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAClB,IAAI,KAAK,yDAAyD;YAChE,+BAA+B,CAClC,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC;AACtB,CAAC"}