@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/README.md
CHANGED
|
@@ -17,9 +17,6 @@ implements it. Quando reads the global rather than importing a polyfill, so it
|
|
|
17
17
|
has no runtime dependencies; anywhere without `Temporal` natively can load
|
|
18
18
|
`temporal-polyfill` first and everything here works untouched.
|
|
19
19
|
|
|
20
|
-
> The rule language, builder, parser and queries below are on `main` and go out
|
|
21
|
-
> in the next release. `0.1.0` on npm carries only the interval core.
|
|
22
|
-
|
|
23
20
|
## A rule
|
|
24
21
|
|
|
25
22
|
```ts
|
|
@@ -70,7 +67,7 @@ For opening hours and rotas there is a plainer front door, which builds the same
|
|
|
70
67
|
thing:
|
|
71
68
|
|
|
72
69
|
```ts
|
|
73
|
-
import { rota, schedule, weekdays, weekends } from "@kensio/quando";
|
|
70
|
+
import { rota, schedule, tally, weekdays, weekends } from "@kensio/quando";
|
|
74
71
|
|
|
75
72
|
const openingHours = schedule()
|
|
76
73
|
.open(weekdays(), "09:00-17:00")
|
|
@@ -84,10 +81,17 @@ const onCall = rota().assign(weekdays(), "alice").assign(weekends(), "bob");
|
|
|
84
81
|
|
|
85
82
|
onCall.whoIsOn(friday);
|
|
86
83
|
// → "alice"
|
|
84
|
+
|
|
85
|
+
const staff = tally().plus(weekdays(), 3).plus("2026-03-11", 2);
|
|
86
|
+
|
|
87
|
+
staff.at(Temporal.ZonedDateTime.from("2026-03-11T11:00[Europe/London]"));
|
|
88
|
+
// → 5
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
say them.
|
|
91
|
+
For a schedule and a rota each line outranks the ones above it, so exceptions
|
|
92
|
+
read in the order you would say them. A tally is the one that adds instead,
|
|
93
|
+
because two teams of three on a Monday are six people. See
|
|
94
|
+
[schedules and rotas](docs/schedules/) and [merging](docs/merging/).
|
|
91
95
|
|
|
92
96
|
## Why intervals
|
|
93
97
|
|
|
@@ -113,6 +117,8 @@ this repository:
|
|
|
113
117
|
- [Serialisation](docs/serialisation/) — the JSON form and its boundary
|
|
114
118
|
- [Schedules and rotas](docs/schedules/) — opening hours and who is on, plainly
|
|
115
119
|
- [Cascades](docs/cascades/) — layers carrying values, resolved by precedence
|
|
120
|
+
- [Merging](docs/merging/) — overlap that adds rather than displaces
|
|
121
|
+
- [Comparing](docs/comparing/) — canonical form, equality and cache keys
|
|
116
122
|
- [API](docs/api/) — everything the package exports
|
|
117
123
|
|
|
118
124
|
## What it is not
|
|
@@ -122,8 +128,12 @@ scheduler: Quando calculates _when_ and never fires anything, so its answer is
|
|
|
122
128
|
your scheduler's input. Not storage, and not a holiday data provider; calendar
|
|
123
129
|
data belongs in satellite packages so that the core carries none.
|
|
124
130
|
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
Not a constraint solver either. Caps per window, minimum spacing and
|
|
132
|
+
rolling-window totals ("ninety days in any hundred and eighty") constrain a
|
|
133
|
+
pattern of occurrences rather than the moments in one, which is a different
|
|
134
|
+
problem. See [what a rule cannot say](docs/concepts/#what-a-rule-cannot-say).
|
|
135
|
+
|
|
136
|
+
Estimates, rule set diffing and a command line are designed and not yet built.
|
|
127
137
|
|
|
128
138
|
## Licence
|
|
129
139
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking the four questions of a cascade rather than of a rule.
|
|
3
|
+
*
|
|
4
|
+
* `activeAt`, `elapsed`, `next` and `advanceBy` are about *when*, and a rule
|
|
5
|
+
* is what they read. A cascade says *what holds when*, which is a different
|
|
6
|
+
* question. Narrowing one to a single value turns it back into the first.
|
|
7
|
+
* The times a rota assigns to Alice are a stretch of when, and every question
|
|
8
|
+
* worth asking about a rule is worth asking about them.
|
|
9
|
+
*
|
|
10
|
+
* So {@link assigned} is what the queries take in place of a rule, and
|
|
11
|
+
* {@link valueAt} is the one question a rule has no version of.
|
|
12
|
+
*/
|
|
13
|
+
import type { Cascade, Valued } from "./cascade.js";
|
|
14
|
+
import type { Context } from "./context.js";
|
|
15
|
+
import type { IntervalStream } from "./interval-stream.js";
|
|
16
|
+
import type { Rule } from "./rule.js";
|
|
17
|
+
/**
|
|
18
|
+
* A cascade narrowed to the times it assigns one value.
|
|
19
|
+
*
|
|
20
|
+
* Not a rule, and deliberately not made to look like one. A rule is a document
|
|
21
|
+
* that stores and travels, and this is a question asked at the point of
|
|
22
|
+
* asking. Building one costs nothing and evaluates nothing.
|
|
23
|
+
*/
|
|
24
|
+
export interface Assigned<V> {
|
|
25
|
+
readonly cascade: Cascade<V>;
|
|
26
|
+
readonly is: V;
|
|
27
|
+
}
|
|
28
|
+
/** Either of the two things a query can read as the times it covers. */
|
|
29
|
+
export type Covers<V> = Rule | Assigned<V>;
|
|
30
|
+
/**
|
|
31
|
+
* The times a cascade assigns a value.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* elapsed(assigned(onCall, "alice"), week);
|
|
35
|
+
* advanceBy(from, threeHours, { during: assigned(onCall, "alice") });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Sameness is `Object.is`, the same test {@link coalesce} uses, so a value
|
|
39
|
+
* matches by identity rather than by shape.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assigned<V>(cascade: Cascade<V>, is: V): Assigned<V>;
|
|
42
|
+
/**
|
|
43
|
+
* The times something covers, whichever of the two it is.
|
|
44
|
+
*
|
|
45
|
+
* This is the one place the queries have to know that a cascade exists, and
|
|
46
|
+
* what comes back either way is an ordinary interval stream, so everything
|
|
47
|
+
* above it stays written once.
|
|
48
|
+
*/
|
|
49
|
+
export declare function covered<V>(covers: Covers<V>, context: Context): IntervalStream;
|
|
50
|
+
/**
|
|
51
|
+
* What a cascade assigns at an instant, or `undefined` where nothing does.
|
|
52
|
+
*
|
|
53
|
+
* The question a rule has no version of. `activeAt` asks whether a rule covers
|
|
54
|
+
* a moment, and the answer for a cascade is not whether but what.
|
|
55
|
+
*
|
|
56
|
+
* Always terminates, whatever the layers say, because it asks about the
|
|
57
|
+
* smallest window there is.
|
|
58
|
+
*/
|
|
59
|
+
export declare function valueAt<V>(cascade: Cascade<V>, at: Temporal.ZonedDateTime, context?: Omit<Context, "from" | "to">): V | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* The next stretch a cascade assigns anything at all, with its value.
|
|
62
|
+
*
|
|
63
|
+
* `next` narrowed to one value answers "when is Alice next on". This answers
|
|
64
|
+
* "what happens next", whatever that turns out to be, which is the question a
|
|
65
|
+
* timeline asks.
|
|
66
|
+
*/
|
|
67
|
+
export declare function nextValue<V>(cascade: Cascade<V>, context: Context): Valued<V> | undefined;
|
|
68
|
+
//# sourceMappingURL=assigned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assigned.d.ts","sourceRoot":"","sources":["../src/assigned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;CAChB;AAED,wEAAwE;AACxE,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;AAE3C;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAEnE;AAOD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,OAAO,GACf,cAAc,CAKhB;AAWD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,QAAQ,CAAC,aAAa,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC,GACrC,CAAC,GAAG,SAAS,CAQf;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,CAAC,CAAC,GAAG,SAAS,CAGvB"}
|
package/dist/assigned.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking the four questions of a cascade rather than of a rule.
|
|
3
|
+
*
|
|
4
|
+
* `activeAt`, `elapsed`, `next` and `advanceBy` are about *when*, and a rule
|
|
5
|
+
* is what they read. A cascade says *what holds when*, which is a different
|
|
6
|
+
* question. Narrowing one to a single value turns it back into the first.
|
|
7
|
+
* The times a rota assigns to Alice are a stretch of when, and every question
|
|
8
|
+
* worth asking about a rule is worth asking about them.
|
|
9
|
+
*
|
|
10
|
+
* So {@link assigned} is what the queries take in place of a rule, and
|
|
11
|
+
* {@link valueAt} is the one question a rule has no version of.
|
|
12
|
+
*/
|
|
13
|
+
import { intervals } from "./interpret.js";
|
|
14
|
+
import { resolve } from "./resolve.js";
|
|
15
|
+
import { take } from "./stream.js";
|
|
16
|
+
/**
|
|
17
|
+
* The times a cascade assigns a value.
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* elapsed(assigned(onCall, "alice"), week);
|
|
21
|
+
* advanceBy(from, threeHours, { during: assigned(onCall, "alice") });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Sameness is `Object.is`, the same test {@link coalesce} uses, so a value
|
|
25
|
+
* matches by identity rather than by shape.
|
|
26
|
+
*/
|
|
27
|
+
export function assigned(cascade, is) {
|
|
28
|
+
return { cascade, is };
|
|
29
|
+
}
|
|
30
|
+
/** Whether a query is reading a rule or a narrowed cascade. */
|
|
31
|
+
function isRule(covers) {
|
|
32
|
+
return "type" in covers;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The times something covers, whichever of the two it is.
|
|
36
|
+
*
|
|
37
|
+
* This is the one place the queries have to know that a cascade exists, and
|
|
38
|
+
* what comes back either way is an ordinary interval stream, so everything
|
|
39
|
+
* above it stays written once.
|
|
40
|
+
*/
|
|
41
|
+
export function covered(covers, context) {
|
|
42
|
+
if (isRule(covers)) {
|
|
43
|
+
return intervals(covers, context);
|
|
44
|
+
}
|
|
45
|
+
return matching(covers, context);
|
|
46
|
+
}
|
|
47
|
+
/** The stretches of a resolved cascade carrying the value asked for. */
|
|
48
|
+
function* matching(covers, context) {
|
|
49
|
+
for (const span of resolve(covers.cascade, context)) {
|
|
50
|
+
if (Object.is(span.value, covers.is)) {
|
|
51
|
+
yield { start: span.start, end: span.end };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* What a cascade assigns at an instant, or `undefined` where nothing does.
|
|
57
|
+
*
|
|
58
|
+
* The question a rule has no version of. `activeAt` asks whether a rule covers
|
|
59
|
+
* a moment, and the answer for a cascade is not whether but what.
|
|
60
|
+
*
|
|
61
|
+
* Always terminates, whatever the layers say, because it asks about the
|
|
62
|
+
* smallest window there is.
|
|
63
|
+
*/
|
|
64
|
+
export function valueAt(cascade, at, context) {
|
|
65
|
+
const moment = {
|
|
66
|
+
...context,
|
|
67
|
+
from: at,
|
|
68
|
+
to: at.add({ nanoseconds: 1 }),
|
|
69
|
+
};
|
|
70
|
+
const [now] = take(resolve(cascade, moment), 1);
|
|
71
|
+
return now?.value;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The next stretch a cascade assigns anything at all, with its value.
|
|
75
|
+
*
|
|
76
|
+
* `next` narrowed to one value answers "when is Alice next on". This answers
|
|
77
|
+
* "what happens next", whatever that turns out to be, which is the question a
|
|
78
|
+
* timeline asks.
|
|
79
|
+
*/
|
|
80
|
+
export function nextValue(cascade, context) {
|
|
81
|
+
const [first] = take(resolve(cascade, context), 1);
|
|
82
|
+
return first;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=assigned.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assigned.js","sourceRoot":"","sources":["../src/assigned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAiBnC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,QAAQ,CAAI,OAAmB,EAAE,EAAK;IACpD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACzB,CAAC;AAED,+DAA+D;AAC/D,SAAS,MAAM,CAAI,MAAiB;IAClC,OAAO,MAAM,IAAI,MAAM,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CACrB,MAAiB,EACjB,OAAgB;IAEhB,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,wEAAwE;AACxE,QAAQ,CAAC,CAAC,QAAQ,CAAI,MAAmB,EAAE,OAAgB;IACzD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YACrC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CACrB,OAAmB,EACnB,EAA0B,EAC1B,OAAsC;IAEtC,MAAM,MAAM,GAAY;QACtB,GAAG,OAAO;QACV,IAAI,EAAE,EAAE;QACR,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;KAC/B,CAAC;IACF,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,OAAO,GAAG,EAAE,KAAK,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,OAAmB,EACnB,OAAgB;IAEhB,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one form of a rule that says what a rule says.
|
|
3
|
+
*
|
|
4
|
+
* `.except(…)` is `all(this, not(any(…)))` spelled out, so a rule built with
|
|
5
|
+
* it carries an `all` inside an `all`. Nothing is wrong with that, and it does
|
|
6
|
+
* mean two rules a reader would call identical are two different documents.
|
|
7
|
+
* Comparing them, hashing them or diffing them all want the same thing first,
|
|
8
|
+
* which is a form that depends on what a rule says rather than on how it was
|
|
9
|
+
* written.
|
|
10
|
+
*
|
|
11
|
+
* The normal form here is syntactic. It flattens, drops identities, collapses
|
|
12
|
+
* double negation, sorts and deduplicates, and stops. Two rules that *cover
|
|
13
|
+
* the same time* by different routes stay different, because deciding that in
|
|
14
|
+
* general means evaluating them over all of time. `always` and the seven days
|
|
15
|
+
* of the week are the pair to keep in mind.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here throws. A rule holding a date that will not parse comes back
|
|
18
|
+
* with that date untouched, because a function used for cache keys is worth
|
|
19
|
+
* more total than strict, and `parseRule` is the place that refuses.
|
|
20
|
+
*/
|
|
21
|
+
import { type Rule } from "./rule.js";
|
|
22
|
+
export declare function canonicalRule(rule: Rule): Rule;
|
|
23
|
+
//# sourceMappingURL=canonical-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-rule.d.ts","sourceRoot":"","sources":["../src/canonical-rule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,IAAI,EAA0B,MAAM,WAAW,CAAC;AAyF9D,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAqD9C"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one form of a rule that says what a rule says.
|
|
3
|
+
*
|
|
4
|
+
* `.except(…)` is `all(this, not(any(…)))` spelled out, so a rule built with
|
|
5
|
+
* it carries an `all` inside an `all`. Nothing is wrong with that, and it does
|
|
6
|
+
* mean two rules a reader would call identical are two different documents.
|
|
7
|
+
* Comparing them, hashing them or diffing them all want the same thing first,
|
|
8
|
+
* which is a form that depends on what a rule says rather than on how it was
|
|
9
|
+
* written.
|
|
10
|
+
*
|
|
11
|
+
* The normal form here is syntactic. It flattens, drops identities, collapses
|
|
12
|
+
* double negation, sorts and deduplicates, and stops. Two rules that *cover
|
|
13
|
+
* the same time* by different routes stay different, because deciding that in
|
|
14
|
+
* general means evaluating them over all of time. `always` and the seven days
|
|
15
|
+
* of the week are the pair to keep in mind.
|
|
16
|
+
*
|
|
17
|
+
* Nothing here throws. A rule holding a date that will not parse comes back
|
|
18
|
+
* with that date untouched, because a function used for cache keys is worth
|
|
19
|
+
* more total than strict, and `parseRule` is the place that refuses.
|
|
20
|
+
*/
|
|
21
|
+
import { WEEKDAYS } from "./rule.js";
|
|
22
|
+
/** Where a weekday sorts. Calendar order rather than alphabetical. */
|
|
23
|
+
const DAY_ORDER = new Map(WEEKDAYS.map((day, index) => [day, index]));
|
|
24
|
+
/** A rule's stable string form, which is what sorting and equality compare. */
|
|
25
|
+
function key(rule) {
|
|
26
|
+
return JSON.stringify(rule);
|
|
27
|
+
}
|
|
28
|
+
/** Present or absent, never present-and-undefined. */
|
|
29
|
+
function zonePart(zone) {
|
|
30
|
+
return zone === undefined ? {} : { zone };
|
|
31
|
+
}
|
|
32
|
+
const asTime = (from) => Temporal.PlainTime.from(from);
|
|
33
|
+
const asDate = (from) => Temporal.PlainDate.from(from);
|
|
34
|
+
/**
|
|
35
|
+
* A `Temporal` value written the one way, where it can be read at all.
|
|
36
|
+
*
|
|
37
|
+
* `"09:00"` and `"09:00:00"` are the same time of day written twice, and two
|
|
38
|
+
* rules holding one each should compare equal. A string neither form can read
|
|
39
|
+
* is handed back as it came, so this stays total.
|
|
40
|
+
*/
|
|
41
|
+
function written(value, read) {
|
|
42
|
+
try {
|
|
43
|
+
return read(value).toString();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function canonicalDays(days) {
|
|
50
|
+
return [...new Set(days)].toSorted((a, b) => (DAY_ORDER.get(a) ?? 0) - (DAY_ORDER.get(b) ?? 0));
|
|
51
|
+
}
|
|
52
|
+
function canonicalDates(dates) {
|
|
53
|
+
const one = dates.map((date) => written(date, asDate));
|
|
54
|
+
return [...new Set(one)].toSorted();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The operands of an `all` or an `any`, flattened, reduced and ordered.
|
|
58
|
+
*
|
|
59
|
+
* Both are the same shape with the two constants swapped. For `all`, `always`
|
|
60
|
+
* adds nothing and `never` settles it. For `any` it is the other way round.
|
|
61
|
+
*/
|
|
62
|
+
function combined(type, rules) {
|
|
63
|
+
const absorbed = type === "all" ? "always" : "never";
|
|
64
|
+
const settles = type === "all" ? "never" : "always";
|
|
65
|
+
const flat = [];
|
|
66
|
+
for (const rule of rules) {
|
|
67
|
+
const inner = canonicalRule(rule);
|
|
68
|
+
if (inner.type === settles) {
|
|
69
|
+
return { type: settles };
|
|
70
|
+
}
|
|
71
|
+
if (inner.type === absorbed) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
// Already canonical, so its own operands are reduced and its type is not
|
|
75
|
+
// the one being flattened into unless it genuinely nests.
|
|
76
|
+
if (inner.type === type) {
|
|
77
|
+
flat.push(...inner.rules);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
flat.push(inner);
|
|
81
|
+
}
|
|
82
|
+
const kept = [...new Map(flat.map((rule) => [key(rule), rule])).values()];
|
|
83
|
+
const unique = kept.toSorted((a, b) => key(a).localeCompare(key(b)));
|
|
84
|
+
const only = unique[0];
|
|
85
|
+
if (only === undefined) {
|
|
86
|
+
return { type: absorbed };
|
|
87
|
+
}
|
|
88
|
+
return unique.length === 1 ? only : { type, rules: unique };
|
|
89
|
+
}
|
|
90
|
+
export function canonicalRule(rule) {
|
|
91
|
+
switch (rule.type) {
|
|
92
|
+
case "always":
|
|
93
|
+
case "never": {
|
|
94
|
+
return { type: rule.type };
|
|
95
|
+
}
|
|
96
|
+
case "daysOfWeek": {
|
|
97
|
+
return {
|
|
98
|
+
type: "daysOfWeek",
|
|
99
|
+
days: canonicalDays(rule.days),
|
|
100
|
+
...zonePart(rule.zone),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
case "dates": {
|
|
104
|
+
return {
|
|
105
|
+
type: "dates",
|
|
106
|
+
dates: canonicalDates(rule.dates),
|
|
107
|
+
...zonePart(rule.zone),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
case "timeOfDay": {
|
|
111
|
+
return {
|
|
112
|
+
type: "timeOfDay",
|
|
113
|
+
from: written(rule.from, asTime),
|
|
114
|
+
to: written(rule.to, asTime),
|
|
115
|
+
...zonePart(rule.zone),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
case "not": {
|
|
119
|
+
const inner = canonicalRule(rule.rule);
|
|
120
|
+
// Two complements cancel, and the complement of a constant is the other
|
|
121
|
+
// one. Both keep a `not` out of the form where it says nothing.
|
|
122
|
+
if (inner.type === "not") {
|
|
123
|
+
return inner.rule;
|
|
124
|
+
}
|
|
125
|
+
if (inner.type === "always") {
|
|
126
|
+
return { type: "never" };
|
|
127
|
+
}
|
|
128
|
+
if (inner.type === "never") {
|
|
129
|
+
return { type: "always" };
|
|
130
|
+
}
|
|
131
|
+
return { type: "not", rule: inner };
|
|
132
|
+
}
|
|
133
|
+
case "all":
|
|
134
|
+
case "any": {
|
|
135
|
+
return combined(rule.type, rule.rules);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=canonical-rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-rule.js","sourceRoot":"","sources":["../src/canonical-rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparing rules and cascades, and the one form that makes it possible.
|
|
3
|
+
*
|
|
4
|
+
* [canonical-rule.ts](./canonical-rule.ts) holds the normal form itself and
|
|
5
|
+
* the reasoning behind where it stops. This is the surface over it: the same
|
|
6
|
+
* treatment for a cascade, a stable key, and equality.
|
|
7
|
+
*/
|
|
8
|
+
import { type Cascade } from "./cascade.js";
|
|
9
|
+
import type { Rule } from "./rule.js";
|
|
10
|
+
/**
|
|
11
|
+
* The one form of a rule or a cascade that says what this one says.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* canonical(weekdays().except(dates("2026-12-25")));
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Flattens nested `all` and `any`, drops `always` from an `all` and `never`
|
|
18
|
+
* from an `any`, settles the ones that dominate, cancels double negation,
|
|
19
|
+
* deduplicates, and orders what is left. Leaves are ordered too, so
|
|
20
|
+
* `daysOfWeek("friday", "monday")` and `daysOfWeek("monday", "friday")` are
|
|
21
|
+
* the same document afterwards.
|
|
22
|
+
*
|
|
23
|
+
* A cascade keeps its layer order, because that order is its meaning.
|
|
24
|
+
*/
|
|
25
|
+
export declare function canonical(rule: Rule): Rule;
|
|
26
|
+
export declare function canonical<V>(cascade: Cascade<V>): Cascade<V>;
|
|
27
|
+
/**
|
|
28
|
+
* A stable string for a rule or a cascade, the same for any two that say the
|
|
29
|
+
* same thing.
|
|
30
|
+
*
|
|
31
|
+
* What a cache key is. A cascade's values go through `JSON.stringify` with
|
|
32
|
+
* everything else, so this is worth as much as those values are storable.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fingerprint<V>(value: Rule | Cascade<V>): string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether two rules, or two cascades, say the same thing.
|
|
37
|
+
*
|
|
38
|
+
* Syntactic, and deliberately so. Two rules that cover the same time by
|
|
39
|
+
* different routes are not equal, because deciding that in general means
|
|
40
|
+
* evaluating them over all of time. `always` and all seven days of the week
|
|
41
|
+
* are the pair to remember.
|
|
42
|
+
*/
|
|
43
|
+
export declare function equals<V>(left: Rule | Cascade<V>, right: Rule | Cascade<V>): boolean;
|
|
44
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,KAAK,OAAO,EAAyB,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAwBtC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;AAC5C,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAK9D;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAE/D;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CAAC,CAAC,EACtB,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,EACvB,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAET"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparing rules and cascades, and the one form that makes it possible.
|
|
3
|
+
*
|
|
4
|
+
* [canonical-rule.ts](./canonical-rule.ts) holds the normal form itself and
|
|
5
|
+
* the reasoning behind where it stops. This is the surface over it: the same
|
|
6
|
+
* treatment for a cascade, a stable key, and equality.
|
|
7
|
+
*/
|
|
8
|
+
import { canonicalRule } from "./canonical-rule.js";
|
|
9
|
+
import { isCascade } from "./cascade.js";
|
|
10
|
+
function canonicalLayer(layer) {
|
|
11
|
+
return "value" in layer
|
|
12
|
+
? { scope: canonicalRule(layer.scope), value: layer.value }
|
|
13
|
+
: {
|
|
14
|
+
scope: canonicalRule(layer.scope),
|
|
15
|
+
replace: canonicalCascade(layer.replace),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Layers keep their order, because order is what a cascade means. What changes
|
|
20
|
+
* is each scope, and a `merge` of `"override"` written out, which is the
|
|
21
|
+
* default said twice.
|
|
22
|
+
*/
|
|
23
|
+
function canonicalCascade(cascade) {
|
|
24
|
+
const layers = cascade.layers.map((layer) => canonicalLayer(layer));
|
|
25
|
+
return cascade.merge === undefined || cascade.merge === "override"
|
|
26
|
+
? { type: "cascade", layers }
|
|
27
|
+
: { type: "cascade", merge: cascade.merge, layers };
|
|
28
|
+
}
|
|
29
|
+
export function canonical(value) {
|
|
30
|
+
return isCascade(value) ? canonicalCascade(value) : canonicalRule(value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A stable string for a rule or a cascade, the same for any two that say the
|
|
34
|
+
* same thing.
|
|
35
|
+
*
|
|
36
|
+
* What a cache key is. A cascade's values go through `JSON.stringify` with
|
|
37
|
+
* everything else, so this is worth as much as those values are storable.
|
|
38
|
+
*/
|
|
39
|
+
export function fingerprint(value) {
|
|
40
|
+
return JSON.stringify(canonical(value));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Whether two rules, or two cascades, say the same thing.
|
|
44
|
+
*
|
|
45
|
+
* Syntactic, and deliberately so. Two rules that cover the same time by
|
|
46
|
+
* different routes are not equal, because deciding that in general means
|
|
47
|
+
* evaluating them over all of time. `always` and all seven days of the week
|
|
48
|
+
* are the pair to remember.
|
|
49
|
+
*/
|
|
50
|
+
export function equals(left, right) {
|
|
51
|
+
return fingerprint(left) === fingerprint(right);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAgB,SAAS,EAAc,MAAM,cAAc,CAAC;AAGnE,SAAS,cAAc,CAAI,KAAe;IACxC,OAAO,OAAO,IAAI,KAAK;QACrB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;QAC3D,CAAC,CAAC;YACE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC;YACjC,OAAO,EAAE,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC;SACzC,CAAC;AACR,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAI,OAAmB;IAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAEpE,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,UAAU;QAChE,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE;QAC7B,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;AACxD,CAAC;AAmBD,MAAM,UAAU,SAAS,CAAI,KAAwB;IACnD,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAI,KAAwB;IACrD,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAa,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,MAAM,CACpB,IAAuB,EACvB,KAAwB;IAExB,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC"}
|
package/dist/cascade.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* only appear where they are actually needed, which is assignment.
|
|
12
12
|
*/
|
|
13
13
|
import type { Interval } from "./interval.js";
|
|
14
|
+
import type { MergeStrategy } from "./merge.js";
|
|
14
15
|
import type { Rule } from "./rule.js";
|
|
15
16
|
/**
|
|
16
17
|
* An interval with a value assigned to it.
|
|
@@ -58,12 +59,32 @@ export interface ReplacingLayer<V> {
|
|
|
58
59
|
*/
|
|
59
60
|
export interface Cascade<V> {
|
|
60
61
|
readonly type: "cascade";
|
|
62
|
+
/**
|
|
63
|
+
* What happens where two layers claim the same moment. Absent means
|
|
64
|
+
* `override`, which is the precedence a cascade has always had.
|
|
65
|
+
*
|
|
66
|
+
* The strategy is a name in the document. A merge function passed to
|
|
67
|
+
* `resolve` could not be stored, and a cascade that no longer says how it
|
|
68
|
+
* combines is one two readers can disagree about.
|
|
69
|
+
*/
|
|
70
|
+
readonly merge?: MergeStrategy;
|
|
61
71
|
readonly layers: readonly Layer<V>[];
|
|
62
72
|
}
|
|
63
73
|
/** Whether a value is a cascade rather than a rule. */
|
|
64
74
|
export declare function isCascade<V>(value: Rule | Cascade<V>): value is Cascade<V>;
|
|
65
75
|
/** An ordered list of layers, lowest priority first. */
|
|
66
76
|
export declare function cascade<V>(...layers: readonly Layer<V>[]): Cascade<V>;
|
|
77
|
+
/**
|
|
78
|
+
* An ordered list of layers whose overlaps combine rather than displace.
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* const staff = merged("sum", layer(weekdays(), 3), layer(dates("2026-03-11"), 2));
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* The Wednesday has five. Under {@link cascade} it would have two, because the
|
|
85
|
+
* later layer would displace the earlier one.
|
|
86
|
+
*/
|
|
87
|
+
export declare function merged<V>(strategy: MergeStrategy, ...layers: readonly Layer<V>[]): Cascade<V>;
|
|
67
88
|
/** One value, across the whole of a scope. */
|
|
68
89
|
export declare function layer<V>(scope: Rule, value: V): ConstantLayer<V>;
|
|
69
90
|
/**
|
package/dist/cascade.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,CAAE,SAAQ,QAAQ;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;AAE5D,iEAAiE;AACjE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;CACtC;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAE1E;AAED,wDAAwD;AACxD,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAErE;AAED,8CAA8C;AAC9C,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,KAAK,EAAE,IAAI,EACX,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,GACtB,cAAc,CAAC,CAAC,CAAC,CAAC;AACrB,wBAAgB,OAAO,CACrB,KAAK,EAAE,IAAI,EACX,WAAW,EAAE,IAAI,GAChB,cAAc,CAAC,OAAO,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC,CAAE,SAAQ,QAAQ;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;AAE5D,iEAAiE;AACjE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;CACtC;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAE1E;AAED,wDAAwD;AACxD,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAErE;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,CAAC,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,GAC7B,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,8CAA8C;AAC9C,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,KAAK,EAAE,IAAI,EACX,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,GACtB,cAAc,CAAC,CAAC,CAAC,CAAC;AACrB,wBAAgB,OAAO,CACrB,KAAK,EAAE,IAAI,EACX,WAAW,EAAE,IAAI,GAChB,cAAc,CAAC,OAAO,CAAC,CAAC"}
|
package/dist/cascade.js
CHANGED
|
@@ -18,6 +18,19 @@ export function isCascade(value) {
|
|
|
18
18
|
export function cascade(...layers) {
|
|
19
19
|
return { type: "cascade", layers };
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* An ordered list of layers whose overlaps combine rather than displace.
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* const staff = merged("sum", layer(weekdays(), 3), layer(dates("2026-03-11"), 2));
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The Wednesday has five. Under {@link cascade} it would have two, because the
|
|
29
|
+
* later layer would displace the earlier one.
|
|
30
|
+
*/
|
|
31
|
+
export function merged(strategy, ...layers) {
|
|
32
|
+
return { type: "cascade", merge: strategy, layers };
|
|
33
|
+
}
|
|
21
34
|
/** One value, across the whole of a scope. */
|
|
22
35
|
export function layer(scope, value) {
|
|
23
36
|
return { scope, value };
|
package/dist/cascade.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade.js","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"cascade.js","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoEH,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAI,KAAwB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AAClC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,OAAO,CAAI,GAAG,MAA2B;IACvD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CACpB,QAAuB,EACvB,GAAG,MAA2B;IAE9B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,KAAK,CAAI,KAAW,EAAE,KAAQ;IAC5C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAU;IACjC,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AACpC,CAAC;AAkBD,MAAM,UAAU,OAAO,CACrB,KAAW,EACX,WAAoC;IAEpC,OAAO;QACL,KAAK;QACL,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC;KACtE,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,15 +29,26 @@ export { intervals } from "./interpret.js";
|
|
|
29
29
|
export type { Built } from "./build.js";
|
|
30
30
|
export { all, always, any, dates, daysOfWeek, inZone, never, not, timeOfDay, weekdays, weekends, } from "./build.js";
|
|
31
31
|
export { parseRule } from "./parse.js";
|
|
32
|
+
export type { ValueParser } from "./parse-cascade.js";
|
|
33
|
+
export { parseCascade } from "./parse-cascade.js";
|
|
34
|
+
export { asBoolean, asString, fail } from "./parse-shape.js";
|
|
32
35
|
export type { Cascade, ConstantLayer, Layer, ReplacingLayer, Valued, } from "./cascade.js";
|
|
33
|
-
export { cascade, isCascade, layer, replace, whenever } from "./cascade.js";
|
|
36
|
+
export { cascade, isCascade, layer, merged, replace, whenever, } from "./cascade.js";
|
|
37
|
+
export type { Merge, MergeStrategy } from "./merge.js";
|
|
38
|
+
export { MERGE_STRATEGIES } from "./merge.js";
|
|
34
39
|
export type { ValuedStream } from "./valued-stream.js";
|
|
40
|
+
export { overlay } from "./valued-stream.js";
|
|
35
41
|
export { resolve } from "./resolve.js";
|
|
42
|
+
export { canonical, equals, fingerprint } from "./canonical.js";
|
|
36
43
|
export type { PlainRule } from "./plain-forms.js";
|
|
37
44
|
export type { Schedule } from "./schedule.js";
|
|
38
45
|
export { schedule } from "./schedule.js";
|
|
39
46
|
export type { Rota } from "./rota.js";
|
|
40
47
|
export { rota } from "./rota.js";
|
|
48
|
+
export type { Tally } from "./tally.js";
|
|
49
|
+
export { tally } from "./tally.js";
|
|
50
|
+
export type { Assigned, Covers } from "./assigned.js";
|
|
51
|
+
export { assigned, nextValue, valueAt } from "./assigned.js";
|
|
41
52
|
export type { Search } from "./query.js";
|
|
42
53
|
export { activeAt, advanceBy, elapsed, next } from "./query.js";
|
|
43
54
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7D,YAAY,EACV,OAAO,EACP,aAAa,EACb,KAAK,EACL,cAAc,EACd,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EACP,SAAS,EACT,KAAK,EACL,MAAM,EACN,OAAO,EACP,QAAQ,GACT,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEhE,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,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7D,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
|
@@ -24,9 +24,16 @@ export { WEEKDAYS } from "./rule.js";
|
|
|
24
24
|
export { intervals } from "./interpret.js";
|
|
25
25
|
export { all, always, any, dates, daysOfWeek, inZone, never, not, timeOfDay, weekdays, weekends, } from "./build.js";
|
|
26
26
|
export { parseRule } from "./parse.js";
|
|
27
|
-
export {
|
|
27
|
+
export { parseCascade } from "./parse-cascade.js";
|
|
28
|
+
export { asBoolean, asString, fail } from "./parse-shape.js";
|
|
29
|
+
export { cascade, isCascade, layer, merged, replace, whenever, } from "./cascade.js";
|
|
30
|
+
export { MERGE_STRATEGIES } from "./merge.js";
|
|
31
|
+
export { overlay } from "./valued-stream.js";
|
|
28
32
|
export { resolve } from "./resolve.js";
|
|
33
|
+
export { canonical, equals, fingerprint } from "./canonical.js";
|
|
29
34
|
export { schedule } from "./schedule.js";
|
|
30
35
|
export { rota } from "./rota.js";
|
|
36
|
+
export { tally } from "./tally.js";
|
|
37
|
+
export { assigned, nextValue, valueAt } from "./assigned.js";
|
|
31
38
|
export { activeAt, advanceBy, elapsed, next } from "./query.js";
|
|
32
39
|
//# sourceMappingURL=index.js.map
|