reactor-core-ts 3.2.2 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +5 -0
  2. package/dist/core/demand.d.ts +4 -0
  3. package/dist/core/demand.d.ts.map +1 -1
  4. package/dist/core/demand.js +12 -4
  5. package/dist/core/demand.js.map +1 -1
  6. package/dist/internal/deep-value.d.ts +9 -0
  7. package/dist/internal/deep-value.d.ts.map +1 -0
  8. package/dist/internal/deep-value.js +159 -0
  9. package/dist/internal/deep-value.js.map +1 -0
  10. package/dist/internal/iterable-transform.d.ts +8 -1
  11. package/dist/internal/iterable-transform.d.ts.map +1 -1
  12. package/dist/internal/iterable-transform.js +7 -5
  13. package/dist/internal/iterable-transform.js.map +1 -1
  14. package/dist/internal/iteration-demand.d.ts +18 -0
  15. package/dist/internal/iteration-demand.d.ts.map +1 -0
  16. package/dist/internal/iteration-demand.js +34 -0
  17. package/dist/internal/iteration-demand.js.map +1 -0
  18. package/dist/internal/publisher-terminal.d.ts +25 -0
  19. package/dist/internal/publisher-terminal.d.ts.map +1 -0
  20. package/dist/internal/publisher-terminal.js +128 -0
  21. package/dist/internal/publisher-terminal.js.map +1 -0
  22. package/dist/publisher/flux.d.ts.map +1 -1
  23. package/dist/publisher/flux.js +22 -12
  24. package/dist/publisher/flux.js.map +1 -1
  25. package/dist/publisher/mono.d.ts.map +1 -1
  26. package/dist/publisher/mono.js +2 -1
  27. package/dist/publisher/mono.js.map +1 -1
  28. package/dist/publisher/operators/aggregate.d.ts.map +1 -1
  29. package/dist/publisher/operators/aggregate.js +136 -143
  30. package/dist/publisher/operators/aggregate.js.map +1 -1
  31. package/dist/publisher/operators/buffer-lift.d.ts +5 -0
  32. package/dist/publisher/operators/buffer-lift.d.ts.map +1 -0
  33. package/dist/publisher/operators/buffer-lift.js +197 -0
  34. package/dist/publisher/operators/buffer-lift.js.map +1 -0
  35. package/dist/publisher/operators/compat/flux.d.ts.map +1 -1
  36. package/dist/publisher/operators/compat/flux.js +86 -35
  37. package/dist/publisher/operators/compat/flux.js.map +1 -1
  38. package/dist/publisher/operators/coordination.d.ts.map +1 -1
  39. package/dist/publisher/operators/coordination.js +3 -4
  40. package/dist/publisher/operators/coordination.js.map +1 -1
  41. package/dist/publisher/operators/lifecycle.d.ts.map +1 -1
  42. package/dist/publisher/operators/lifecycle.js +64 -21
  43. package/dist/publisher/operators/lifecycle.js.map +1 -1
  44. package/dist/publisher/operators/lift.d.ts +2 -0
  45. package/dist/publisher/operators/lift.d.ts.map +1 -1
  46. package/dist/publisher/operators/lift.js +173 -3
  47. package/dist/publisher/operators/lift.js.map +1 -1
  48. package/dist/publisher/operators/selection.d.ts +5 -0
  49. package/dist/publisher/operators/selection.d.ts.map +1 -1
  50. package/dist/publisher/operators/selection.js +11 -2
  51. package/dist/publisher/operators/selection.js.map +1 -1
  52. package/dist/publisher/operators/terminal-mono.d.ts +12 -0
  53. package/dist/publisher/operators/terminal-mono.d.ts.map +1 -0
  54. package/dist/publisher/operators/terminal-mono.js +244 -0
  55. package/dist/publisher/operators/terminal-mono.js.map +1 -0
  56. package/dist/publisher/operators/terminal.d.ts.map +1 -1
  57. package/dist/publisher/operators/terminal.js +12 -25
  58. package/dist/publisher/operators/terminal.js.map +1 -1
  59. package/dist/publisher/operators/time.d.ts.map +1 -1
  60. package/dist/publisher/operators/time.js +2 -0
  61. package/dist/publisher/operators/time.js.map +1 -1
  62. package/dist/subscription/iterable-subscription.d.ts.map +1 -1
  63. package/dist/subscription/iterable-subscription.js +5 -2
  64. package/dist/subscription/iterable-subscription.js.map +1 -1
  65. package/package.json +1 -1
  66. package/dist/internal/iterable-terminal.d.ts +0 -12
  67. package/dist/internal/iterable-terminal.d.ts.map +0 -1
  68. package/dist/internal/iterable-terminal.js +0 -49
  69. package/dist/internal/iterable-terminal.js.map +0 -1
package/README.md CHANGED
@@ -442,6 +442,7 @@ Every row below includes a minimal example.
442
442
  | `skipUntilOther` | Drop values until another publisher signals. | `Flux.interval(100).skipUntilOther(Mono.delay(300))` |
443
443
  | `distinct` | Keep the first value for each key. | `Flux.just(1, 1, 2).distinct()` |
444
444
  | `distinctUntilChanged` | Drop only adjacent duplicates. | `Flux.just(1, 1, 2, 1).distinctUntilChanged()` |
445
+ | `distinctUntilChangedDeep` | Drop adjacent values with equal nested state. | `users.distinctUntilChangedDeep()` |
445
446
  | `elementAt` | Pick a value by index. | `Flux.just("a", "b").elementAt(1)` |
446
447
  | `defaultIfEmpty` | Emit a fallback value if empty. | `Flux.empty<number>().defaultIfEmpty(0)` |
447
448
  | `switchIfEmpty` | Switch to another source if empty. | `Flux.empty<number>().switchIfEmpty(Flux.just(1))` |
@@ -452,6 +453,10 @@ Every row below includes a minimal example.
452
453
  | `transformDeferredContextual` | Transform per subscription with `Context`. | `Flux.just(1).transformDeferredContextual((f, ctx) => f.map(v => [v, ctx.get("id")]))` |
453
454
  | `hide` | Hide implementation identity. | `Flux.just(1).hide()` |
454
455
 
456
+ `distinctUntilChangedDeep` snapshots arrays, enumerable properties of ordinary
457
+ objects, and local `Date`, `RegExp`, `Map` and `Set` values. Other object types
458
+ keep identity-comparison semantics.
459
+
455
460
  ### Flux Flattening And Combining Methods
456
461
 
457
462
  | Method | What it does and why | Example |
@@ -2,8 +2,12 @@
2
2
  * @packageDocumentation
3
3
  * Reactive Streams core contracts and disposable helpers.
4
4
  */
5
+ /** Demand sentinel used when a subscriber can consume the whole source without batching. */
6
+ export declare const UNBOUNDED_DEMAND: number;
5
7
  /** Validates and normalizes a Reactive Streams request amount. */
6
8
  export declare function normalizeRequest(n: number): number;
7
9
  /** Adds demand values with saturation at positive infinity. */
8
10
  export declare function addCap(a: number, b: number): number;
11
+ /** Multiplies demand values with saturation at positive infinity. */
12
+ export declare function multiplyCap(a: number, b: number): number;
9
13
  //# sourceMappingURL=demand.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"demand.d.ts","sourceRoot":"","sources":["../../src/core/demand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnD"}
1
+ {"version":3,"file":"demand.d.ts","sourceRoot":"","sources":["../../src/core/demand.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,4FAA4F;AAC5F,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAMxD"}
@@ -3,19 +3,27 @@
3
3
  * @packageDocumentation
4
4
  * Reactive Streams core contracts and disposable helpers.
5
5
  */
6
+ /** Demand sentinel used when a subscriber can consume the whole source without batching. */
7
+ var UNBOUNDED_DEMAND = Number.POSITIVE_INFINITY;
6
8
  /** Validates and normalizes a Reactive Streams request amount. */
7
9
  function normalizeRequest(n) {
8
- if (n === Number.POSITIVE_INFINITY) return Number.POSITIVE_INFINITY;
10
+ if (n === UNBOUNDED_DEMAND) return UNBOUNDED_DEMAND;
9
11
  if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) throw new RangeError("request amount must be a strictly positive integer");
10
12
  return n;
11
13
  }
12
14
  /** Adds demand values with saturation at positive infinity. */
13
15
  function addCap(a, b) {
14
- if (a === Number.POSITIVE_INFINITY || b === Number.POSITIVE_INFINITY) return Number.POSITIVE_INFINITY;
16
+ if (a === UNBOUNDED_DEMAND || b === UNBOUNDED_DEMAND) return UNBOUNDED_DEMAND;
15
17
  const next = a + b;
16
- return next >= Number.MAX_SAFE_INTEGER ? Number.POSITIVE_INFINITY : next;
18
+ return next >= Number.MAX_SAFE_INTEGER ? UNBOUNDED_DEMAND : next;
19
+ }
20
+ /** Multiplies demand values with saturation at positive infinity. */
21
+ function multiplyCap(a, b) {
22
+ if (a === UNBOUNDED_DEMAND || b === UNBOUNDED_DEMAND) return UNBOUNDED_DEMAND;
23
+ const next = a * b;
24
+ return next >= Number.MAX_SAFE_INTEGER ? UNBOUNDED_DEMAND : next;
17
25
  }
18
26
  //#endregion
19
- export { addCap, normalizeRequest };
27
+ export { UNBOUNDED_DEMAND, addCap, multiplyCap, normalizeRequest };
20
28
 
21
29
  //# sourceMappingURL=demand.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"demand.js","names":[],"sources":["../../src/core/demand.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Reactive Streams core contracts and disposable helpers.\n */\n/** Validates and normalizes a Reactive Streams request amount. */\nexport function normalizeRequest(n: number): number {\n if (n === Number.POSITIVE_INFINITY) {\n return Number.POSITIVE_INFINITY;\n }\n if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n throw new RangeError(\"request amount must be a strictly positive integer\");\n }\n return n;\n}\n\n/** Adds demand values with saturation at positive infinity. */\nexport function addCap(a: number, b: number): number {\n if (a === Number.POSITIVE_INFINITY || b === Number.POSITIVE_INFINITY) {\n return Number.POSITIVE_INFINITY;\n }\n const next = a + b;\n return next >= Number.MAX_SAFE_INTEGER ? Number.POSITIVE_INFINITY : next;\n}\n"],"mappings":";;;;;;AAKA,SAAgB,iBAAiB,GAAmB;CAChD,IAAI,MAAM,OAAO,mBACb,OAAO,OAAO;CAElB,IAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,KAAK,KAAK,GACpD,MAAM,IAAI,WAAW,oDAAoD;CAE7E,OAAO;AACX;;AAGA,SAAgB,OAAO,GAAW,GAAmB;CACjD,IAAI,MAAM,OAAO,qBAAqB,MAAM,OAAO,mBAC/C,OAAO,OAAO;CAElB,MAAM,OAAO,IAAI;CACjB,OAAO,QAAQ,OAAO,mBAAmB,OAAO,oBAAoB;AACxE"}
1
+ {"version":3,"file":"demand.js","names":[],"sources":["../../src/core/demand.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Reactive Streams core contracts and disposable helpers.\n */\n/** Demand sentinel used when a subscriber can consume the whole source without batching. */\nexport const UNBOUNDED_DEMAND = Number.POSITIVE_INFINITY;\n\n/** Validates and normalizes a Reactive Streams request amount. */\nexport function normalizeRequest(n: number): number {\n if (n === UNBOUNDED_DEMAND) {\n return UNBOUNDED_DEMAND;\n }\n if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n throw new RangeError(\"request amount must be a strictly positive integer\");\n }\n return n;\n}\n\n/** Adds demand values with saturation at positive infinity. */\nexport function addCap(a: number, b: number): number {\n if (a === UNBOUNDED_DEMAND || b === UNBOUNDED_DEMAND) {\n return UNBOUNDED_DEMAND;\n }\n const next = a + b;\n return next >= Number.MAX_SAFE_INTEGER ? UNBOUNDED_DEMAND : next;\n}\n\n/** Multiplies demand values with saturation at positive infinity. */\nexport function multiplyCap(a: number, b: number): number {\n if (a === UNBOUNDED_DEMAND || b === UNBOUNDED_DEMAND) {\n return UNBOUNDED_DEMAND;\n }\n const next = a * b;\n return next >= Number.MAX_SAFE_INTEGER ? UNBOUNDED_DEMAND : next;\n}\n"],"mappings":";;;;;;AAKA,IAAa,mBAAmB,OAAO;;AAGvC,SAAgB,iBAAiB,GAAmB;CAChD,IAAI,MAAM,kBACN,OAAO;CAEX,IAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,KAAK,KAAK,GACpD,MAAM,IAAI,WAAW,oDAAoD;CAE7E,OAAO;AACX;;AAGA,SAAgB,OAAO,GAAW,GAAmB;CACjD,IAAI,MAAM,oBAAoB,MAAM,kBAChC,OAAO;CAEX,MAAM,OAAO,IAAI;CACjB,OAAO,QAAQ,OAAO,mBAAmB,mBAAmB;AAChE;;AAGA,SAAgB,YAAY,GAAW,GAAmB;CACtD,IAAI,MAAM,oBAAoB,MAAM,kBAChC,OAAO;CAEX,MAAM,OAAO,IAAI;CACjB,OAAO,QAAQ,OAAO,mBAAmB,mBAAmB;AAChE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Internal helpers for snapshotting and comparing nested JavaScript values.
4
+ */
5
+ /** Creates a detached snapshot of nested enumerable state and supported mutable value types. */
6
+ export declare function snapshotDeep(value: unknown): unknown;
7
+ /** Compares nested enumerable state, supported mutable values, cycles and shared references. */
8
+ export declare function deepEqual(left: unknown, right: unknown): boolean;
9
+ //# sourceMappingURL=deep-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-value.d.ts","sourceRoot":"","sources":["../../src/internal/deep-value.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAkEpD;AAED,gGAAgG;AAChG,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAyEhE"}
@@ -0,0 +1,159 @@
1
+ //#region src/internal/deep-value.ts
2
+ /** Retains reliable kind metadata for snapshots whose prototypes may contain stateful getters. */
3
+ var SNAPSHOT_KINDS = /* @__PURE__ */ new WeakMap();
4
+ /** Creates a detached snapshot of nested enumerable state and supported mutable value types. */
5
+ function snapshotDeep(value) {
6
+ const snapshots = /* @__PURE__ */ new Map();
7
+ function snapshotValue(current) {
8
+ if (!isObject(current) || typeof current === "function") return current;
9
+ if (snapshots.has(current)) return snapshots.get(current);
10
+ const kind = valueKind(current);
11
+ let snapshot;
12
+ switch (kind) {
13
+ case "array":
14
+ snapshot = new Array(current.length);
15
+ break;
16
+ case "date":
17
+ snapshot = new Date(current.getTime());
18
+ break;
19
+ case "regexp": {
20
+ const source = current;
21
+ const regexp = new RegExp(source.source, source.flags);
22
+ regexp.lastIndex = source.lastIndex;
23
+ snapshot = regexp;
24
+ break;
25
+ }
26
+ case "map":
27
+ snapshot = /* @__PURE__ */ new Map();
28
+ break;
29
+ case "set":
30
+ snapshot = /* @__PURE__ */ new Set();
31
+ break;
32
+ case "record":
33
+ snapshot = Object.create(Object.getPrototypeOf(current));
34
+ break;
35
+ case "opaque": return current;
36
+ }
37
+ if (kind === "array") Object.setPrototypeOf(snapshot, Object.getPrototypeOf(current));
38
+ SNAPSHOT_KINDS.set(snapshot, kind);
39
+ snapshots.set(current, snapshot);
40
+ if (kind === "map") {
41
+ const source = current;
42
+ const target = snapshot;
43
+ for (const [key, entryValue] of source) target.set(snapshotValue(key), snapshotValue(entryValue));
44
+ } else if (kind === "set") {
45
+ const source = current;
46
+ const target = snapshot;
47
+ for (const entryValue of source) target.add(snapshotValue(entryValue));
48
+ }
49
+ copyEnumerableState(current, snapshot, snapshotValue);
50
+ return snapshot;
51
+ }
52
+ return snapshotValue(value);
53
+ }
54
+ /** Compares nested enumerable state, supported mutable values, cycles and shared references. */
55
+ function deepEqual(left, right) {
56
+ const leftToRight = /* @__PURE__ */ new Map();
57
+ const rightToLeft = /* @__PURE__ */ new Map();
58
+ function equal(leftValue, rightValue) {
59
+ if (Object.is(leftValue, rightValue)) {
60
+ if (isObject(leftValue)) {
61
+ if (leftToRight.has(leftValue) || rightToLeft.has(leftValue)) return leftToRight.get(leftValue) === leftValue && rightToLeft.get(leftValue) === leftValue;
62
+ leftToRight.set(leftValue, leftValue);
63
+ rightToLeft.set(leftValue, leftValue);
64
+ }
65
+ return true;
66
+ }
67
+ if (!isObject(leftValue) || !isObject(rightValue)) return false;
68
+ if (typeof leftValue === "function" || typeof rightValue === "function") return false;
69
+ if (Object.getPrototypeOf(leftValue) !== Object.getPrototypeOf(rightValue)) return false;
70
+ const kind = valueKind(leftValue);
71
+ if (kind === "opaque" || kind !== valueKind(rightValue)) return false;
72
+ if (leftToRight.has(leftValue) || rightToLeft.has(rightValue)) return leftToRight.get(leftValue) === rightValue && rightToLeft.get(rightValue) === leftValue;
73
+ leftToRight.set(leftValue, rightValue);
74
+ rightToLeft.set(rightValue, leftValue);
75
+ switch (kind) {
76
+ case "array":
77
+ if (leftValue.length !== rightValue.length) return false;
78
+ break;
79
+ case "date":
80
+ if (!Object.is(leftValue.getTime(), rightValue.getTime())) return false;
81
+ break;
82
+ case "regexp": {
83
+ const leftRegExp = leftValue;
84
+ const rightRegExp = rightValue;
85
+ if (leftRegExp.source !== rightRegExp.source || leftRegExp.flags !== rightRegExp.flags || leftRegExp.lastIndex !== rightRegExp.lastIndex) return false;
86
+ break;
87
+ }
88
+ case "map":
89
+ if (!equalMap(leftValue, rightValue, equal)) return false;
90
+ break;
91
+ case "set":
92
+ if (!equalSet(leftValue, rightValue, equal)) return false;
93
+ break;
94
+ case "record": break;
95
+ }
96
+ return equalEnumerableState(leftValue, rightValue, equal);
97
+ }
98
+ return equal(left, right);
99
+ }
100
+ /** Returns true for non-null object and function values. */
101
+ function isObject(value) {
102
+ return typeof value === "object" && value !== null || typeof value === "function";
103
+ }
104
+ /** Classifies values with observable state supported by the deep snapshot. */
105
+ function valueKind(value) {
106
+ const snapshotKind = SNAPSHOT_KINDS.get(value);
107
+ if (snapshotKind) return snapshotKind;
108
+ if (Array.isArray(value)) return "array";
109
+ const prototype = Object.getPrototypeOf(value);
110
+ if (value instanceof Date && prototype === Date.prototype) return "date";
111
+ if (value instanceof RegExp && prototype === RegExp.prototype) return "regexp";
112
+ if (value instanceof Map && prototype === Map.prototype) return "map";
113
+ if (value instanceof Set && prototype === Set.prototype) return "set";
114
+ return Object.prototype.toString.call(value) === "[object Object]" ? "record" : "opaque";
115
+ }
116
+ /** Copies enumerable own properties without retaining nested object references. */
117
+ function copyEnumerableState(source, target, snapshot) {
118
+ for (const key of enumerableKeys(source)) if (!Object.prototype.hasOwnProperty.call(target, key)) Object.defineProperty(target, key, {
119
+ configurable: true,
120
+ enumerable: true,
121
+ value: snapshot(Reflect.get(source, key)),
122
+ writable: true
123
+ });
124
+ }
125
+ /** Compares enumerable own properties in linear time. */
126
+ function equalEnumerableState(left, right, equal) {
127
+ const leftKeys = enumerableKeys(left);
128
+ if (leftKeys.length !== enumerableKeys(right).length) return false;
129
+ for (const key of leftKeys) if (!Object.prototype.propertyIsEnumerable.call(right, key) || !equal(Reflect.get(left, key), Reflect.get(right, key))) return false;
130
+ return true;
131
+ }
132
+ /** Lists enumerable string and symbol properties owned by a value. */
133
+ function enumerableKeys(value) {
134
+ return Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));
135
+ }
136
+ /** Compares Maps in their observable iteration order. */
137
+ function equalMap(left, right, equal) {
138
+ if (left.size !== right.size) return false;
139
+ const rightEntries = right.entries();
140
+ for (const [leftKey, leftValue] of left) {
141
+ const rightEntry = rightEntries.next();
142
+ if (rightEntry.done || !equal(leftKey, rightEntry.value[0]) || !equal(leftValue, rightEntry.value[1])) return false;
143
+ }
144
+ return true;
145
+ }
146
+ /** Compares Sets in their observable iteration order. */
147
+ function equalSet(left, right, equal) {
148
+ if (left.size !== right.size) return false;
149
+ const rightValues = right.values();
150
+ for (const leftValue of left) {
151
+ const rightValue = rightValues.next();
152
+ if (rightValue.done || !equal(leftValue, rightValue.value)) return false;
153
+ }
154
+ return true;
155
+ }
156
+ //#endregion
157
+ export { deepEqual, snapshotDeep };
158
+
159
+ //# sourceMappingURL=deep-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-value.js","names":[],"sources":["../../src/internal/deep-value.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Internal helpers for snapshotting and comparing nested JavaScript values.\n */\n\n/** Value categories whose mutable state can be captured without retaining the source object. */\ntype DeepValueKind = \"array\" | \"date\" | \"regexp\" | \"map\" | \"set\" | \"record\" | \"opaque\";\n\n/** Retains reliable kind metadata for snapshots whose prototypes may contain stateful getters. */\nconst SNAPSHOT_KINDS = new WeakMap<object, DeepValueKind>();\n\n/** Creates a detached snapshot of nested enumerable state and supported mutable value types. */\nexport function snapshotDeep(value: unknown): unknown {\n const snapshots = new Map<object, unknown>();\n\n function snapshotValue(current: unknown): unknown {\n if (!isObject(current) || typeof current === \"function\") {\n return current;\n }\n\n if (snapshots.has(current)) {\n return snapshots.get(current);\n }\n\n const kind = valueKind(current);\n let snapshot: object;\n switch (kind) {\n case \"array\":\n snapshot = new Array((current as unknown[]).length);\n break;\n case \"date\":\n snapshot = new Date((current as unknown as Date).getTime());\n break;\n case \"regexp\": {\n const source = current as unknown as RegExp;\n const regexp = new RegExp(source.source, source.flags);\n regexp.lastIndex = source.lastIndex;\n snapshot = regexp;\n break;\n }\n case \"map\":\n snapshot = new Map();\n break;\n case \"set\":\n snapshot = new Set();\n break;\n case \"record\":\n snapshot = Object.create(Object.getPrototypeOf(current)) as object;\n break;\n case \"opaque\":\n return current;\n }\n\n if (kind === \"array\") {\n Object.setPrototypeOf(snapshot, Object.getPrototypeOf(current));\n }\n SNAPSHOT_KINDS.set(snapshot, kind);\n snapshots.set(current, snapshot);\n\n if (kind === \"map\") {\n const source = current as unknown as Map<unknown, unknown>;\n const target = snapshot as Map<unknown, unknown>;\n for (const [key, entryValue] of source) {\n target.set(snapshotValue(key), snapshotValue(entryValue));\n }\n } else if (kind === \"set\") {\n const source = current as unknown as Set<unknown>;\n const target = snapshot as Set<unknown>;\n for (const entryValue of source) {\n target.add(snapshotValue(entryValue));\n }\n }\n\n copyEnumerableState(current, snapshot, snapshotValue);\n return snapshot;\n }\n\n return snapshotValue(value);\n}\n\n/** Compares nested enumerable state, supported mutable values, cycles and shared references. */\nexport function deepEqual(left: unknown, right: unknown): boolean {\n const leftToRight = new Map<object, object>();\n const rightToLeft = new Map<object, object>();\n\n function equal(leftValue: unknown, rightValue: unknown): boolean {\n if (Object.is(leftValue, rightValue)) {\n if (isObject(leftValue)) {\n if (leftToRight.has(leftValue) || rightToLeft.has(leftValue)) {\n return leftToRight.get(leftValue) === leftValue && rightToLeft.get(leftValue) === leftValue;\n }\n leftToRight.set(leftValue, leftValue);\n rightToLeft.set(leftValue, leftValue);\n }\n return true;\n }\n if (!isObject(leftValue) || !isObject(rightValue)) {\n return false;\n }\n if (typeof leftValue === \"function\" || typeof rightValue === \"function\") {\n return false;\n }\n if (Object.getPrototypeOf(leftValue) !== Object.getPrototypeOf(rightValue)) {\n return false;\n }\n\n const kind = valueKind(leftValue);\n if (kind === \"opaque\" || kind !== valueKind(rightValue)) {\n return false;\n }\n if (leftToRight.has(leftValue) || rightToLeft.has(rightValue)) {\n return leftToRight.get(leftValue) === rightValue && rightToLeft.get(rightValue) === leftValue;\n }\n leftToRight.set(leftValue, rightValue);\n rightToLeft.set(rightValue, leftValue);\n\n switch (kind) {\n case \"array\":\n if ((leftValue as unknown[]).length !== (rightValue as unknown[]).length) {\n return false;\n }\n break;\n case \"date\":\n if (!Object.is((leftValue as Date).getTime(), (rightValue as Date).getTime())) {\n return false;\n }\n break;\n case \"regexp\": {\n const leftRegExp = leftValue as RegExp;\n const rightRegExp = rightValue as RegExp;\n if (leftRegExp.source !== rightRegExp.source\n || leftRegExp.flags !== rightRegExp.flags\n || leftRegExp.lastIndex !== rightRegExp.lastIndex) {\n return false;\n }\n break;\n }\n case \"map\":\n if (!equalMap(leftValue as Map<unknown, unknown>, rightValue as Map<unknown, unknown>, equal)) {\n return false;\n }\n break;\n case \"set\":\n if (!equalSet(leftValue as Set<unknown>, rightValue as Set<unknown>, equal)) {\n return false;\n }\n break;\n case \"record\":\n break;\n }\n return equalEnumerableState(leftValue, rightValue, equal);\n }\n\n return equal(left, right);\n}\n\n/** Returns true for non-null object and function values. */\nfunction isObject(value: unknown): value is object {\n return (typeof value === \"object\" && value !== null) || typeof value === \"function\";\n}\n\n/** Classifies values with observable state supported by the deep snapshot. */\nfunction valueKind(value: object): DeepValueKind {\n const snapshotKind = SNAPSHOT_KINDS.get(value);\n if (snapshotKind) {\n return snapshotKind;\n }\n if (Array.isArray(value)) {\n return \"array\";\n }\n const prototype = Object.getPrototypeOf(value);\n if (value instanceof Date && prototype === Date.prototype) {\n return \"date\";\n }\n if (value instanceof RegExp && prototype === RegExp.prototype) {\n return \"regexp\";\n }\n if (value instanceof Map && prototype === Map.prototype) {\n return \"map\";\n }\n if (value instanceof Set && prototype === Set.prototype) {\n return \"set\";\n }\n return Object.prototype.toString.call(value) === \"[object Object]\" ? \"record\" : \"opaque\";\n}\n\n/** Copies enumerable own properties without retaining nested object references. */\nfunction copyEnumerableState(source: object, target: object, snapshot: (value: unknown) => unknown): void {\n for (const key of enumerableKeys(source)) {\n if (!Object.prototype.hasOwnProperty.call(target, key)) {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: true,\n value: snapshot(Reflect.get(source, key)),\n writable: true\n });\n }\n }\n}\n\n/** Compares enumerable own properties in linear time. */\nfunction equalEnumerableState(\n left: object,\n right: object,\n equal: (left: unknown, right: unknown) => boolean\n): boolean {\n const leftKeys = enumerableKeys(left);\n if (leftKeys.length !== enumerableKeys(right).length) {\n return false;\n }\n for (const key of leftKeys) {\n if (!Object.prototype.propertyIsEnumerable.call(right, key)\n || !equal(Reflect.get(left, key), Reflect.get(right, key))) {\n return false;\n }\n }\n return true;\n}\n\n/** Lists enumerable string and symbol properties owned by a value. */\nfunction enumerableKeys(value: object): PropertyKey[] {\n return Reflect.ownKeys(value).filter(key => Object.prototype.propertyIsEnumerable.call(value, key));\n}\n\n/** Compares Maps in their observable iteration order. */\nfunction equalMap(\n left: Map<unknown, unknown>,\n right: Map<unknown, unknown>,\n equal: (left: unknown, right: unknown) => boolean\n): boolean {\n if (left.size !== right.size) {\n return false;\n }\n const rightEntries = right.entries();\n for (const [leftKey, leftValue] of left) {\n const rightEntry = rightEntries.next();\n if (rightEntry.done || !equal(leftKey, rightEntry.value[0]) || !equal(leftValue, rightEntry.value[1])) {\n return false;\n }\n }\n return true;\n}\n\n/** Compares Sets in their observable iteration order. */\nfunction equalSet(\n left: Set<unknown>,\n right: Set<unknown>,\n equal: (left: unknown, right: unknown) => boolean\n): boolean {\n if (left.size !== right.size) {\n return false;\n }\n const rightValues = right.values();\n for (const leftValue of left) {\n const rightValue = rightValues.next();\n if (rightValue.done || !equal(leftValue, rightValue.value)) {\n return false;\n }\n }\n return true;\n}\n"],"mappings":"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"}
@@ -3,6 +3,13 @@
3
3
  * Internal iterable transformation helpers.
4
4
  */
5
5
  import { type AnyIterable } from "./iterable.js";
6
+ /** Defines how adjacent selected keys are compared and retained. */
7
+ export interface DistinctUntilChangedStrategy<K> {
8
+ /** Returns true when adjacent keys represent the same state. */
9
+ equals(previous: unknown, current: K): boolean;
10
+ /** Captures the state retained for the next comparison. */
11
+ snapshot(value: K): unknown;
12
+ }
6
13
  /** Maps an iterable, preserving synchronous iteration when possible. */
7
14
  export declare function mapIterable<T, R>(source: AnyIterable<T>, mapper: (value: T) => R): AnyIterable<R>;
8
15
  /** Filters an iterable, preserving synchronous iteration when possible. */
@@ -18,7 +25,7 @@ export declare function skipWhileIterable<T>(source: AnyIterable<T>, predicate:
18
25
  /** Keeps the first value for every selected key, preserving synchronous iteration when possible. */
19
26
  export declare function distinctIterable<T, K>(source: AnyIterable<T>, keySelector: (value: T) => K): AnyIterable<T>;
20
27
  /** Keeps values whose selected key differs from the previous key. */
21
- export declare function distinctUntilChangedIterable<T, K>(source: AnyIterable<T>, keySelector: (value: T) => K): AnyIterable<T>;
28
+ export declare function distinctUntilChangedIterable<T, K>(source: AnyIterable<T>, keySelector: (value: T) => K, strategy?: DistinctUntilChangedStrategy<K>): AnyIterable<T>;
22
29
  /** Emits a fallback value when the source is empty. */
23
30
  export declare function defaultIfEmptyIterable<T>(source: AnyIterable<T>, defaultValue: T): AnyIterable<T>;
24
31
  //# sourceMappingURL=iterable-transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"iterable-transform.d.ts","sourceRoot":"","sources":["../../src/internal/iterable-transform.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAC,KAAK,WAAW,EAAkB,MAAM,wBAAwB,CAAC;AAEzE,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAajG;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAiB1G;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAmB7G;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAmB7G;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAuBrF;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAuB7G;AAED,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAuB3G;AAED,qEAAqE;AACrE,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,CAAC,EAC7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAC7B,WAAW,CAAC,CAAC,CAAC,CA2BhB;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAuBjG"}
1
+ {"version":3,"file":"iterable-transform.d.ts","sourceRoot":"","sources":["../../src/internal/iterable-transform.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAC,KAAK,WAAW,EAAkB,MAAM,wBAAwB,CAAC;AAEzE,oEAAoE;AACpE,MAAM,WAAW,4BAA4B,CAAC,CAAC;IAC3C,gEAAgE;IAChE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;IAE/C,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;CAC/B;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAajG;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAiB1G;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAmB7G;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAmB7G;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAuBrF;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAuB7G;AAED,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAuB3G;AAED,qEAAqE;AACrE,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,CAAC,EAC7C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAC5B,QAAQ,CAAC,EAAE,4BAA4B,CAAC,CAAC,CAAC,GAC3C,WAAW,CAAC,CAAC,CAAC,CA6BhB;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAuBjG"}
@@ -108,15 +108,17 @@ function distinctIterable(source, keySelector) {
108
108
  })();
109
109
  }
110
110
  /** Keeps values whose selected key differs from the previous key. */
111
- function distinctUntilChangedIterable(source, keySelector) {
111
+ function distinctUntilChangedIterable(source, keySelector, strategy) {
112
+ const equals = strategy?.equals ?? Object.is;
113
+ const snapshot = strategy?.snapshot ?? ((value) => value);
112
114
  if (isAsyncIterable(source)) return (async function* () {
113
115
  let hasPrevious = false;
114
116
  let previous;
115
117
  for await (const value of source) {
116
118
  const key = keySelector(value);
117
- if (!hasPrevious || !Object.is(previous, key)) {
119
+ if (!hasPrevious || !equals(previous, key)) {
118
120
  hasPrevious = true;
119
- previous = key;
121
+ previous = snapshot(key);
120
122
  yield value;
121
123
  }
122
124
  }
@@ -126,9 +128,9 @@ function distinctUntilChangedIterable(source, keySelector) {
126
128
  let previous;
127
129
  for (const value of source) {
128
130
  const key = keySelector(value);
129
- if (!hasPrevious || !Object.is(previous, key)) {
131
+ if (!hasPrevious || !equals(previous, key)) {
130
132
  hasPrevious = true;
131
- previous = key;
133
+ previous = snapshot(key);
132
134
  yield value;
133
135
  }
134
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"iterable-transform.js","names":[],"sources":["../../src/internal/iterable-transform.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Internal iterable transformation helpers.\n */\nimport {type AnyIterable, isAsyncIterable} from \"@/internal/iterable.js\";\n\n/** Maps an iterable, preserving synchronous iteration when possible. */\nexport function mapIterable<T, R>(source: AnyIterable<T>, mapper: (value: T) => R): AnyIterable<R> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n yield mapper(value);\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n yield mapper(value);\n }\n })();\n}\n\n/** Filters an iterable, preserving synchronous iteration when possible. */\nexport function filterIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n if (predicate(value)) {\n yield value;\n }\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n if (predicate(value)) {\n yield value;\n }\n }\n })();\n}\n\n/** Takes values while a predicate returns true, preserving synchronous iteration when possible. */\nexport function takeWhileIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n if (!predicate(value)) {\n return;\n }\n yield value;\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n if (!predicate(value)) {\n return;\n }\n yield value;\n }\n })();\n}\n\n/** Takes values until a predicate returns true, preserving synchronous iteration when possible. */\nexport function takeUntilIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n yield value;\n if (predicate(value)) {\n return;\n }\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n yield value;\n if (predicate(value)) {\n return;\n }\n }\n })();\n}\n\n/** Skips a fixed number of values, preserving synchronous iteration when possible. */\nexport function skipIterable<T>(source: AnyIterable<T>, count: number): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let skipped = 0;\n for await (const value of source) {\n if (skipped < count) {\n skipped += 1;\n } else {\n yield value;\n }\n }\n })();\n }\n return (function* () {\n let skipped = 0;\n for (const value of source) {\n if (skipped < count) {\n skipped += 1;\n } else {\n yield value;\n }\n }\n })();\n}\n\n/** Skips values while a predicate returns true, preserving synchronous iteration when possible. */\nexport function skipWhileIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let skipping = true;\n for await (const value of source) {\n if (skipping && predicate(value)) {\n continue;\n }\n skipping = false;\n yield value;\n }\n })();\n }\n return (function* () {\n let skipping = true;\n for (const value of source) {\n if (skipping && predicate(value)) {\n continue;\n }\n skipping = false;\n yield value;\n }\n })();\n}\n\n/** Keeps the first value for every selected key, preserving synchronous iteration when possible. */\nexport function distinctIterable<T, K>(source: AnyIterable<T>, keySelector: (value: T) => K): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n const seen = new Set<K>();\n for await (const value of source) {\n const key = keySelector(value);\n if (!seen.has(key)) {\n seen.add(key);\n yield value;\n }\n }\n })();\n }\n return (function* () {\n const seen = new Set<K>();\n for (const value of source) {\n const key = keySelector(value);\n if (!seen.has(key)) {\n seen.add(key);\n yield value;\n }\n }\n })();\n}\n\n/** Keeps values whose selected key differs from the previous key. */\nexport function distinctUntilChangedIterable<T, K>(\n source: AnyIterable<T>,\n keySelector: (value: T) => K\n): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let hasPrevious = false;\n let previous: K | undefined;\n for await (const value of source) {\n const key = keySelector(value);\n if (!hasPrevious || !Object.is(previous, key)) {\n hasPrevious = true;\n previous = key;\n yield value;\n }\n }\n })();\n }\n return (function* () {\n let hasPrevious = false;\n let previous: K | undefined;\n for (const value of source) {\n const key = keySelector(value);\n if (!hasPrevious || !Object.is(previous, key)) {\n hasPrevious = true;\n previous = key;\n yield value;\n }\n }\n })();\n}\n\n/** Emits a fallback value when the source is empty. */\nexport function defaultIfEmptyIterable<T>(source: AnyIterable<T>, defaultValue: T): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let empty = true;\n for await (const value of source) {\n empty = false;\n yield value;\n }\n if (empty) {\n yield defaultValue;\n }\n })();\n }\n return (function* () {\n let empty = true;\n for (const value of source) {\n empty = false;\n yield value;\n }\n if (empty) {\n yield defaultValue;\n }\n })();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"iterable-transform.js","names":[],"sources":["../../src/internal/iterable-transform.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Internal iterable transformation helpers.\n */\nimport {type AnyIterable, isAsyncIterable} from \"@/internal/iterable.js\";\n\n/** Defines how adjacent selected keys are compared and retained. */\nexport interface DistinctUntilChangedStrategy<K> {\n /** Returns true when adjacent keys represent the same state. */\n equals(previous: unknown, current: K): boolean;\n\n /** Captures the state retained for the next comparison. */\n snapshot(value: K): unknown;\n}\n\n/** Maps an iterable, preserving synchronous iteration when possible. */\nexport function mapIterable<T, R>(source: AnyIterable<T>, mapper: (value: T) => R): AnyIterable<R> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n yield mapper(value);\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n yield mapper(value);\n }\n })();\n}\n\n/** Filters an iterable, preserving synchronous iteration when possible. */\nexport function filterIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n if (predicate(value)) {\n yield value;\n }\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n if (predicate(value)) {\n yield value;\n }\n }\n })();\n}\n\n/** Takes values while a predicate returns true, preserving synchronous iteration when possible. */\nexport function takeWhileIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n if (!predicate(value)) {\n return;\n }\n yield value;\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n if (!predicate(value)) {\n return;\n }\n yield value;\n }\n })();\n}\n\n/** Takes values until a predicate returns true, preserving synchronous iteration when possible. */\nexport function takeUntilIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n for await (const value of source) {\n yield value;\n if (predicate(value)) {\n return;\n }\n }\n })();\n }\n return (function* () {\n for (const value of source) {\n yield value;\n if (predicate(value)) {\n return;\n }\n }\n })();\n}\n\n/** Skips a fixed number of values, preserving synchronous iteration when possible. */\nexport function skipIterable<T>(source: AnyIterable<T>, count: number): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let skipped = 0;\n for await (const value of source) {\n if (skipped < count) {\n skipped += 1;\n } else {\n yield value;\n }\n }\n })();\n }\n return (function* () {\n let skipped = 0;\n for (const value of source) {\n if (skipped < count) {\n skipped += 1;\n } else {\n yield value;\n }\n }\n })();\n}\n\n/** Skips values while a predicate returns true, preserving synchronous iteration when possible. */\nexport function skipWhileIterable<T>(source: AnyIterable<T>, predicate: (value: T) => boolean): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let skipping = true;\n for await (const value of source) {\n if (skipping && predicate(value)) {\n continue;\n }\n skipping = false;\n yield value;\n }\n })();\n }\n return (function* () {\n let skipping = true;\n for (const value of source) {\n if (skipping && predicate(value)) {\n continue;\n }\n skipping = false;\n yield value;\n }\n })();\n}\n\n/** Keeps the first value for every selected key, preserving synchronous iteration when possible. */\nexport function distinctIterable<T, K>(source: AnyIterable<T>, keySelector: (value: T) => K): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n const seen = new Set<K>();\n for await (const value of source) {\n const key = keySelector(value);\n if (!seen.has(key)) {\n seen.add(key);\n yield value;\n }\n }\n })();\n }\n return (function* () {\n const seen = new Set<K>();\n for (const value of source) {\n const key = keySelector(value);\n if (!seen.has(key)) {\n seen.add(key);\n yield value;\n }\n }\n })();\n}\n\n/** Keeps values whose selected key differs from the previous key. */\nexport function distinctUntilChangedIterable<T, K>(\n source: AnyIterable<T>,\n keySelector: (value: T) => K,\n strategy?: DistinctUntilChangedStrategy<K>\n): AnyIterable<T> {\n const equals = strategy?.equals ?? Object.is;\n const snapshot = strategy?.snapshot ?? ((value: K): unknown => value);\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let hasPrevious = false;\n let previous: unknown;\n for await (const value of source) {\n const key = keySelector(value);\n if (!hasPrevious || !equals(previous, key)) {\n hasPrevious = true;\n previous = snapshot(key);\n yield value;\n }\n }\n })();\n }\n return (function* () {\n let hasPrevious = false;\n let previous: unknown;\n for (const value of source) {\n const key = keySelector(value);\n if (!hasPrevious || !equals(previous, key)) {\n hasPrevious = true;\n previous = snapshot(key);\n yield value;\n }\n }\n })();\n}\n\n/** Emits a fallback value when the source is empty. */\nexport function defaultIfEmptyIterable<T>(source: AnyIterable<T>, defaultValue: T): AnyIterable<T> {\n if (isAsyncIterable<T>(source)) {\n return (async function* () {\n let empty = true;\n for await (const value of source) {\n empty = false;\n yield value;\n }\n if (empty) {\n yield defaultValue;\n }\n })();\n }\n return (function* () {\n let empty = true;\n for (const value of source) {\n empty = false;\n yield value;\n }\n if (empty) {\n yield defaultValue;\n }\n })();\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Internal subscriber hook that exposes an already-known upstream demand batch. */
2
+ export declare const ITERATION_DEMAND_HINT: unique symbol;
3
+ /** Subscriber shape that can propagate a demand hint before source assembly. */
4
+ export interface IterationDemandAware {
5
+ /** Returns the demand batch that this subscriber will request upstream. */
6
+ [ITERATION_DEMAND_HINT]?(): number | undefined;
7
+ }
8
+ /** Marks nested iteration as an unbounded terminal drain. */
9
+ export declare function markUnboundedIteration(signal: AbortSignal): void;
10
+ /** Marks a signal when a subscriber already knows it will request unbounded demand. */
11
+ export declare function applyIterationDemandHint(signal: AbortSignal, subscriber: unknown): void;
12
+ /** Reads an internal demand hint without exposing it through the public Subscriber contract. */
13
+ export declare function iterationDemandHint(subscriber: unknown): number | undefined;
14
+ /** Returns true when nested Publisher bridges may request unbounded demand once. */
15
+ export declare function isUnboundedIteration(signal: AbortSignal): boolean;
16
+ /** Propagates unbounded iteration metadata to a derived cancellation signal. */
17
+ export declare function inheritIterationDemand(parent: AbortSignal, child: AbortSignal): void;
18
+ //# sourceMappingURL=iteration-demand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iteration-demand.d.ts","sourceRoot":"","sources":["../../src/internal/iteration-demand.ts"],"names":[],"mappings":"AAMA,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,eAAkC,CAAC;AAErE,gFAAgF;AAChF,MAAM,WAAW,oBAAoB;IACjC,2EAA2E;IAC3E,CAAC,qBAAqB,CAAC,CAAC,IAAI,MAAM,GAAG,SAAS,CAAC;CAClD;AAKD,6DAA6D;AAC7D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAEhE;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAKvF;AAED,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE3E;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAEjE;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAIpF"}
@@ -0,0 +1,34 @@
1
+ import { UNBOUNDED_DEMAND } from "../core/demand.js";
2
+ //#region src/internal/iteration-demand.ts
3
+ /**
4
+ * @packageDocumentation
5
+ * Internal demand metadata propagated through nested iterable operator paths.
6
+ */
7
+ /** Internal subscriber hook that exposes an already-known upstream demand batch. */
8
+ var ITERATION_DEMAND_HINT = Symbol("iteration-demand-hint");
9
+ /** Signals whose enclosing subscriber requested unbounded demand. */
10
+ var UNBOUNDED_SIGNALS = /* @__PURE__ */ new WeakSet();
11
+ /** Marks nested iteration as an unbounded terminal drain. */
12
+ function markUnboundedIteration(signal) {
13
+ UNBOUNDED_SIGNALS.add(signal);
14
+ }
15
+ /** Marks a signal when a subscriber already knows it will request unbounded demand. */
16
+ function applyIterationDemandHint(signal, subscriber) {
17
+ if (iterationDemandHint(subscriber) === UNBOUNDED_DEMAND) markUnboundedIteration(signal);
18
+ }
19
+ /** Reads an internal demand hint without exposing it through the public Subscriber contract. */
20
+ function iterationDemandHint(subscriber) {
21
+ return subscriber?.[ITERATION_DEMAND_HINT]?.();
22
+ }
23
+ /** Returns true when nested Publisher bridges may request unbounded demand once. */
24
+ function isUnboundedIteration(signal) {
25
+ return UNBOUNDED_SIGNALS.has(signal);
26
+ }
27
+ /** Propagates unbounded iteration metadata to a derived cancellation signal. */
28
+ function inheritIterationDemand(parent, child) {
29
+ if (isUnboundedIteration(parent)) markUnboundedIteration(child);
30
+ }
31
+ //#endregion
32
+ export { ITERATION_DEMAND_HINT, applyIterationDemandHint, inheritIterationDemand, isUnboundedIteration, iterationDemandHint, markUnboundedIteration };
33
+
34
+ //# sourceMappingURL=iteration-demand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iteration-demand.js","names":[],"sources":["../../src/internal/iteration-demand.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Internal demand metadata propagated through nested iterable operator paths.\n */\nimport {UNBOUNDED_DEMAND} from \"@/core/demand.js\";\n\n/** Internal subscriber hook that exposes an already-known upstream demand batch. */\nexport const ITERATION_DEMAND_HINT = Symbol(\"iteration-demand-hint\");\n\n/** Subscriber shape that can propagate a demand hint before source assembly. */\nexport interface IterationDemandAware {\n /** Returns the demand batch that this subscriber will request upstream. */\n [ITERATION_DEMAND_HINT]?(): number | undefined;\n}\n\n/** Signals whose enclosing subscriber requested unbounded demand. */\nconst UNBOUNDED_SIGNALS = new WeakSet<AbortSignal>();\n\n/** Marks nested iteration as an unbounded terminal drain. */\nexport function markUnboundedIteration(signal: AbortSignal): void {\n UNBOUNDED_SIGNALS.add(signal);\n}\n\n/** Marks a signal when a subscriber already knows it will request unbounded demand. */\nexport function applyIterationDemandHint(signal: AbortSignal, subscriber: unknown): void {\n const demand = iterationDemandHint(subscriber);\n if (demand === UNBOUNDED_DEMAND) {\n markUnboundedIteration(signal);\n }\n}\n\n/** Reads an internal demand hint without exposing it through the public Subscriber contract. */\nexport function iterationDemandHint(subscriber: unknown): number | undefined {\n return (subscriber as IterationDemandAware | null | undefined)?.[ITERATION_DEMAND_HINT]?.();\n}\n\n/** Returns true when nested Publisher bridges may request unbounded demand once. */\nexport function isUnboundedIteration(signal: AbortSignal): boolean {\n return UNBOUNDED_SIGNALS.has(signal);\n}\n\n/** Propagates unbounded iteration metadata to a derived cancellation signal. */\nexport function inheritIterationDemand(parent: AbortSignal, child: AbortSignal): void {\n if (isUnboundedIteration(parent)) {\n markUnboundedIteration(child);\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,wBAAwB,OAAO,uBAAuB;;AASnE,IAAM,oCAAoB,IAAI,QAAqB;;AAGnD,SAAgB,uBAAuB,QAA2B;CAC9D,kBAAkB,IAAI,MAAM;AAChC;;AAGA,SAAgB,yBAAyB,QAAqB,YAA2B;CAErF,IADe,oBAAoB,UAC/B,MAAW,kBACX,uBAAuB,MAAM;AAErC;;AAGA,SAAgB,oBAAoB,YAAyC;CACzE,OAAQ,aAAyD,sBAAsB,GAAG;AAC9F;;AAGA,SAAgB,qBAAqB,QAA8B;CAC/D,OAAO,kBAAkB,IAAI,MAAM;AACvC;;AAGA,SAAgB,uBAAuB,QAAqB,OAA0B;CAClF,IAAI,qBAAqB,MAAM,GAC3B,uBAAuB,KAAK;AAEpC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * Direct Publisher terminal-consumption primitives.
4
+ */
5
+ import type { Context } from "../context/context.js";
6
+ import type { Publisher } from "../publisher/publisher.js";
7
+ /** Stateful terminal reduction performed directly from Publisher signals. */
8
+ export interface TerminalCollector<T, R> {
9
+ /** Consumes one value and returns true when the terminal result is already known. */
10
+ onNext(value: T): boolean;
11
+ /** Produces the terminal result after completion or an early match. */
12
+ result(): R;
13
+ }
14
+ /**
15
+ * Subscribes directly to a Publisher, requests one configured batch and reduces
16
+ * signals without crossing the pull-based async-iterator bridge.
17
+ */
18
+ export declare function consumePublisher<T, R>(publisher: Publisher<T>, signal: AbortSignal, context: Context, request: number, collector: TerminalCollector<T, R>): Promise<R>;
19
+ /** Collects every Publisher value with one unbounded upstream request. */
20
+ export declare function collectPublisher<T>(publisher: Publisher<T>, signal: AbortSignal, context: Context): Promise<T[]>;
21
+ /** Returns the last Publisher value after consuming it with unbounded demand. */
22
+ export declare function lastPublisherValue<T>(publisher: Publisher<T>, signal: AbortSignal, context: Context): Promise<T | undefined>;
23
+ /** Consumes and discards every Publisher value with one unbounded request. */
24
+ export declare function drainPublisher(publisher: Publisher<unknown>, signal: AbortSignal, context: Context): Promise<void>;
25
+ //# sourceMappingURL=publisher-terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher-terminal.d.ts","sourceRoot":"","sources":["../../src/internal/publisher-terminal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAC;AAIlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAIxD,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB,CAAC,CAAC,EAAE,CAAC;IACnC,qFAAqF;IACrF,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IAE1B,uEAAuE;IACvE,MAAM,IAAI,CAAC,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EACjC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GACnC,OAAO,CAAC,CAAC,CAAC,CA0GZ;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAUhH;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,CAAC,EAChC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,OAAO,GACjB,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAUxB;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlH"}
@@ -0,0 +1,128 @@
1
+ import { UNBOUNDED_DEMAND } from "../core/demand.js";
2
+ import { CancelledError } from "../errors/classes.js";
3
+ import { ITERATION_DEMAND_HINT } from "./iteration-demand.js";
4
+ //#region src/internal/publisher-terminal.ts
5
+ /**
6
+ * Subscribes directly to a Publisher, requests one configured batch and reduces
7
+ * signals without crossing the pull-based async-iterator bridge.
8
+ */
9
+ function consumePublisher(publisher, signal, context, request, collector) {
10
+ return new Promise((resolve, reject) => {
11
+ let subscription;
12
+ let subscribed = false;
13
+ let terminated = false;
14
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
15
+ const terminate = () => {
16
+ if (terminated) return false;
17
+ terminated = true;
18
+ cleanup();
19
+ return true;
20
+ };
21
+ const cancelUpstream = () => {
22
+ try {
23
+ subscription?.cancel();
24
+ } catch {}
25
+ };
26
+ const fail = (error, cancel) => {
27
+ if (!terminate()) return;
28
+ if (cancel) cancelUpstream();
29
+ reject(error);
30
+ };
31
+ const complete = (cancel) => {
32
+ if (!terminate()) return;
33
+ if (cancel) cancelUpstream();
34
+ try {
35
+ resolve(collector.result());
36
+ } catch (error) {
37
+ reject(error);
38
+ }
39
+ };
40
+ function onAbort() {
41
+ fail(new CancelledError(), true);
42
+ }
43
+ if (signal.aborted) {
44
+ reject(new CancelledError());
45
+ return;
46
+ }
47
+ signal.addEventListener("abort", onAbort, { once: true });
48
+ const subscriber = {
49
+ /** Propagates the configured terminal batch through nested iterable operators. */
50
+ [ITERATION_DEMAND_HINT]: () => request,
51
+ /** Exposes the downstream context to context-aware Publisher sources. */
52
+ currentContext: () => context,
53
+ /** Stores the subscription and starts the configured terminal batch. */
54
+ onSubscribe(nextSubscription) {
55
+ if (subscribed || terminated) {
56
+ try {
57
+ nextSubscription.cancel();
58
+ } catch {}
59
+ return;
60
+ }
61
+ subscribed = true;
62
+ subscription = nextSubscription;
63
+ try {
64
+ nextSubscription.request(request);
65
+ } catch (error) {
66
+ fail(error, true);
67
+ }
68
+ },
69
+ /** Reduces a value and cancels immediately when the result is known. */
70
+ onNext(value) {
71
+ if (terminated) return;
72
+ try {
73
+ if (collector.onNext(value)) complete(true);
74
+ } catch (error) {
75
+ fail(error, true);
76
+ }
77
+ },
78
+ /** Forwards the first Publisher failure. */
79
+ onError(error) {
80
+ fail(error, false);
81
+ },
82
+ /** Produces the collected result after normal completion. */
83
+ onComplete() {
84
+ complete(false);
85
+ }
86
+ };
87
+ try {
88
+ publisher.subscribe(subscriber);
89
+ } catch (error) {
90
+ fail(error, true);
91
+ }
92
+ });
93
+ }
94
+ /** Collects every Publisher value with one unbounded upstream request. */
95
+ function collectPublisher(publisher, signal, context) {
96
+ const values = [];
97
+ return consumePublisher(publisher, signal, context, UNBOUNDED_DEMAND, {
98
+ /** Appends one source value to the result array. */
99
+ onNext(value) {
100
+ values.push(value);
101
+ return false;
102
+ },
103
+ result: () => values
104
+ });
105
+ }
106
+ /** Returns the last Publisher value after consuming it with unbounded demand. */
107
+ function lastPublisherValue(publisher, signal, context) {
108
+ let last;
109
+ return consumePublisher(publisher, signal, context, UNBOUNDED_DEMAND, {
110
+ /** Replaces the previously observed last value. */
111
+ onNext(value) {
112
+ last = value;
113
+ return false;
114
+ },
115
+ result: () => last
116
+ });
117
+ }
118
+ /** Consumes and discards every Publisher value with one unbounded request. */
119
+ function drainPublisher(publisher, signal, context) {
120
+ return consumePublisher(publisher, signal, context, UNBOUNDED_DEMAND, {
121
+ onNext: () => false,
122
+ result: () => void 0
123
+ });
124
+ }
125
+ //#endregion
126
+ export { collectPublisher, consumePublisher, drainPublisher, lastPublisherValue };
127
+
128
+ //# sourceMappingURL=publisher-terminal.js.map