@zingage/scheduling 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +190 -5
  2. package/dist/batcher.d.ts +231 -0
  3. package/dist/batcher.d.ts.map +1 -0
  4. package/dist/batcher.js +391 -0
  5. package/dist/batcher.js.map +1 -0
  6. package/dist/collapsed-task-creator.d.ts +235 -0
  7. package/dist/collapsed-task-creator.d.ts.map +1 -0
  8. package/dist/collapsed-task-creator.js +491 -0
  9. package/dist/collapsed-task-creator.js.map +1 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +6 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/logger.d.ts +16 -0
  15. package/dist/logger.d.ts.map +1 -0
  16. package/dist/logger.js +14 -0
  17. package/dist/logger.js.map +1 -0
  18. package/dist/pending-promises-tracker.d.ts +32 -0
  19. package/dist/pending-promises-tracker.d.ts.map +1 -0
  20. package/dist/pending-promises-tracker.js +60 -0
  21. package/dist/pending-promises-tracker.js.map +1 -0
  22. package/dist/performance-now.d.ts +14 -0
  23. package/dist/performance-now.d.ts.map +1 -0
  24. package/dist/performance-now.js +10 -0
  25. package/dist/performance-now.js.map +1 -0
  26. package/dist/scheduling-contract-error.d.ts +9 -0
  27. package/dist/scheduling-contract-error.d.ts.map +1 -0
  28. package/dist/scheduling-contract-error.js +9 -0
  29. package/dist/scheduling-contract-error.js.map +1 -0
  30. package/dist/synchronous-result.d.ts +10 -0
  31. package/dist/synchronous-result.d.ts.map +1 -0
  32. package/dist/synchronous-result.js +18 -0
  33. package/dist/synchronous-result.js.map +1 -0
  34. package/dist/time-sliced-search.d.ts +47 -0
  35. package/dist/time-sliced-search.d.ts.map +1 -0
  36. package/dist/time-sliced-search.js +41 -0
  37. package/dist/time-sliced-search.js.map +1 -0
  38. package/dist/time-slicing.d.ts +20 -7
  39. package/dist/time-slicing.d.ts.map +1 -1
  40. package/dist/time-slicing.js +14 -8
  41. package/dist/time-slicing.js.map +1 -1
  42. package/dist/wrap-with-task-collapsing.d.ts +30 -0
  43. package/dist/wrap-with-task-collapsing.d.ts.map +1 -0
  44. package/dist/wrap-with-task-collapsing.js +80 -0
  45. package/dist/wrap-with-task-collapsing.js.map +1 -0
  46. package/package.json +10 -4
  47. package/src/batcher.ts +614 -0
  48. package/src/collapsed-task-creator.ts +774 -0
  49. package/src/index.ts +23 -0
  50. package/src/logger.ts +32 -0
  51. package/src/pending-promises-tracker.ts +62 -0
  52. package/src/performance-now.ts +21 -0
  53. package/src/scheduling-contract-error.ts +8 -0
  54. package/src/synchronous-result.ts +28 -0
  55. package/src/time-sliced-search.ts +98 -0
  56. package/src/time-slicing.ts +50 -26
  57. package/src/wrap-with-task-collapsing.ts +103 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Tracks promises until they settle, so that an owner's `close` can wait for
3
+ * the work it accepted.
4
+ *
5
+ * Each tracked promise leaves the tracker when it settles. Tracking never
6
+ * creates an unhandled rejection: the tracker observes a rejection, but the
7
+ * caller still owns the promise and its rejection.
8
+ *
9
+ * The tracker has no closed state. Each owner decides what new work does
10
+ * after its own `close` starts, and in what order it drains its trackers.
11
+ */
12
+ export class PendingPromisesTracker {
13
+ #pending = new Set();
14
+ /** The number of tracked promises that have not settled yet. */
15
+ get size() {
16
+ return this.#pending.size;
17
+ }
18
+ /** Tracks `promise` until it settles, and returns it unchanged. */
19
+ // oxlint-disable-next-line typescript/promise-function-async -- Returns the same promise it tracks.
20
+ track(promise) {
21
+ this.#pending.add(promise);
22
+ const untrack = () => {
23
+ this.#pending.delete(promise);
24
+ };
25
+ // oxlint-disable-next-line no-void -- Untracks on settle; the caller owns the promise and its rejection.
26
+ void promise.then(untrack, untrack);
27
+ return promise;
28
+ }
29
+ /**
30
+ * Calls `start` and tracks its result. The promise is tracked before
31
+ * `start` runs, so a `drain` that `start` itself triggers synchronously
32
+ * still waits for it. A synchronous throw from `start` becomes a rejection.
33
+ */
34
+ // oxlint-disable-next-line typescript/promise-function-async -- Returns the tracked promise, and must call start synchronously.
35
+ run(start) {
36
+ const { promise, resolve, reject } = Promise.withResolvers();
37
+ // oxlint-disable-next-line no-void -- track returns the same promise, which run returns.
38
+ void this.track(promise);
39
+ try {
40
+ resolve(start());
41
+ }
42
+ catch (error) {
43
+ reject(error);
44
+ }
45
+ return promise;
46
+ }
47
+ /**
48
+ * Resolves once no tracked promise is pending, including promises tracked
49
+ * while it waits. It loops because settling work can start more work, for
50
+ * example a producer that reads other keys from its own wrapper. It never
51
+ * rejects.
52
+ */
53
+ async drain() {
54
+ // oxlint-disable-next-line zingage/no-restricted-syntax -- Loops until nothing is pending, because settling work can track more.
55
+ while (this.#pending.size > 0) {
56
+ await Promise.allSettled(this.#pending);
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=pending-promises-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-promises-tracker.js","sourceRoot":"","sources":["../src/pending-promises-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,sBAAsB;IACxB,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEhD,gEAAgE;IAChE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED,mEAAmE;IACnE,oGAAoG;IACpG,KAAK,CAAI,OAAmB;QAC1B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC;QACF,yGAAyG;QACzG,KAAK,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;OAIG;IACH,gIAAgI;IAChI,GAAG,CAAI,KAAuB;QAC5B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAK,CAAC;QAChE,yFAAyF;QACzF,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,KAAK;QACT,iIAAiI;QACjI,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { Tagged } from "type-fest";
2
+ /**
3
+ * A reading of `performance.now()`, in milliseconds since the time origin.
4
+ *
5
+ * The tag keeps other numbers out of a parameter that expects a reading of
6
+ * this clock. Examples are a `Date.now()` time, which uses a different
7
+ * origin, and a duration.
8
+ */
9
+ export type PerformanceNow = Tagged<number, "PerformanceNow">;
10
+ /** Reads `performance.now()`. */
11
+ export declare function performanceNow(): PerformanceNow;
12
+ /** The milliseconds that passed between `start` and now. */
13
+ export declare function msSince(start: PerformanceNow): number;
14
+ //# sourceMappingURL=performance-now.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-now.d.ts","sourceRoot":"","sources":["../src/performance-now.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGxC;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAE9D,iCAAiC;AACjC,wBAAgB,cAAc,IAAI,cAAc,CAE/C;AAED,4DAA4D;AAC5D,wBAAgB,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAErD"}
@@ -0,0 +1,10 @@
1
+ import { instantiateTaggedType } from "type-party/runtime/tagged-types.js";
2
+ /** Reads `performance.now()`. */
3
+ export function performanceNow() {
4
+ return instantiateTaggedType(performance.now());
5
+ }
6
+ /** The milliseconds that passed between `start` and now. */
7
+ export function msSince(start) {
8
+ return performance.now() - start;
9
+ }
10
+ //# sourceMappingURL=performance-now.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-now.js","sourceRoot":"","sources":["../src/performance-now.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAW3E,iCAAiC;AACjC,MAAM,UAAU,cAAc;IAC5B,OAAO,qBAAqB,CAAiB,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,OAAO,CAAC,KAAqB;IAC3C,OAAO,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;AACnC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Reports that a caller broke a contract of this package. Examples are a
3
+ * `dispatch` or `schedule` callback that returns the wrong number of results,
4
+ * and a `schedule` callback that requests a key it is starting a task for.
5
+ */
6
+ export declare class SchedulingContractError extends Error {
7
+ readonly name: string;
8
+ }
9
+ //# sourceMappingURL=scheduling-contract-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduling-contract-error.d.ts","sourceRoot":"","sources":["../src/scheduling-contract-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,EAAE,MAAM,CAA6B;CAC5D"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Reports that a caller broke a contract of this package. Examples are a
3
+ * `dispatch` or `schedule` callback that returns the wrong number of results,
4
+ * and a `schedule` callback that requests a key it is starting a task for.
5
+ */
6
+ export class SchedulingContractError extends Error {
7
+ name = "SchedulingContractError";
8
+ }
9
+ //# sourceMappingURL=scheduling-contract-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduling-contract-error.js","sourceRoot":"","sources":["../src/scheduling-contract-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAC9B,IAAI,GAAW,yBAAyB,CAAC;CAC5D"}
@@ -0,0 +1,10 @@
1
+ export declare const GENERATOR_HINT = "For async work, use a generator callback with `yield* waitFor(...)`.";
2
+ export declare const TRAVERSAL_HINT = "For async work, use a generator callback with `yield* waitFor(...)` in timeSlicedMap or timeSlicedForEach first.";
3
+ /**
4
+ * Returns `value` unchanged, or throws a `TypeError` if it is a thenable.
5
+ *
6
+ * TypeScript cannot reject a promise result without also rejecting generic
7
+ * results, so the synchronous callback rule is checked here at runtime.
8
+ */
9
+ export declare function assertNotThenable<Value>(value: Value, helper: string, hint: string): Value;
10
+ //# sourceMappingURL=synchronous-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synchronous-result.d.ts","sourceRoot":"","sources":["../src/synchronous-result.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,yEAC6C,CAAC;AACzE,eAAO,MAAM,cAAc,qHACyF,CAAC;AAErH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EACrC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,KAAK,CAYP"}
@@ -0,0 +1,18 @@
1
+ export const GENERATOR_HINT = "For async work, use a generator callback with `yield* waitFor(...)`.";
2
+ export const TRAVERSAL_HINT = "For async work, use a generator callback with `yield* waitFor(...)` in timeSlicedMap or timeSlicedForEach first.";
3
+ /**
4
+ * Returns `value` unchanged, or throws a `TypeError` if it is a thenable.
5
+ *
6
+ * TypeScript cannot reject a promise result without also rejecting generic
7
+ * results, so the synchronous callback rule is checked here at runtime.
8
+ */
9
+ export function assertNotThenable(value, helper, hint) {
10
+ if (((typeof value === "object" && value !== null) ||
11
+ typeof value === "function") &&
12
+ "then" in value &&
13
+ typeof value.then === "function") {
14
+ throw new TypeError(`${helper} received a promise or other thenable from a synchronous callback. ${hint}`);
15
+ }
16
+ return value;
17
+ }
18
+ //# sourceMappingURL=synchronous-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synchronous-result.js","sourceRoot":"","sources":["../src/synchronous-result.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GACzB,sEAAsE,CAAC;AACzE,MAAM,CAAC,MAAM,cAAc,GACzB,kHAAkH,CAAC;AAErH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAY,EACZ,MAAc,EACd,IAAY;IAEZ,IACE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;QAC5C,OAAO,KAAK,KAAK,UAAU,CAAC;QAC9B,MAAM,IAAI,KAAK;QACf,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,EAChC,CAAC;QACD,MAAM,IAAI,SAAS,CACjB,GAAG,MAAM,sEAAsE,IAAI,EAAE,CACtF,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { TimeSliceBudget } from "./time-slicing.js";
2
+ /**
3
+ * Returns whether any item matches a synchronous predicate, in input order.
4
+ *
5
+ * Stops at the first match. It does not advance the iterable past that item,
6
+ * and it builds no intermediate array. Measures each predicate call, including
7
+ * calls that throw. One predicate call cannot be interrupted. Throws a
8
+ * `TypeError` if the predicate returns a promise or other thenable.
9
+ * The optional budget defaults to a new independent `TimeSliceBudget`.
10
+ *
11
+ * @example Check for a negative number.
12
+ * const hasNegative = await timeSlicedSome([3, -1, 2], (value) => value < 0);
13
+ *
14
+ * @example Share a budget with other work, and stop early on a lazy source.
15
+ * const budget = new TimeSliceBudget();
16
+ * const found = await timeSlicedSome(map.values(), (entry) => entry.active, budget);
17
+ */
18
+ export declare function timeSlicedSome<Item>(items: Iterable<Item>, predicate: (item: Item, index: number) => boolean, budget?: TimeSliceBudget): Promise<boolean>;
19
+ /**
20
+ * Returns the first item that matches a type-guard predicate, narrowed.
21
+ *
22
+ * @example Find the first string.
23
+ * const text = await timeSlicedFind(
24
+ * [1, "a", 2],
25
+ * (value): value is string => typeof value === "string",
26
+ * );
27
+ */
28
+ export declare function timeSlicedFind<Item, Found extends Item>(items: Iterable<Item>, predicate: (item: Item, index: number) => item is Found, budget?: TimeSliceBudget): Promise<Found | undefined>;
29
+ /**
30
+ * Returns the first item that matches a synchronous predicate, or `undefined`.
31
+ *
32
+ * Stops at the first match. It does not advance the iterable past that item,
33
+ * and it builds no intermediate array. Measures each predicate call, including
34
+ * calls that throw. One predicate call cannot be interrupted. Throws a
35
+ * `TypeError` if the predicate returns a promise or other thenable. As with
36
+ * `Array.prototype.find`, a matching `undefined` item also returns `undefined`.
37
+ * The optional budget defaults to a new independent `TimeSliceBudget`.
38
+ *
39
+ * @example Find the first even number.
40
+ * const even = await timeSlicedFind([1, 4, 6], (value) => value % 2 === 0);
41
+ *
42
+ * @example Use the index and a shared budget.
43
+ * const budget = new TimeSliceBudget();
44
+ * const late = await timeSlicedFind(["a", "b"], (_, index) => index > 0, budget);
45
+ */
46
+ export declare function timeSlicedFind<Item>(items: Iterable<Item>, predicate: (item: Item, index: number) => boolean, budget?: TimeSliceBudget): Promise<Item | undefined>;
47
+ //# sourceMappingURL=time-sliced-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-sliced-search.d.ts","sourceRoot":"","sources":["../src/time-sliced-search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AA0BpD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAAC,IAAI,EACvC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,EACjD,MAAM,kBAAwB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAKlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,KAAK,SAAS,IAAI,EACrD,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,KAAK,EACvD,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;AAC9B;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EACjC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,EACrB,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,EACjD,MAAM,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { TRAVERSAL_HINT, assertNotThenable } from "./synchronous-result.js";
2
+ import { TimeSliceBudget } from "./time-slicing.js";
3
+ async function findFirstMatch(helper, items, predicate, budget) {
4
+ const position = { index: 0 };
5
+ // oxlint-disable-next-line zingage/no-restricted-syntax -- Stop at the first match; native iteration closes the iterator without advancing it.
6
+ for (const item of items) {
7
+ const matched = budget.measure(() => assertNotThenable(predicate(item, position.index), helper, TRAVERSAL_HINT));
8
+ position.index += 1;
9
+ const pending = budget.yieldIfNeeded();
10
+ if (pending !== undefined)
11
+ await pending;
12
+ if (matched)
13
+ return { item };
14
+ }
15
+ return undefined;
16
+ }
17
+ /**
18
+ * Returns whether any item matches a synchronous predicate, in input order.
19
+ *
20
+ * Stops at the first match. It does not advance the iterable past that item,
21
+ * and it builds no intermediate array. Measures each predicate call, including
22
+ * calls that throw. One predicate call cannot be interrupted. Throws a
23
+ * `TypeError` if the predicate returns a promise or other thenable.
24
+ * The optional budget defaults to a new independent `TimeSliceBudget`.
25
+ *
26
+ * @example Check for a negative number.
27
+ * const hasNegative = await timeSlicedSome([3, -1, 2], (value) => value < 0);
28
+ *
29
+ * @example Share a budget with other work, and stop early on a lazy source.
30
+ * const budget = new TimeSliceBudget();
31
+ * const found = await timeSlicedSome(map.values(), (entry) => entry.active, budget);
32
+ */
33
+ export async function timeSlicedSome(items, predicate, budget = new TimeSliceBudget()) {
34
+ return ((await findFirstMatch("timeSlicedSome", items, predicate, budget)) !==
35
+ undefined);
36
+ }
37
+ export async function timeSlicedFind(items, predicate, budget = new TimeSliceBudget()) {
38
+ return (await findFirstMatch("timeSlicedFind", items, predicate, budget))
39
+ ?.item;
40
+ }
41
+ //# sourceMappingURL=time-sliced-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-sliced-search.js","sourceRoot":"","sources":["../src/time-sliced-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,KAAK,UAAU,cAAc,CAC3B,MAAc,EACd,KAAqB,EACrB,SAAiD,EACjD,MAAuB;IAEvB,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAC9B,+IAA+I;IAC/I,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAClC,iBAAiB,CACf,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,EAC/B,MAAM,EACN,cAAc,CACf,CACF,CAAC;QACF,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;QACvC,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,OAAO,CAAC;QACzC,IAAI,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAqB,EACrB,SAAiD,EACjD,MAAM,GAAG,IAAI,eAAe,EAAE;IAE9B,OAAO,CACL,CAAC,MAAM,cAAc,CAAC,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAClE,SAAS,CACV,CAAC;AACJ,CAAC;AAsCD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAqB,EACrB,SAAiD,EACjD,MAAM,GAAG,IAAI,eAAe,EAAE;IAE9B,OAAO,CAAC,MAAM,cAAc,CAAC,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACvE,EAAE,IAAI,CAAC;AACX,CAAC"}
@@ -1,4 +1,3 @@
1
- type Synchronous<Result> = Result extends PromiseLike<unknown> ? never : Result;
2
1
  /**
3
2
  * Tracks measured synchronous work before yielding to the event loop.
4
3
  *
@@ -29,6 +28,8 @@ export declare class TimeSliceBudget {
29
28
  *
30
29
  * Nested measurements on this budget count once. This method does not yield.
31
30
  * Call `yieldIfNeeded` at a safe boundary after handling the result.
31
+ * `work` must be synchronous. If it returns a promise or other thenable, this
32
+ * method throws a `TypeError` after charging the elapsed time.
32
33
  *
33
34
  * @example Measure one segment and then check the budget.
34
35
  * const budget = new TimeSliceBudget();
@@ -36,7 +37,7 @@ export declare class TimeSliceBudget {
36
37
  * const pending = budget.yieldIfNeeded();
37
38
  * if (pending !== undefined) await pending;
38
39
  */
39
- measure<Result>(work: () => Result & Synchronous<Result>): Result;
40
+ measure<Result>(work: () => Result): Result;
40
41
  /**
41
42
  * Returns a yield promise if the allowance is exhausted, or `undefined` otherwise.
42
43
  *
@@ -81,6 +82,9 @@ export declare function waitFor<Value>(promise: PromiseLike<Value>): CallbackGen
81
82
  * finishes before the next item starts. Measures synchronous callback work and
82
83
  * every generator `next()`/`throw()` segment, excluding promise waits.
83
84
  * Iterator advancement is unmeasured. Unhandled failures stop the traversal.
85
+ * A non-generator callback must be synchronous. If it returns a promise or
86
+ * other thenable (an `async` function, for example), the traversal throws a
87
+ * `TypeError` on that first call. The type checker does not catch this.
84
88
  * The optional budget defaults to a new independent `TimeSliceBudget`.
85
89
  *
86
90
  * @example Run a synchronous visitor.
@@ -96,17 +100,21 @@ export declare function timeSlicedForEach<Item, Result>(items: Iterable<Item>, c
96
100
  /**
97
101
  * Runs a synchronous visitor in input order with an optional processing budget.
98
102
  *
103
+ * Throws a `TypeError` if the visitor returns a promise or other thenable.
104
+ *
99
105
  * @example
100
106
  * await timeSlicedForEach([1, 2], (value) => console.log(value));
101
107
  */
102
- export declare function timeSlicedForEach<Item, Result>(items: Iterable<Item>, callback: (item: Item, index: number) => Result & Synchronous<Result>, budget?: TimeSliceBudget): Promise<void>;
108
+ export declare function timeSlicedForEach<Item, Result>(items: Iterable<Item>, callback: (item: Item, index: number) => Result, budget?: TimeSliceBudget): Promise<void>;
103
109
  /**
104
110
  * Returns transformed values in input order using sequential callbacks.
105
111
  *
106
112
  * Accepts synchronous callbacks or generators that yield promises. Each generator
107
113
  * finishes before the next item starts. Measures every synchronous segment,
108
114
  * including `throw()` recovery and result accumulation. Promise waits and iterator
109
- * advancement are unmeasured. Ordinary async callbacks are not supported.
115
+ * advancement are unmeasured. Ordinary async callbacks are not supported: if a
116
+ * non-generator callback returns a promise or other thenable, the traversal
117
+ * throws a `TypeError` on that first call. The type checker does not catch this.
110
118
  * The optional budget defaults to a new independent `TimeSliceBudget`.
111
119
  *
112
120
  * @example Transform synchronous values.
@@ -122,10 +130,12 @@ export declare function timeSlicedMap<Item, Result>(items: Iterable<Item>, callb
122
130
  /**
123
131
  * Maps synchronous values in input order with an optional processing budget.
124
132
  *
133
+ * Throws a `TypeError` if the callback returns a promise or other thenable.
134
+ *
125
135
  * @example
126
136
  * const doubled = await timeSlicedMap([1, 2], (value) => value * 2);
127
137
  */
128
- export declare function timeSlicedMap<Item, Result>(items: Iterable<Item>, callback: (item: Item, index: number) => Result & Synchronous<Result>, budget?: TimeSliceBudget): Promise<Result[]>;
138
+ export declare function timeSlicedMap<Item, Result>(items: Iterable<Item>, callback: (item: Item, index: number) => Result, budget?: TimeSliceBudget): Promise<Result[]>;
129
139
  /**
130
140
  * Maps each item to a synchronous list and flattens the lists in input order.
131
141
  *
@@ -149,7 +159,8 @@ export declare function timeSlicedFlatMap<Item, Result>(items: Iterable<Item>, c
149
159
  * Returns items whose synchronous predicate is true, preserving input order.
150
160
  *
151
161
  * Measures predicate work and result accumulation. One predicate call cannot be
152
- * interrupted. The optional budget defaults to a new independent instance.
162
+ * interrupted. Throws a `TypeError` if the predicate returns a promise or other
163
+ * thenable. The optional budget defaults to a new independent instance.
153
164
  *
154
165
  * @example Keep odd numbers.
155
166
  * const odd = await timeSlicedFilter([1, 2, 3], (value) => value % 2 === 1);
@@ -165,6 +176,8 @@ export declare function timeSlicedFilter<Item>(items: Iterable<Item>, predicate:
165
176
  * Groups items by a synchronous key, preserving key and group insertion order.
166
177
  *
167
178
  * Uses `Map` key equality. Measures key selection and group accumulation.
179
+ * `keyOf` must be synchronous. If it returns a promise or other thenable, the
180
+ * operation throws a `TypeError` before it stores the key.
168
181
  * The optional budget defaults to a new independent `TimeSliceBudget`.
169
182
  *
170
183
  * @example Group strings by length.
@@ -176,7 +189,7 @@ export declare function timeSlicedFilter<Item>(items: Iterable<Item>, predicate:
176
189
  * return yield* waitFor(timeSlicedGroupBy(values, (value) => value % 2, budget));
177
190
  * }, budget);
178
191
  */
179
- export declare function timeSlicedGroupBy<Item, Key>(items: Iterable<Item>, keyOf: (item: Item, index: number) => Key & Synchronous<Key>, budget?: TimeSliceBudget): Promise<Map<Key, Item[]>>;
192
+ export declare function timeSlicedGroupBy<Item, Key>(items: Iterable<Item>, keyOf: (item: Item, index: number) => Key, budget?: TimeSliceBudget): Promise<Map<Key, Item[]>>;
180
193
  /**
181
194
  * Builds a Map from entries in input order; the last value for a repeated key wins.
182
195
  *
@@ -1 +1 @@
1
- {"version":3,"file":"time-slicing.d.ts","sourceRoot":"","sources":["../src/time-slicing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"time-slicing.d.ts","sourceRoot":"","sources":["../src/time-slicing.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { setImmediate } from "node:timers/promises";
3
+ import { GENERATOR_HINT, TRAVERSAL_HINT, assertNotThenable, } from "./synchronous-result.js";
3
4
  const DEFAULT_TIME_SLICE_MS = 4;
4
5
  const performanceNow = performance.now.bind(performance);
5
6
  /**
@@ -42,6 +43,8 @@ export class TimeSliceBudget {
42
43
  *
43
44
  * Nested measurements on this budget count once. This method does not yield.
44
45
  * Call `yieldIfNeeded` at a safe boundary after handling the result.
46
+ * `work` must be synchronous. If it returns a promise or other thenable, this
47
+ * method throws a `TypeError` after charging the elapsed time.
45
48
  *
46
49
  * @example Measure one segment and then check the budget.
47
50
  * const budget = new TimeSliceBudget();
@@ -54,7 +57,7 @@ export class TimeSliceBudget {
54
57
  const startedAt = outermost ? this.#now() : 0;
55
58
  this.#depth += 1;
56
59
  try {
57
- return work();
60
+ return assertNotThenable(work(), "TimeSliceBudget.measure", GENERATOR_HINT);
58
61
  }
59
62
  finally {
60
63
  this.#depth -= 1;
@@ -159,11 +162,11 @@ async function runCallbackGenerator(generator, budget) {
159
162
  }
160
163
  return state.step.value;
161
164
  }
162
- async function traverse(items, callback, accept, budget) {
165
+ async function traverse(helper, items, callback, accept, budget) {
163
166
  const position = { index: 0 };
164
167
  // oxlint-disable-next-line zingage/no-restricted-syntax -- Native iteration owns cleanup while callbacks and budget yields settle sequentially.
165
168
  for (const item of items) {
166
- const value = budget.measure(() => callback(item, position.index));
169
+ const value = budget.measure(() => assertNotThenable(callback(item, position.index), helper, GENERATOR_HINT));
167
170
  const result = isCallbackGenerator(value)
168
171
  ? await runCallbackGenerator(value, budget)
169
172
  : value;
@@ -175,11 +178,11 @@ async function traverse(items, callback, accept, budget) {
175
178
  }
176
179
  }
177
180
  export async function timeSlicedForEach(items, callback, budget = new TimeSliceBudget()) {
178
- await traverse(items, callback, () => { }, budget);
181
+ await traverse("timeSlicedForEach", items, callback, () => { }, budget);
179
182
  }
180
183
  export async function timeSlicedMap(items, callback, budget = new TimeSliceBudget()) {
181
184
  const results = [];
182
- await traverse(items, callback, (result) => {
185
+ await traverse("timeSlicedMap", items, callback, (result) => {
183
186
  // oxlint-disable-next-line zingage/no-restricted-syntax -- Append to the local result to avoid quadratic copying.
184
187
  results.push(result);
185
188
  }, budget);
@@ -227,7 +230,8 @@ export async function timeSlicedFlatMap(items, callback, budget = new TimeSliceB
227
230
  * Returns items whose synchronous predicate is true, preserving input order.
228
231
  *
229
232
  * Measures predicate work and result accumulation. One predicate call cannot be
230
- * interrupted. The optional budget defaults to a new independent instance.
233
+ * interrupted. Throws a `TypeError` if the predicate returns a promise or other
234
+ * thenable. The optional budget defaults to a new independent instance.
231
235
  *
232
236
  * @example Keep odd numbers.
233
237
  * const odd = await timeSlicedFilter([1, 2, 3], (value) => value % 2 === 1);
@@ -241,7 +245,7 @@ export async function timeSlicedFlatMap(items, callback, budget = new TimeSliceB
241
245
  export async function timeSlicedFilter(items, predicate, budget = new TimeSliceBudget()) {
242
246
  const results = [];
243
247
  await timeSlicedForEach(items, (item, index) => {
244
- if (predicate(item, index)) {
248
+ if (assertNotThenable(predicate(item, index), "timeSlicedFilter", TRAVERSAL_HINT)) {
245
249
  // oxlint-disable-next-line zingage/no-restricted-syntax -- Append to the local result without quadratic copying.
246
250
  results.push(item);
247
251
  }
@@ -252,6 +256,8 @@ export async function timeSlicedFilter(items, predicate, budget = new TimeSliceB
252
256
  * Groups items by a synchronous key, preserving key and group insertion order.
253
257
  *
254
258
  * Uses `Map` key equality. Measures key selection and group accumulation.
259
+ * `keyOf` must be synchronous. If it returns a promise or other thenable, the
260
+ * operation throws a `TypeError` before it stores the key.
255
261
  * The optional budget defaults to a new independent `TimeSliceBudget`.
256
262
  *
257
263
  * @example Group strings by length.
@@ -266,7 +272,7 @@ export async function timeSlicedFilter(items, predicate, budget = new TimeSliceB
266
272
  export async function timeSlicedGroupBy(items, keyOf, budget = new TimeSliceBudget()) {
267
273
  const groups = new Map();
268
274
  await timeSlicedForEach(items, (item, index) => {
269
- const key = keyOf(item, index);
275
+ const key = assertNotThenable(keyOf(item, index), "timeSlicedGroupBy", TRAVERSAL_HINT);
270
276
  const group = groups.get(key);
271
277
  if (group === undefined)
272
278
  groups.set(key, [item]);
@@ -1 +1 @@
1
- {"version":3,"file":"time-slicing.js","sourceRoot":"","sources":["../src/time-slicing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"time-slicing.js","sourceRoot":"","sources":["../src/time-slicing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type Logger } from "./logger.js";
2
+ /**
3
+ * Wraps a function that starts a task and returns a promise for its result.
4
+ * The returned function behaves like the original, except that a call reuses
5
+ * the promise of an earlier call if and only if: 1) the calls have the same
6
+ * key, which `makeKey` derives from their arguments [a la memoize]; 2) less
7
+ * than `collapseTasksMs` milliseconds have passed since the earlier call
8
+ * started its task [a la throttle]; and 3) that task is still running
9
+ * [unique]. Otherwise, the call calls through to the original function. So it
10
+ * is sort of a combination of memoize, throttle, and promise chaining.
11
+ *
12
+ * It runs on {@link CollapsedTaskCreator}: each call is one task request,
13
+ * whose input carries the call's arguments and key. See that class for why
14
+ * these semantics are useful.
15
+ *
16
+ * It does not support task cancellation. A call takes no `AbortSignal`, so no
17
+ * individual caller can cancel a task that other callers share. Users who
18
+ * need cancellation should use `CollapsedTaskCreator` directly.
19
+ *
20
+ * @param taskCreator The task creation function
21
+ * @param collapseTasksMs The number of milliseconds up until which, if a caller
22
+ * tries to start the same task while a previous version of the task is still
23
+ * running, the promise for the result of the currently-running task will be
24
+ * returned instead.
25
+ * @param makeKey A function for converting the arguments passed to the task
26
+ * creation into a cache key, like in your standard memoize implementation.
27
+ * @param logger Receives the trace lines that each call writes.
28
+ */
29
+ export declare function wrapWithTaskCollapsing<Args extends unknown[], Key, Result>(taskCreator: (...args: Args) => Promise<Result>, collapseTasksMs: number, makeKey: (args: Args) => Key, logger?: Logger): (...args: Args) => Promise<Result>;
30
+ //# sourceMappingURL=wrap-with-task-collapsing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-with-task-collapsing.d.ts","sourceRoot":"","sources":["../src/wrap-with-task-collapsing.ts"],"names":[],"mappings":"AAIA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAuBrE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,EACxE,WAAW,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,EAC/C,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,GAAG,EAC5B,MAAM,GAAE,MAA4D,aA2B7C,IAAI,qBAiB5B"}
@@ -0,0 +1,80 @@
1
+ import { CollapsedTaskCreator, } from "./collapsed-task-creator.js";
2
+ import { defaultLoggersByComponent } from "./logger.js";
3
+ // The creator reserves `undefined` for inputs that never share work, but here
4
+ // `undefined` is an ordinary key. So it stands in for `undefined` with a
5
+ // key that no caller can produce.
6
+ const undefinedKey = Symbol("undefined key");
7
+ /**
8
+ * The "started" log line for each reason a call starts a task. A call here
9
+ * has no signal, so its task is never cancelled, and its key is never
10
+ * `undefined` for the creator. But every reason has a line, so the log stays
11
+ * accurate if that changes.
12
+ */
13
+ const startedMessages = {
14
+ noPendingTask: "started new task b/c there was no in-progress task for these args",
15
+ pendingTaskTooOld: "started new task; there _was_ an in-progress one, but it's too old",
16
+ pendingTaskCancelled: "started new task; there _was_ an in-progress one, but it was cancelled",
17
+ noKey: "started new task b/c these args have no key",
18
+ };
19
+ /**
20
+ * Wraps a function that starts a task and returns a promise for its result.
21
+ * The returned function behaves like the original, except that a call reuses
22
+ * the promise of an earlier call if and only if: 1) the calls have the same
23
+ * key, which `makeKey` derives from their arguments [a la memoize]; 2) less
24
+ * than `collapseTasksMs` milliseconds have passed since the earlier call
25
+ * started its task [a la throttle]; and 3) that task is still running
26
+ * [unique]. Otherwise, the call calls through to the original function. So it
27
+ * is sort of a combination of memoize, throttle, and promise chaining.
28
+ *
29
+ * It runs on {@link CollapsedTaskCreator}: each call is one task request,
30
+ * whose input carries the call's arguments and key. See that class for why
31
+ * these semantics are useful.
32
+ *
33
+ * It does not support task cancellation. A call takes no `AbortSignal`, so no
34
+ * individual caller can cancel a task that other callers share. Users who
35
+ * need cancellation should use `CollapsedTaskCreator` directly.
36
+ *
37
+ * @param taskCreator The task creation function
38
+ * @param collapseTasksMs The number of milliseconds up until which, if a caller
39
+ * tries to start the same task while a previous version of the task is still
40
+ * running, the promise for the result of the currently-running task will be
41
+ * returned instead.
42
+ * @param makeKey A function for converting the arguments passed to the task
43
+ * creation into a cache key, like in your standard memoize implementation.
44
+ * @param logger Receives the trace lines that each call writes.
45
+ */
46
+ export function wrapWithTaskCollapsing(taskCreator, collapseTasksMs, makeKey, logger = defaultLoggersByComponent["collapsed-task-creator"]) {
47
+ const logTrace = logger.bind(null, "collapsed-task-creator", "trace");
48
+ // The creator's input carries the key, so `makeKey` runs once per call and
49
+ // every log line below can include the key.
50
+ const creator = new CollapsedTaskCreator({
51
+ collapseTasksMs,
52
+ makeKey: ({ taskKey }) => taskKey === undefined ? undefinedKey : taskKey,
53
+ schedule: (toStart) => toStart.map(({ input: { args, taskKey }, startReason }) => {
54
+ logTrace(startedMessages[startReason], args);
55
+ const taskRes = taskCreator(...args);
56
+ logTrace("pending = new state for taskKey/args", { args, taskKey });
57
+ return {
58
+ result: taskRes.finally(() => {
59
+ logTrace("completed = new state for taskKey/args", {
60
+ args,
61
+ taskKey,
62
+ });
63
+ }),
64
+ handle: undefined,
65
+ };
66
+ }),
67
+ });
68
+ return async (...args) => {
69
+ const taskKey = makeKey(args);
70
+ logTrace("requested = new state for taskKey/args", { args, taskKey });
71
+ const [{ result, rode }] = creator.startOrRideTasks([
72
+ { input: { args, taskKey } },
73
+ ]);
74
+ if (rode) {
75
+ logTrace("reusing result from prior, still-in-progress run of task for args/taskKey", { args, taskKey });
76
+ }
77
+ return result;
78
+ };
79
+ }
80
+ //# sourceMappingURL=wrap-with-task-collapsing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-with-task-collapsing.js","sourceRoot":"","sources":["../src/wrap-with-task-collapsing.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,GAErB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,yBAAyB,EAAe,MAAM,aAAa,CAAC;AAErE,8EAA8E;AAC9E,yEAAyE;AACzE,kCAAkC;AAClC,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,eAAe,GAAoC;IACvD,aAAa,EACX,mEAAmE;IACrE,iBAAiB,EACf,oEAAoE;IACtE,oBAAoB,EAClB,wEAAwE;IAC1E,KAAK,EAAE,6CAA6C;CACrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAA+C,EAC/C,eAAuB,EACvB,OAA4B,EAC5B,MAAM,GAAW,yBAAyB,CAAC,wBAAwB,CAAC;IAEpE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,wBAAwB,EAAE,OAAO,CAAC,CAAC;IAEtE,2EAA2E;IAC3E,4CAA4C;IAC5C,MAAM,OAAO,GAAG,IAAI,oBAAoB,CAAC;QACvC,eAAe;QACf,OAAO,EAAE,CAAC,EAAE,OAAO,EAAgC,EAAE,EAAE,CACrD,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO;QAChD,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CACpB,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;YACxD,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;YAC7C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC;YACrC,QAAQ,CAAC,sCAAsC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACpE,OAAO;gBACL,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE;oBAC3B,QAAQ,CAAC,wCAAwC,EAAE;wBACjD,IAAI;wBACJ,OAAO;qBACR,CAAC,CAAC;gBACL,CAAC,CAAC;gBACF,MAAM,EAAE,SAAS;aAClB,CAAC;QACJ,CAAC,CAAC;KACL,CAAC,CAAC;IAEH,OAAO,KAAK,EAAE,GAAG,IAAU,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,QAAQ,CAAC,wCAAwC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAEtE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAClD,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;SAC7B,CAAC,CAAC;QAEH,IAAI,IAAI,EAAE,CAAC;YACT,QAAQ,CACN,2EAA2E,EAC3E,EAAE,IAAI,EAAE,OAAO,EAAE,CAClB,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}