@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.
- package/README.md +18 -8
- package/dist/assigned.d.ts +68 -0
- package/dist/assigned.d.ts.map +1 -0
- package/dist/assigned.js +84 -0
- package/dist/assigned.js.map +1 -0
- package/dist/canonical-rule.d.ts +23 -0
- package/dist/canonical-rule.d.ts.map +1 -0
- package/dist/canonical-rule.js +139 -0
- package/dist/canonical-rule.js.map +1 -0
- package/dist/canonical.d.ts +44 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +53 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cascade.d.ts +21 -0
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +13 -0
- package/dist/cascade.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/merge.d.ts +43 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +79 -0
- package/dist/merge.js.map +1 -0
- package/dist/parse-cascade.d.ts +37 -0
- package/dist/parse-cascade.d.ts.map +1 -0
- package/dist/parse-cascade.js +105 -0
- package/dist/parse-cascade.js.map +1 -0
- package/dist/parse-fields.d.ts +7 -10
- package/dist/parse-fields.d.ts.map +1 -1
- package/dist/parse-fields.js +8 -36
- package/dist/parse-fields.js.map +1 -1
- package/dist/parse-shape.d.ts +39 -0
- package/dist/parse-shape.d.ts.map +1 -0
- package/dist/parse-shape.js +77 -0
- package/dist/parse-shape.js.map +1 -0
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +4 -26
- package/dist/parse.js.map +1 -1
- package/dist/query.d.ts +23 -17
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +25 -19
- package/dist/query.js.map +1 -1
- package/dist/resolve.d.ts +14 -8
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +41 -26
- package/dist/resolve.js.map +1 -1
- package/dist/rota.d.ts.map +1 -1
- package/dist/rota.js +2 -8
- package/dist/rota.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +2 -7
- package/dist/schedule.js.map +1 -1
- package/dist/tally.d.ts +76 -0
- package/dist/tally.d.ts.map +1 -0
- package/dist/tally.js +80 -0
- package/dist/tally.js.map +1 -0
- package/dist/valued-stream.d.ts +19 -10
- package/dist/valued-stream.d.ts.map +1 -1
- package/dist/valued-stream.js +95 -24
- package/dist/valued-stream.js.map +1 -1
- package/package.json +22 -20
package/dist/query.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Asking a
|
|
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
|
|
38
|
-
* the smallest window there is, so nothing can walk far looking for an
|
|
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(
|
|
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(
|
|
52
|
+
export declare function elapsed<V>(covers: Covers<V>, context: Context): Temporal.Duration;
|
|
48
53
|
/**
|
|
49
|
-
* The next stretch of time
|
|
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
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
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(
|
|
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
|
|
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:
|
|
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
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA
|
|
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
|
|
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
|
|
54
|
-
* the smallest window there is, so nothing can walk far looking for an
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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(
|
|
92
|
-
const [first] = take(
|
|
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
|
|
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
|
|
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":"AAAA
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
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
|
|
22
|
-
* same contract `intervals` keeps
|
|
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
|
package/dist/resolve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA
|
|
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
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
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 {
|
|
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
|
|
21
|
-
* same contract `intervals` keeps
|
|
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
|
|
25
|
-
|
|
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
|
-
*
|
|
41
|
+
* A layer's own scope, minus every scope a replacing layer above it claims.
|
|
29
42
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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:
|
|
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
|
|
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
|
|
62
|
-
//
|
|
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
|
|
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) {
|
package/dist/resolve.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
package/dist/rota.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rota.d.ts","sourceRoot":"","sources":["../src/rota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
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;
|
|
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"}
|
package/dist/schedule.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;
|
|
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)) {
|
package/dist/schedule.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAA4B,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAiB,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAkB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,8CAA8C;AAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AAuDvD,SAAS,IAAI,CAAC,KAAgB,EAAE,KAA4B;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,KAAK,CAAC,MAAiC;IAC9C,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,SAAS;QACf,MAAM;QAEN,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAClE,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CACtB,KAAK,CAAC,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE1D,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
|
package/dist/tally.d.ts
ADDED
|
@@ -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"}
|