@kensio/quando 0.2.0 → 1.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.
Files changed (63) hide show
  1. package/README.md +18 -8
  2. package/dist/assigned.d.ts +68 -0
  3. package/dist/assigned.d.ts.map +1 -0
  4. package/dist/assigned.js +84 -0
  5. package/dist/assigned.js.map +1 -0
  6. package/dist/canonical-rule.d.ts +23 -0
  7. package/dist/canonical-rule.d.ts.map +1 -0
  8. package/dist/canonical-rule.js +139 -0
  9. package/dist/canonical-rule.js.map +1 -0
  10. package/dist/canonical.d.ts +44 -0
  11. package/dist/canonical.d.ts.map +1 -0
  12. package/dist/canonical.js +53 -0
  13. package/dist/canonical.js.map +1 -0
  14. package/dist/cascade.d.ts +21 -0
  15. package/dist/cascade.d.ts.map +1 -1
  16. package/dist/cascade.js +13 -0
  17. package/dist/cascade.js.map +1 -1
  18. package/dist/index.d.ts +12 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +8 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/merge.d.ts +43 -0
  23. package/dist/merge.d.ts.map +1 -0
  24. package/dist/merge.js +79 -0
  25. package/dist/merge.js.map +1 -0
  26. package/dist/parse-cascade.d.ts +37 -0
  27. package/dist/parse-cascade.d.ts.map +1 -0
  28. package/dist/parse-cascade.js +105 -0
  29. package/dist/parse-cascade.js.map +1 -0
  30. package/dist/parse-fields.d.ts +7 -10
  31. package/dist/parse-fields.d.ts.map +1 -1
  32. package/dist/parse-fields.js +8 -36
  33. package/dist/parse-fields.js.map +1 -1
  34. package/dist/parse-shape.d.ts +39 -0
  35. package/dist/parse-shape.d.ts.map +1 -0
  36. package/dist/parse-shape.js +77 -0
  37. package/dist/parse-shape.js.map +1 -0
  38. package/dist/parse.d.ts.map +1 -1
  39. package/dist/parse.js +4 -26
  40. package/dist/parse.js.map +1 -1
  41. package/dist/query.d.ts +23 -17
  42. package/dist/query.d.ts.map +1 -1
  43. package/dist/query.js +25 -19
  44. package/dist/query.js.map +1 -1
  45. package/dist/resolve.d.ts +14 -8
  46. package/dist/resolve.d.ts.map +1 -1
  47. package/dist/resolve.js +41 -26
  48. package/dist/resolve.js.map +1 -1
  49. package/dist/rota.d.ts.map +1 -1
  50. package/dist/rota.js +2 -8
  51. package/dist/rota.js.map +1 -1
  52. package/dist/schedule.d.ts.map +1 -1
  53. package/dist/schedule.js +2 -7
  54. package/dist/schedule.js.map +1 -1
  55. package/dist/tally.d.ts +76 -0
  56. package/dist/tally.d.ts.map +1 -0
  57. package/dist/tally.js +80 -0
  58. package/dist/tally.js.map +1 -0
  59. package/dist/valued-stream.d.ts +19 -10
  60. package/dist/valued-stream.d.ts.map +1 -1
  61. package/dist/valued-stream.js +95 -24
  62. package/dist/valued-stream.js.map +1 -1
  63. package/package.json +22 -20
package/dist/query.d.ts CHANGED
@@ -1,18 +1,22 @@
1
1
  /**
2
- * Asking a rule a question, rather than reading the times it covers.
2
+ * Asking a question, rather than reading the times something covers.
3
3
  *
4
4
  * `intervals` is the plumbing. These are what a caller actually wants: is it
5
5
  * open now, how much working time is in this window, when does it next open,
6
6
  * and — the one both of the libraries this evolves from were built around —
7
7
  * where do you get to after three hours that only count while it is open.
8
8
  *
9
+ * Each takes a rule, or a cascade narrowed to one of its values by
10
+ * [`assigned`](./assigned.ts). "Three hours while the warehouse is open" and
11
+ * "three hours while Alice is on call" are the same question.
12
+ *
9
13
  * Durations are exact elapsed time throughout. Three operating hours means
10
14
  * three real hours of opening, so a window spanning a clock change is measured
11
15
  * by how long it lasted rather than by what the clock said.
12
16
  */
17
+ import { type Covers } from "./assigned.js";
13
18
  import type { Context } from "./context.js";
14
19
  import { type Interval } from "./interval.js";
15
- import type { Rule } from "./rule.js";
16
20
  /**
17
21
  * How far a search runs.
18
22
  *
@@ -32,36 +36,38 @@ export interface Search {
32
36
  readonly within?: Temporal.Duration;
33
37
  }
34
38
  /**
35
- * Whether a rule covers an instant.
39
+ * Whether a rule, or a value a cascade assigns, covers an instant.
36
40
  *
37
- * Always terminates, whatever the rule and whatever the context: it asks about
38
- * the smallest window there is, so nothing can walk far looking for an answer.
41
+ * Always terminates, whatever it is reading and whatever the context: it asks
42
+ * about the smallest window there is, so nothing can walk far looking for an
43
+ * answer.
39
44
  */
40
- export declare function activeAt(rule: Rule, at: Temporal.ZonedDateTime, context?: Omit<Context, "from" | "to">): boolean;
45
+ export declare function activeAt<V>(covers: Covers<V>, at: Temporal.ZonedDateTime, context?: Omit<Context, "from" | "to">): boolean;
41
46
  /**
42
- * How much time a rule covers within a window.
47
+ * How much time a rule, or a value a cascade assigns, covers within a window.
43
48
  *
44
49
  * Needs a window with an end, because the alternative is a number that never
45
50
  * finishes being counted.
46
51
  */
47
- export declare function elapsed(rule: Rule, context: Context): Temporal.Duration;
52
+ export declare function elapsed<V>(covers: Covers<V>, context: Context): Temporal.Duration;
48
53
  /**
49
- * The next stretch of time a rule covers, at or after the context's start.
54
+ * The next stretch of time covered, at or after the context's start.
50
55
  *
51
- * `undefined` when there is none within the search. If the rule is covering
52
- * time already at the context's start, that stretch is returned clipped to
53
- * begin there — "when does it next open" answers "it is open" rather than
54
- * skipping to tomorrow.
56
+ * `undefined` when there is none within the search. If time is being covered
57
+ * already at the context's start, that stretch is returned clipped to begin
58
+ * there — "when does it next open" answers "it is open" rather than skipping
59
+ * to tomorrow.
55
60
  */
56
- export declare function next(rule: Rule, context: Context, search?: Search): Interval | undefined;
61
+ export declare function next<V>(covers: Covers<V>, context: Context, search?: Search): Interval | undefined;
57
62
  /**
58
- * Where you get to after an amount of time that only counts while a rule holds.
63
+ * Where you get to after an amount of time that only counts while something
64
+ * holds.
59
65
  *
60
66
  * Three operating hours from an order placed at five to five on a Friday is
61
67
  * some way into Monday morning, and this is the function that says where.
62
68
  * `undefined` when the search runs out before the time does.
63
69
  */
64
- export declare function advanceBy(from: Temporal.ZonedDateTime, amount: Temporal.Duration, options: {
65
- readonly during: Rule;
70
+ export declare function advanceBy<V>(from: Temporal.ZonedDateTime, amount: Temporal.Duration, options: {
71
+ readonly during: Covers<V>;
66
72
  } & Search & Omit<Context, "from" | "to">): Temporal.ZonedDateTime | undefined;
67
73
  //# sourceMappingURL=query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAwB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMtC;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACrC;AA0CD;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,QAAQ,CAAC,aAAa,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,GACrC,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAevE;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAClB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,GAAG,SAAS,CAGtB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,GACzE,QAAQ,CAAC,aAAa,GAAG,SAAS,CA8BpC"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAW,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAwB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAMpE;;;;;;;;GAQG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACrC;AA0CD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EACxB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,EAAE,EAAE,QAAQ,CAAC,aAAa,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,GACrC,OAAO,CAOT;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,OAAO,GACf,QAAQ,CAAC,QAAQ,CAenB;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EACpB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,GAAG,SAAS,CAGtB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG,MAAM,GAC9C,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,GAC7B,QAAQ,CAAC,aAAa,GAAG,SAAS,CA8BpC"}
package/dist/query.js CHANGED
@@ -1,17 +1,21 @@
1
1
  /**
2
- * Asking a rule a question, rather than reading the times it covers.
2
+ * Asking a question, rather than reading the times something covers.
3
3
  *
4
4
  * `intervals` is the plumbing. These are what a caller actually wants: is it
5
5
  * open now, how much working time is in this window, when does it next open,
6
6
  * and — the one both of the libraries this evolves from were built around —
7
7
  * where do you get to after three hours that only count while it is open.
8
8
  *
9
+ * Each takes a rule, or a cascade narrowed to one of its values by
10
+ * [`assigned`](./assigned.ts). "Three hours while the warehouse is open" and
11
+ * "three hours while Alice is on call" are the same question.
12
+ *
9
13
  * Durations are exact elapsed time throughout. Three operating hours means
10
14
  * three real hours of opening, so a window spanning a clock change is measured
11
15
  * by how long it lasted rather than by what the clock said.
12
16
  */
17
+ import { covered } from "./assigned.js";
13
18
  import { duration, earlierEnd } from "./interval.js";
14
- import { intervals } from "./interpret.js";
15
19
  import { take } from "./stream.js";
16
20
  /** Zero, as a duration to accumulate onto. */
17
21
  const NOTHING = Temporal.Duration.from({ seconds: 0 });
@@ -48,31 +52,32 @@ function checkExact(amount) {
48
52
  }
49
53
  }
50
54
  /**
51
- * Whether a rule covers an instant.
55
+ * Whether a rule, or a value a cascade assigns, covers an instant.
52
56
  *
53
- * Always terminates, whatever the rule and whatever the context: it asks about
54
- * the smallest window there is, so nothing can walk far looking for an answer.
57
+ * Always terminates, whatever it is reading and whatever the context: it asks
58
+ * about the smallest window there is, so nothing can walk far looking for an
59
+ * answer.
55
60
  */
56
- export function activeAt(rule, at, context) {
61
+ export function activeAt(covers, at, context) {
57
62
  const moment = {
58
63
  ...context,
59
64
  from: at,
60
65
  to: at.add({ nanoseconds: 1 }),
61
66
  };
62
- return take(intervals(rule, moment), 1).length > 0;
67
+ return take(covered(covers, moment), 1).length > 0;
63
68
  }
64
69
  /**
65
- * How much time a rule covers within a window.
70
+ * How much time a rule, or a value a cascade assigns, covers within a window.
66
71
  *
67
72
  * Needs a window with an end, because the alternative is a number that never
68
73
  * finishes being counted.
69
74
  */
70
- export function elapsed(rule, context) {
75
+ export function elapsed(covers, context) {
71
76
  if (context.to === undefined) {
72
77
  throw new RangeError("elapsed() needs a window with an end: give the context a `to`.");
73
78
  }
74
79
  let total = NOTHING;
75
- for (const interval of intervals(rule, context)) {
80
+ for (const interval of covered(covers, context)) {
76
81
  const length = duration(interval);
77
82
  if (length !== undefined) {
78
83
  total = total.add(length);
@@ -81,19 +86,20 @@ export function elapsed(rule, context) {
81
86
  return total.round({ largestUnit: "hour" });
82
87
  }
83
88
  /**
84
- * The next stretch of time a rule covers, at or after the context's start.
89
+ * The next stretch of time covered, at or after the context's start.
85
90
  *
86
- * `undefined` when there is none within the search. If the rule is covering
87
- * time already at the context's start, that stretch is returned clipped to
88
- * begin there — "when does it next open" answers "it is open" rather than
89
- * skipping to tomorrow.
91
+ * `undefined` when there is none within the search. If time is being covered
92
+ * already at the context's start, that stretch is returned clipped to begin
93
+ * there — "when does it next open" answers "it is open" rather than skipping
94
+ * to tomorrow.
90
95
  */
91
- export function next(rule, context, search) {
92
- const [first] = take(intervals(rule, bounded(context, search)), 1);
96
+ export function next(covers, context, search) {
97
+ const [first] = take(covered(covers, bounded(context, search)), 1);
93
98
  return first;
94
99
  }
95
100
  /**
96
- * Where you get to after an amount of time that only counts while a rule holds.
101
+ * Where you get to after an amount of time that only counts while something
102
+ * holds.
97
103
  *
98
104
  * Three operating hours from an order placed at five to five on a Friday is
99
105
  * some way into Monday morning, and this is the function that says where.
@@ -107,7 +113,7 @@ export function advanceBy(from, amount, options) {
107
113
  const { during, within, ...rest } = options;
108
114
  const context = bounded({ ...rest, from }, within === undefined ? undefined : { within });
109
115
  let remaining = amount;
110
- for (const interval of intervals(during, context)) {
116
+ for (const interval of covered(during, context)) {
111
117
  const length = duration(interval);
112
118
  // An interval with no end has more than enough of whatever is left.
113
119
  if (length === undefined ||
package/dist/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
package/dist/resolve.d.ts CHANGED
@@ -1,15 +1,21 @@
1
1
  /**
2
2
  * Reading a cascade as the values it assigns, over time.
3
3
  *
4
- * The whole of resolution is one idea: **a layer holds where its own scope
5
- * holds and no layer above it claims the moment.** Said as a rule that is
6
- * `all(scope, not(any(…the scopes above)))`, which the rule interpreter
7
- * already knows how to evaluate so precedence costs no new algebra, and the
8
- * clipping, the zone normalisation and the laziness all come along unchanged.
4
+ * Resolution is a fold. Each layer is read as the times it covers, and laid
5
+ * over everything below it by the cascade's {@link MergeStrategy}. Precedence
6
+ * falls out of that as the merge that keeps the later value, so a rota and a
7
+ * roster of headcounts take the same path through here and differ only in what
8
+ * they do where two layers meet.
9
+ *
10
+ * The regions themselves stay ordinary rules. A layer covers its own scope,
11
+ * minus anything a *replacing* layer above it has claimed, and that is
12
+ * `all(scope, not(any(…)))` which the rule interpreter already evaluates. So
13
+ * the clipping, the zone normalisation and the laziness all come along
14
+ * unchanged, and the one new sweep is the two-stream {@link overlay}.
9
15
  *
10
16
  * What comes back is only the time a cascade actually assigns. A moment no
11
17
  * layer claims is absent from the stream rather than present with some empty
12
- * value, for the same reason a rule yields only the time it covers: there is
18
+ * value, for the same reason a rule yields only the time it covers. There is
13
19
  * no such thing as the value of an unassigned moment.
14
20
  */
15
21
  import type { Cascade } from "./cascade.js";
@@ -18,8 +24,8 @@ import { type ValuedStream } from "./valued-stream.js";
18
24
  /**
19
25
  * The values a cascade assigns within a context, in order and coalesced.
20
26
  *
21
- * Lazy, and endless when the context has no end and the layers recur the
22
- * same contract `intervals` keeps, because this is built out of it.
27
+ * Lazy, and endless when the context has no end and the layers recur, which is
28
+ * the same contract `intervals` keeps because this is built out of it.
23
29
  */
24
30
  export declare function resolve<V>(cascade: Cascade<V>, context: Context): ValuedStream<V>;
25
31
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAS,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAI5C,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7E;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,EAAE,OAAO,GACf,YAAY,CAAC,CAAC,CAAC,CASjB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAS,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAK5C,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE1E;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,EAAE,OAAO,GACf,YAAY,CAAC,CAAC,CAAC,CAWjB"}
package/dist/resolve.js CHANGED
@@ -1,54 +1,69 @@
1
1
  /**
2
2
  * Reading a cascade as the values it assigns, over time.
3
3
  *
4
- * The whole of resolution is one idea: **a layer holds where its own scope
5
- * holds and no layer above it claims the moment.** Said as a rule that is
6
- * `all(scope, not(any(…the scopes above)))`, which the rule interpreter
7
- * already knows how to evaluate so precedence costs no new algebra, and the
8
- * clipping, the zone normalisation and the laziness all come along unchanged.
4
+ * Resolution is a fold. Each layer is read as the times it covers, and laid
5
+ * over everything below it by the cascade's {@link MergeStrategy}. Precedence
6
+ * falls out of that as the merge that keeps the later value, so a rota and a
7
+ * roster of headcounts take the same path through here and differ only in what
8
+ * they do where two layers meet.
9
+ *
10
+ * The regions themselves stay ordinary rules. A layer covers its own scope,
11
+ * minus anything a *replacing* layer above it has claimed, and that is
12
+ * `all(scope, not(any(…)))` which the rule interpreter already evaluates. So
13
+ * the clipping, the zone normalisation and the laziness all come along
14
+ * unchanged, and the one new sweep is the two-stream {@link overlay}.
9
15
  *
10
16
  * What comes back is only the time a cascade actually assigns. A moment no
11
17
  * layer claims is absent from the stream rather than present with some empty
12
- * value, for the same reason a rule yields only the time it covers: there is
18
+ * value, for the same reason a rule yields only the time it covers. There is
13
19
  * no such thing as the value of an unassigned moment.
14
20
  */
15
21
  import { intervals } from "./interpret.js";
16
- import { coalesce, interleave } from "./valued-stream.js";
22
+ import { mergeBy } from "./merge.js";
23
+ import { coalesce, overlay } from "./valued-stream.js";
17
24
  /**
18
25
  * The values a cascade assigns within a context, in order and coalesced.
19
26
  *
20
- * Lazy, and endless when the context has no end and the layers recur the
21
- * same contract `intervals` keeps, because this is built out of it.
27
+ * Lazy, and endless when the context has no end and the layers recur, which is
28
+ * the same contract `intervals` keeps because this is built out of it.
22
29
  */
23
30
  export function resolve(cascade, context) {
24
- const claimed = cascade.layers.map((layer, index) => assignments(layer, wins(layer.scope, cascade.layers.slice(index + 1)), context));
25
- return coalesce(interleave(claimed));
31
+ const merge = mergeBy(cascade.merge);
32
+ let stack = [];
33
+ for (const [index, layer] of cascade.layers.entries()) {
34
+ const above = cascade.layers.slice(index + 1);
35
+ const claimed = assignments(layer, unreplaced(layer.scope, above), context);
36
+ stack = overlay(stack, claimed, merge);
37
+ }
38
+ return coalesce(stack);
26
39
  }
27
40
  /**
28
- * Where a layer wins: inside its own scope, and outside every scope above it.
41
+ * A layer's own scope, minus every scope a replacing layer above it claims.
29
42
  *
30
- * The layers above are re-evaluated once per layer below them, which is
31
- * quadratic in the number of layers. Layers are few and the streams are lazy,
32
- * so this buys a precedence that needs no sweep of its own for the price of
33
- * some repeated work over a handful of rules.
43
+ * Nothing needs subtracting for an ordinary layer above. The fold already
44
+ * settles that, and under `override` the later value wins the overlap outright.
45
+ * A replacing layer is the case that cannot be left to the fold, because it
46
+ * claims its scope whether or not the cascade inside it assigns anything
47
+ * there. Closing early on one day is exactly that. The base hours must stay
48
+ * out of the afternoon the override dropped, rather than showing through it.
34
49
  */
35
- function wins(scope, above) {
36
- // For the top layer this is `all(scope, not(any()))` `any()` covers no
37
- // time, its complement covers all of it, and the intersection is the scope
38
- // itself. Left general rather than special-cased: one path is easier to
39
- // trust than two, and the identities make the general one right.
50
+ function unreplaced(scope, above) {
51
+ const replacing = above.filter((layer) => "replace" in layer);
52
+ if (replacing.length === 0) {
53
+ return scope;
54
+ }
40
55
  return {
41
56
  type: "all",
42
57
  rules: [
43
58
  scope,
44
59
  {
45
60
  type: "not",
46
- rule: { type: "any", rules: above.map((layer) => layer.scope) },
61
+ rule: { type: "any", rules: replacing.map((layer) => layer.scope) },
47
62
  },
48
63
  ],
49
64
  };
50
65
  }
51
- /** What a layer assigns, over the region it wins. */
66
+ /** What a layer assigns, over the region it covers. */
52
67
  function* assignments(layer, region, context) {
53
68
  for (const interval of intervals(region, context)) {
54
69
  if ("value" in layer) {
@@ -58,8 +73,8 @@ function* assignments(layer, region, context) {
58
73
  // A replacing layer claims the region and hands the question inwards. The
59
74
  // inner cascade is resolved against the region rather than against the
60
75
  // whole context, which is what stops it reaching outside the scope it
61
- // replaces and what makes anything it leaves unassigned stay unassigned
62
- // rather than falling through to the layers this one outranks.
76
+ // replaces. It also carries its own merge, so a replacement says how its
77
+ // own layers combine without the cascade around it having a view.
63
78
  yield* resolve(layer.replace, within(context, interval));
64
79
  }
65
80
  }
@@ -67,7 +82,7 @@ function* assignments(layer, region, context) {
67
82
  * A context narrowed to one interval.
68
83
  *
69
84
  * The interval came from evaluating a rule against this context, so its start
70
- * is inside the window and never unbounded; the fallback is for the type
85
+ * is inside the window and never unbounded. The fallback is for the type
71
86
  * rather than for a case that occurs.
72
87
  */
73
88
  function within(context, interval) {
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAqB,MAAM,oBAAoB,CAAC;AAE7E;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CACrB,OAAmB,EACnB,OAAgB;IAEhB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAClD,WAAW,CACT,KAAK,EACL,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAClD,OAAO,CACR,CACF,CAAC;IACF,OAAO,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,IAAI,CAAC,KAAW,EAAE,KAAgC;IACzD,yEAAyE;IACzE,2EAA2E;IAC3E,wEAAwE;IACxE,iEAAiE;IACjE,OAAO;QACL,IAAI,EAAE,KAAK;QACX,KAAK,EAAE;YACL,KAAK;YACL;gBACE,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;aAChE;SACF;KACF,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,QAAQ,CAAC,CAAC,WAAW,CACnB,KAAe,EACf,MAAY,EACZ,OAAgB;IAEhB,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QAClD,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,0EAA0E;QAC1E,uEAAuE;QACvE,sEAAsE;QACtE,0EAA0E;QAC1E,+DAA+D;QAC/D,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,OAAgB,EAAE,QAAkB;IAClD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC;IAErC,OAAO,QAAQ,CAAC,GAAG,KAAK,SAAS;QAC/B,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;QAC1B,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAqB,MAAM,oBAAoB,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CACrB,OAAmB,EACnB,OAAgB;IAEhB,MAAM,KAAK,GAAG,OAAO,CAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAExC,IAAI,KAAK,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAC5E,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,UAAU,CAAC,KAAW,EAAE,KAAgC;IAC/D,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;IAC9D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO;QACL,IAAI,EAAE,KAAK;QACX,KAAK,EAAE;YACL,KAAK;YACL;gBACE,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;aACpE;SACF;KACF,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,QAAQ,CAAC,CAAC,WAAW,CACnB,KAAe,EACf,MAAY,EACZ,OAAgB;IAEhB,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QAClD,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;YACrB,MAAM,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QAED,0EAA0E;QAC1E,uEAAuE;QACvE,sEAAsE;QACtE,yEAAyE;QACzE,kEAAkE;QAClE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,OAAgB,EAAE,QAAkB;IAClD,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC;IAErC,OAAO,QAAQ,CAAC,GAAG,KAAK,SAAS;QAC/B,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;QAC1B,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC;AACjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"rota.d.ts","sourceRoot":"","sources":["../src/rota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,yEAAyE;AACzE,MAAM,WAAW,IAAI,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAElE,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;IAEhE;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,CAAC,EAAE,QAAQ,CAAC,aAAa,KACxB,YAAY,CAAC,CAAC,CAAC,CAAC;CACtB;AA4BD;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAEzC"}
1
+ {"version":3,"file":"rota.d.ts","sourceRoot":"","sources":["../src/rota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,KAAK,OAAO,EAAqB,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,yEAAyE;AACzE,MAAM,WAAW,IAAI,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACzC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEtE;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAElE,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;IAEhE;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,CAAC,EAAE,QAAQ,CAAC,aAAa,KACxB,YAAY,CAAC,CAAC,CAAC,CAAC;CACtB;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAEzC"}
package/dist/rota.js CHANGED
@@ -10,23 +10,17 @@
10
10
  * makes an exhaustive switch over who is on call actually exhaustive. Ask for
11
11
  * `rota<string>()` when the names are not known up front.
12
12
  */
13
+ import { valueAt } from "./assigned.js";
13
14
  import { layer } from "./cascade.js";
14
15
  import { asDays } from "./plain-forms.js";
15
16
  import { resolve } from "./resolve.js";
16
- import { take } from "./stream.js";
17
17
  function build(layers) {
18
18
  const self = {
19
19
  type: "cascade",
20
20
  layers,
21
21
  assign: (scope, value) => build([...layers, layer(asDays(scope), value)]),
22
22
  swap: (day, value) => build([...layers, layer(asDays(day), value)]),
23
- whoIsOn: (at) => {
24
- // The smallest window there is, so this terminates whatever the layers
25
- // say — the same trick `activeAt` uses on a rule.
26
- const moment = { from: at, to: at.add({ nanoseconds: 1 }) };
27
- const [now] = take(resolve(self, moment), 1);
28
- return now?.value;
29
- },
23
+ whoIsOn: (at) => valueAt(self, at),
30
24
  shifts: (from, to) => resolve(self, to === undefined ? { from } : { from, to }),
31
25
  };
32
26
  return self;
package/dist/rota.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rota.js","sourceRoot":"","sources":["../src/rota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAA4B,KAAK,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAkB,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAgCnC,SAAS,KAAK,CAAI,MAA2B;IAC3C,MAAM,IAAI,GAAY;QACpB,IAAI,EAAE,SAAS;QACf,MAAM;QAEN,MAAM,EAAE,CAAI,KAAgB,EAAE,KAAQ,EAAE,EAAE,CACxC,KAAK,CAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,CAAQ,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAE/D,IAAI,EAAE,CAAI,GAAc,EAAE,KAAQ,EAAE,EAAE,CACpC,KAAK,CAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,CAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAE7D,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE;YACd,uEAAuE;YACvE,kDAAkD;YAClD,MAAM,MAAM,GAAY,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACrE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7C,OAAO,GAAG,EAAE,KAAK,CAAC;QACpB,CAAC;QAED,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CACnB,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;KAC5D,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,IAAI;IAClB,OAAO,KAAK,CAAI,EAAE,CAAC,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"rota.js","sourceRoot":"","sources":["../src/rota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAA4B,KAAK,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAkB,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAgCvC,SAAS,KAAK,CAAI,MAA2B;IAC3C,MAAM,IAAI,GAAY;QACpB,IAAI,EAAE,SAAS;QACf,MAAM;QAEN,MAAM,EAAE,CAAI,KAAgB,EAAE,KAAQ,EAAE,EAAE,CACxC,KAAK,CAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,CAAQ,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAE/D,IAAI,EAAE,CAAI,GAAc,EAAE,KAAQ,EAAE,EAAE,CACpC,KAAK,CAAQ,CAAC,GAAG,MAAM,EAAE,KAAK,CAAQ,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAE7D,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAElC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CACnB,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;KAC5D,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,IAAI;IAClB,OAAO,KAAK,CAAI,EAAE,CAAC,CAAC;AACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,KAAK,OAAO,EAA8B,MAAM,cAAc,CAAC;AAExE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOnE;;;;;;GAMG;AACH,MAAM,WAAW,QAAS,SAAQ,OAAO,CAAC,OAAO,CAAC;IAChD;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEjE,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEhD;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEjE,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,aAAa,KAAK,OAAO,CAAC;IAEzD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,SAAS,EAAE,CAClB,EAAE,EAAE,QAAQ,CAAC,aAAa,EAC1B,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACvB,QAAQ,GAAG,SAAS,CAAC;IAE1B,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,CACpB,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,EAAE,QAAQ,CAAC,aAAa,KACvB,QAAQ,CAAC,QAAQ,CAAC;CACxB;AA+DD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,IAAI,QAAQ,CAEnC"}
1
+ {"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,KAAK,OAAO,EAA8B,MAAM,cAAc,CAAC;AAExE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOnE;;;;;;GAMG;AACH,MAAM,WAAW,QAAS,SAAQ,OAAO,CAAC,OAAO,CAAC;IAChD;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEjE,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEhD;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,KAAK,QAAQ,CAAC;IAEjE,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,aAAa,KAAK,OAAO,CAAC;IAEzD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,SAAS,EAAE,CAClB,EAAE,EAAE,QAAQ,CAAC,aAAa,EAC1B,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACvB,QAAQ,GAAG,SAAS,CAAC;IAE1B,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,CACpB,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,EAAE,QAAQ,CAAC,aAAa,KACvB,QAAQ,CAAC,QAAQ,CAAC;CACxB;AAyDD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,IAAI,QAAQ,CAEnC"}
package/dist/schedule.js CHANGED
@@ -11,6 +11,7 @@
11
11
  * before it — which is the same precedence a cascade has, arrived at by
12
12
  * writing the sentence in the obvious order rather than by knowing the rule.
13
13
  */
14
+ import { valueAt } from "./assigned.js";
14
15
  import { all } from "./build.js";
15
16
  import { layer, replace } from "./cascade.js";
16
17
  import { duration } from "./interval.js";
@@ -30,13 +31,7 @@ function build(layers) {
30
31
  open: (scope, hours) => build([...layers, open(scope, hours)]),
31
32
  closed: (scope) => build([...layers, layer(asDays(scope), false)]),
32
33
  hoursOn: (day, hours) => build([...layers, replace(asDays(day), asHours(hours))]),
33
- isOpen: (at) => {
34
- // The smallest window there is, so this terminates whatever the layers
35
- // say — the same trick `activeAt` uses on a rule.
36
- const moment = { from: at, to: at.add({ nanoseconds: 1 }) };
37
- const [now] = take(resolve(self, moment), 1);
38
- return now?.value ?? false;
39
- },
34
+ isOpen: (at) => valueAt(self, at) ?? false,
40
35
  opensNext: (at, within) => {
41
36
  const search = within === undefined ? { from: at } : { from: at, to: at.add(within) };
42
37
  for (const period of resolve(self, search)) {
@@ -1 +1 @@
1
- {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * How many, in the words people use for counting.
3
+ *
4
+ * The same relationship to [merging](./merge.ts) that a
5
+ * [schedule](./schedule.ts) has to a cascade. `merged("sum", layer(…),
6
+ * layer(…))` says what it does, and it asks the reader to know three things
7
+ * first: that layers overlap, that an overlap is what combines, and what a
8
+ * bare `"sum"` in the first argument governs. Nobody staffing a warehouse
9
+ * says any of that. They say three on weekdays, two more on the eleventh.
10
+ *
11
+ * A `Tally` *is* a `Cascade<number>` with `merge: "sum"`, so everything that
12
+ * takes a cascade takes one of these, and it serialises to the document a
13
+ * hand-written one would.
14
+ */
15
+ import { type Cascade } from "./cascade.js";
16
+ import { type PlainRule } from "./plain-forms.js";
17
+ import type { ValuedStream } from "./valued-stream.js";
18
+ /** How many there are over time, and the questions worth asking about that. */
19
+ export interface Tally extends Cascade<number> {
20
+ /**
21
+ * That much more, on top of whatever else covers the same time.
22
+ *
23
+ * The verb a tally is mostly written in. Two teams each putting three
24
+ * people on a Monday have six people on that Monday.
25
+ */
26
+ readonly plus: (scope: PlainRule, amount: number) => Tally;
27
+ /**
28
+ * That many for these times, in place of whatever was said before.
29
+ *
30
+ * Instead of, not as well as. A skeleton crew on Christmas Eve is a figure
31
+ * that replaces the usual one, and writing it as a `plus` would need the
32
+ * author to know what they were adding to.
33
+ *
34
+ * "Exactly" is about the figure rather than the last word on it. This
35
+ * outranks every line above it, and a `plus` written afterwards still adds,
36
+ * the same way `hoursOn` works on a [schedule](./schedule.ts).
37
+ */
38
+ readonly exactly: (scope: PlainRule, amount: number) => Tally;
39
+ /**
40
+ * How many at that moment.
41
+ *
42
+ * Zero where no layer claims the moment. A cascade leaves an unclaimed
43
+ * moment out of its stream, and nobody rostered is nobody there, so this
44
+ * reads it as the figure it is. The same call
45
+ * [`isOpen`](./schedule.ts) makes for a schedule.
46
+ */
47
+ readonly at: (at: Temporal.ZonedDateTime) => number;
48
+ /**
49
+ * The lowest figure anywhere between two moments.
50
+ *
51
+ * The question capacity is really asking. A stretch that no layer claims
52
+ * counts as zero, so a window with a gap in it answers zero however well
53
+ * covered the rest of it is.
54
+ */
55
+ readonly least: (from: Temporal.ZonedDateTime, to: Temporal.ZonedDateTime) => number;
56
+ /**
57
+ * Each stretch between two moments, and how many are on for it.
58
+ *
59
+ * Leave `to` out for an endless run of them, which is lazy and safe to stop
60
+ * pulling from whenever you have enough.
61
+ */
62
+ readonly counts: (from: Temporal.ZonedDateTime, to?: Temporal.ZonedDateTime) => ValuedStream<number>;
63
+ }
64
+ /**
65
+ * An empty tally: nobody, until something says otherwise.
66
+ *
67
+ * ```ts
68
+ * const staff = tally()
69
+ * .plus(weekdays(), 3)
70
+ * .plus(weekends(), 1)
71
+ * .plus("2026-03-11", 2)
72
+ * .exactly("2026-12-24", 1);
73
+ * ```
74
+ */
75
+ export declare function tally(): Tally;
76
+ //# sourceMappingURL=tally.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tally.d.ts","sourceRoot":"","sources":["../src/tally.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,+EAA+E;AAC/E,MAAM,WAAW,KAAM,SAAQ,OAAO,CAAC,MAAM,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;IAE3D;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;IAE9D;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,aAAa,KAAK,MAAM,CAAC;IAEpD;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,CACd,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,EAAE,QAAQ,CAAC,aAAa,KACvB,MAAM,CAAC;IAEZ;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,IAAI,EAAE,QAAQ,CAAC,aAAa,EAC5B,EAAE,CAAC,EAAE,QAAQ,CAAC,aAAa,KACxB,YAAY,CAAC,MAAM,CAAC,CAAC;CAC3B;AAwDD;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,IAAI,KAAK,CAE7B"}