@nlozgachev/pipelined 0.11.0 → 0.12.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.
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Functional utilities for unique-value collections (`ReadonlySet<A>`). All functions are pure
3
+ * and data-last — they compose naturally with `pipe`.
4
+ *
5
+ * Every "mutating" operation returns a new set; the original is never changed.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Uniq } from "@nlozgachev/pipelined/utils";
10
+ * import { pipe } from "@nlozgachev/pipelined/composition";
11
+ *
12
+ * const active = pipe(
13
+ * Uniq.fromArray(["alice", "bob", "alice", "carol"]),
14
+ * Uniq.remove("bob"),
15
+ * Uniq.map(name => name.toUpperCase()),
16
+ * );
17
+ * // ReadonlySet { "ALICE", "CAROL" }
18
+ * ```
19
+ */
20
+ export var Uniq;
21
+ (function (Uniq) {
22
+ // ---------------------------------------------------------------------------
23
+ // Constructors
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Creates an empty unique collection.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * Uniq.empty<number>(); // ReadonlySet {}
31
+ * ```
32
+ */
33
+ Uniq.empty = () => new globalThis.Set();
34
+ /**
35
+ * Creates a unique collection containing a single item.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * Uniq.singleton(42); // ReadonlySet { 42 }
40
+ * ```
41
+ */
42
+ Uniq.singleton = (item) => new globalThis.Set([item]);
43
+ /**
44
+ * Creates a unique collection from an array, automatically discarding duplicates.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * Uniq.fromArray([1, 2, 2, 3, 3, 3]); // ReadonlySet { 1, 2, 3 }
49
+ * Uniq.fromArray([]); // ReadonlySet {}
50
+ * ```
51
+ */
52
+ Uniq.fromArray = (arr) => new globalThis.Set(arr);
53
+ // ---------------------------------------------------------------------------
54
+ // Query
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Returns `true` if the collection contains the given item.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.has(2)); // true
62
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.has(4)); // false
63
+ * ```
64
+ */
65
+ Uniq.has = (item) => (s) => s.has(item);
66
+ /**
67
+ * Returns the number of items in the collection.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * Uniq.size(Uniq.fromArray([1, 2, 3])); // 3
72
+ * ```
73
+ */
74
+ Uniq.size = (s) => s.size;
75
+ /**
76
+ * Returns `true` if the collection has no items.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * Uniq.isEmpty(Uniq.empty()); // true
81
+ * ```
82
+ */
83
+ Uniq.isEmpty = (s) => s.size === 0;
84
+ /**
85
+ * Returns `true` if every item in `set` also exists in `other`.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * pipe(Uniq.fromArray([1, 2]), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // true
90
+ * pipe(Uniq.fromArray([1, 4]), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // false
91
+ * pipe(Uniq.empty<number>(), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // true
92
+ * ```
93
+ */
94
+ Uniq.isSubsetOf = (other) => (s) => {
95
+ const set = s;
96
+ if (typeof set.isSubsetOf === "function")
97
+ return set.isSubsetOf(other);
98
+ for (const item of s)
99
+ if (!other.has(item))
100
+ return false;
101
+ return true;
102
+ };
103
+ // ---------------------------------------------------------------------------
104
+ // Modification
105
+ // ---------------------------------------------------------------------------
106
+ /**
107
+ * Returns a new collection with the item added. If the item is already present, returns the
108
+ * original collection unchanged.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * pipe(Uniq.fromArray([1, 2]), Uniq.insert(3)); // ReadonlySet { 1, 2, 3 }
113
+ * pipe(Uniq.fromArray([1, 2]), Uniq.insert(2)); // ReadonlySet { 1, 2 } — unchanged
114
+ * ```
115
+ */
116
+ Uniq.insert = (item) => (s) => {
117
+ if (s.has(item))
118
+ return s;
119
+ const result = new globalThis.Set(s);
120
+ result.add(item);
121
+ return result;
122
+ };
123
+ /**
124
+ * Returns a new collection with the item removed. If the item is not present, returns the
125
+ * original collection unchanged.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.remove(2)); // ReadonlySet { 1, 3 }
130
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.remove(4)); // ReadonlySet { 1, 2, 3 } — unchanged
131
+ * ```
132
+ */
133
+ Uniq.remove = (item) => (s) => {
134
+ if (!s.has(item))
135
+ return s;
136
+ const result = new globalThis.Set(s);
137
+ result.delete(item);
138
+ return result;
139
+ };
140
+ // ---------------------------------------------------------------------------
141
+ // Transform
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * Applies `f` to each item, returning a new collection of the results. Duplicate results are
145
+ * automatically merged.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * pipe(Uniq.fromArray([1, 2, 3, 4]), Uniq.map(n => n % 3)); // ReadonlySet { 1, 2, 0 }
150
+ * ```
151
+ */
152
+ Uniq.map = (f) => (s) => {
153
+ const result = new globalThis.Set();
154
+ for (const item of s) {
155
+ result.add(f(item));
156
+ }
157
+ return result;
158
+ };
159
+ /**
160
+ * Returns a new collection containing only the items for which the predicate returns `true`.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * pipe(Uniq.fromArray([1, 2, 3, 4, 5]), Uniq.filter(n => n % 2 === 0));
165
+ * // ReadonlySet { 2, 4 }
166
+ * ```
167
+ */
168
+ Uniq.filter = (predicate) => (s) => {
169
+ const result = new globalThis.Set();
170
+ for (const item of s) {
171
+ if (predicate(item))
172
+ result.add(item);
173
+ }
174
+ return result;
175
+ };
176
+ // ---------------------------------------------------------------------------
177
+ // Set operations
178
+ // ---------------------------------------------------------------------------
179
+ /**
180
+ * Returns a new collection containing all items from both collections.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.union(Uniq.fromArray([2, 3, 4])));
185
+ * // ReadonlySet { 1, 2, 3, 4 }
186
+ * ```
187
+ */
188
+ Uniq.union = (other) => (s) => {
189
+ const set = s;
190
+ if (typeof set.union === "function")
191
+ return set.union(other);
192
+ const result = new globalThis.Set(s);
193
+ for (const item of other)
194
+ result.add(item);
195
+ return result;
196
+ };
197
+ /**
198
+ * Returns a new collection containing only the items that appear in both collections.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * pipe(Uniq.fromArray([1, 2, 3]), Uniq.intersection(Uniq.fromArray([2, 3, 4])));
203
+ * // ReadonlySet { 2, 3 }
204
+ * ```
205
+ */
206
+ Uniq.intersection = (other) => (s) => {
207
+ const set = s;
208
+ if (typeof set.intersection === "function")
209
+ return set.intersection(other);
210
+ const result = new globalThis.Set();
211
+ for (const item of s)
212
+ if (other.has(item))
213
+ result.add(item);
214
+ return result;
215
+ };
216
+ /**
217
+ * Returns a new collection containing only the items from `set` that do not appear in `other`.
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * pipe(Uniq.fromArray([1, 2, 3, 4]), Uniq.difference(Uniq.fromArray([2, 4])));
222
+ * // ReadonlySet { 1, 3 }
223
+ * ```
224
+ */
225
+ Uniq.difference = (other) => (s) => {
226
+ const set = s;
227
+ if (typeof set.difference === "function")
228
+ return set.difference(other);
229
+ const result = new globalThis.Set();
230
+ for (const item of s)
231
+ if (!other.has(item))
232
+ result.add(item);
233
+ return result;
234
+ };
235
+ // ---------------------------------------------------------------------------
236
+ // Fold
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * Folds the collection into a single value by applying `f` to each item in insertion order.
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * Uniq.reduce(0, (acc, n) => acc + n)(Uniq.fromArray([1, 2, 3])); // 6
244
+ * ```
245
+ */
246
+ Uniq.reduce = (init, f) => (s) => {
247
+ let acc = init;
248
+ for (const item of s) {
249
+ acc = f(acc, item);
250
+ }
251
+ return acc;
252
+ };
253
+ // ---------------------------------------------------------------------------
254
+ // Convert
255
+ // ---------------------------------------------------------------------------
256
+ /**
257
+ * Converts the collection to a readonly array in insertion order.
258
+ *
259
+ * @example
260
+ * ```ts
261
+ * Uniq.toArray(Uniq.fromArray([3, 1, 2])); // [3, 1, 2]
262
+ * ```
263
+ */
264
+ Uniq.toArray = (s) => [...s];
265
+ })(Uniq || (Uniq = {}));
@@ -2,3 +2,5 @@ export * from "./Arr.js";
2
2
  export * from "./Rec.js";
3
3
  export * from "./Num.js";
4
4
  export * from "./Str.js";
5
+ export * from "./Dict.js";
6
+ export * from "./Uniq.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nlozgachev/pipelined",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Simple functional programming toolkit for TypeScript",
5
5
  "keywords": [
6
6
  "functional",
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tuple = void 0;
4
+ var Tuple;
5
+ (function (Tuple) {
6
+ /**
7
+ * Creates a pair from two values.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * Tuple.make("Paris", 2_161_000); // ["Paris", 2161000]
12
+ * ```
13
+ */
14
+ Tuple.make = (first, second) => [first, second];
15
+ /**
16
+ * Returns the first value from the pair.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * Tuple.first(Tuple.make("Paris", 2_161_000)); // "Paris"
21
+ * ```
22
+ */
23
+ Tuple.first = (tuple) => tuple[0];
24
+ /**
25
+ * Returns the second value from the pair.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * Tuple.second(Tuple.make("Paris", 2_161_000)); // 2161000
30
+ * ```
31
+ */
32
+ Tuple.second = (tuple) => tuple[1];
33
+ /**
34
+ * Transforms the first value, leaving the second unchanged.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * pipe(Tuple.make("alice", 42), Tuple.mapFirst((s) => s.toUpperCase())); // ["ALICE", 42]
39
+ * ```
40
+ */
41
+ Tuple.mapFirst = (f) => (tuple) => [f(tuple[0]), tuple[1]];
42
+ /**
43
+ * Transforms the second value, leaving the first unchanged.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * pipe(Tuple.make("alice", 42), Tuple.mapSecond((n) => n * 2)); // ["alice", 84]
48
+ * ```
49
+ */
50
+ Tuple.mapSecond = (f) => (tuple) => [tuple[0], f(tuple[1])];
51
+ /**
52
+ * Transforms both values independently in a single step.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * pipe(
57
+ * Tuple.make("alice", 42),
58
+ * Tuple.mapBoth(
59
+ * (name) => name.toUpperCase(),
60
+ * (score) => score * 2,
61
+ * ),
62
+ * ); // ["ALICE", 84]
63
+ * ```
64
+ */
65
+ Tuple.mapBoth = (onFirst, onSecond) => (tuple) => [
66
+ onFirst(tuple[0]),
67
+ onSecond(tuple[1]),
68
+ ];
69
+ /**
70
+ * Applies a binary function to both values, collapsing the pair into a single value.
71
+ * Useful as the final step when consuming a pair in a pipeline.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * pipe(Tuple.make("Alice", 100), Tuple.fold((name, score) => `${name}: ${score}`));
76
+ * // "Alice: 100"
77
+ * ```
78
+ */
79
+ Tuple.fold = (f) => (tuple) => f(tuple[0], tuple[1]);
80
+ /**
81
+ * Swaps the two values: `[A, B]` becomes `[B, A]`.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * Tuple.swap(Tuple.make("key", 1)); // [1, "key"]
86
+ * ```
87
+ */
88
+ Tuple.swap = (tuple) => [tuple[1], tuple[0]];
89
+ /**
90
+ * Converts the pair to a heterogeneous readonly array `readonly (A | B)[]`.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * Tuple.toArray(Tuple.make("hello", 42)); // ["hello", 42]
95
+ * ```
96
+ */
97
+ Tuple.toArray = (tuple) => [...tuple];
98
+ /**
99
+ * Runs a side effect with both values without changing the pair.
100
+ * Useful for logging or debugging in the middle of a pipeline.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * pipe(
105
+ * Tuple.make("Paris", 2_161_000),
106
+ * Tuple.tap((city, pop) => console.log(`${city}: ${pop}`)),
107
+ * Tuple.mapSecond((n) => n / 1_000_000),
108
+ * ); // logs "Paris: 2161000", returns ["Paris", 2.161]
109
+ * ```
110
+ */
111
+ Tuple.tap = (f) => (tuple) => {
112
+ f(tuple[0], tuple[1]);
113
+ return tuple;
114
+ };
115
+ })(Tuple || (exports.Tuple = Tuple = {}));
@@ -14,20 +14,21 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./Logged.js"), exports);
18
17
  __exportStar(require("./Deferred.js"), exports);
19
18
  __exportStar(require("./Lens.js"), exports);
19
+ __exportStar(require("./Logged.js"), exports);
20
20
  __exportStar(require("./Option.js"), exports);
21
- __exportStar(require("./Reader.js"), exports);
22
21
  __exportStar(require("./Optional.js"), exports);
23
22
  __exportStar(require("./Predicate.js"), exports);
23
+ __exportStar(require("./Reader.js"), exports);
24
24
  __exportStar(require("./Refinement.js"), exports);
25
25
  __exportStar(require("./RemoteData.js"), exports);
26
- __exportStar(require("./State.js"), exports);
27
26
  __exportStar(require("./Result.js"), exports);
27
+ __exportStar(require("./State.js"), exports);
28
28
  __exportStar(require("./Task.js"), exports);
29
29
  __exportStar(require("./TaskOption.js"), exports);
30
30
  __exportStar(require("./TaskResult.js"), exports);
31
31
  __exportStar(require("./TaskValidation.js"), exports);
32
32
  __exportStar(require("./These.js"), exports);
33
+ __exportStar(require("./Tuple.js"), exports);
33
34
  __exportStar(require("./Validation.js"), exports);