@nlozgachev/pipelined 0.9.0 → 0.11.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 (75) hide show
  1. package/README.md +9 -3
  2. package/esm/src/Core/Option.js +2 -1
  3. package/esm/src/Core/Optional.js +2 -2
  4. package/esm/src/Core/RemoteData.js +8 -8
  5. package/esm/src/Core/TaskValidation.js +35 -12
  6. package/esm/src/Core/Validation.js +3 -3
  7. package/esm/src/Core/index.js +0 -2
  8. package/esm/src/{Core → Utils}/Arr.js +95 -23
  9. package/esm/src/Utils/Num.js +124 -0
  10. package/esm/src/{Core → Utils}/Rec.js +59 -11
  11. package/esm/src/Utils/Str.js +134 -0
  12. package/esm/src/Utils/index.js +4 -0
  13. package/package.json +11 -1
  14. package/script/src/Core/Option.js +2 -1
  15. package/script/src/Core/Optional.js +2 -2
  16. package/script/src/Core/RemoteData.js +8 -8
  17. package/script/src/Core/TaskValidation.js +35 -12
  18. package/script/src/Core/Validation.js +3 -3
  19. package/script/src/Core/index.js +0 -2
  20. package/script/src/{Core → Utils}/Arr.js +95 -23
  21. package/script/src/Utils/Num.js +127 -0
  22. package/script/src/{Core → Utils}/Rec.js +59 -11
  23. package/script/src/Utils/Str.js +137 -0
  24. package/script/src/Utils/index.js +20 -0
  25. package/types/src/Composition/compose.d.ts.map +1 -1
  26. package/types/src/Composition/converge.d.ts.map +1 -1
  27. package/types/src/Composition/curry.d.ts.map +1 -1
  28. package/types/src/Composition/flow.d.ts.map +1 -1
  29. package/types/src/Composition/fn.d.ts.map +1 -1
  30. package/types/src/Composition/juxt.d.ts.map +1 -1
  31. package/types/src/Composition/memoize.d.ts.map +1 -1
  32. package/types/src/Composition/not.d.ts.map +1 -1
  33. package/types/src/Composition/on.d.ts.map +1 -1
  34. package/types/src/Composition/pipe.d.ts.map +1 -1
  35. package/types/src/Composition/uncurry.d.ts.map +1 -1
  36. package/types/src/Core/Deferred.d.ts.map +1 -1
  37. package/types/src/Core/Lens.d.ts.map +1 -1
  38. package/types/src/Core/Logged.d.ts.map +1 -1
  39. package/types/src/Core/Option.d.ts +1 -1
  40. package/types/src/Core/Option.d.ts.map +1 -1
  41. package/types/src/Core/Optional.d.ts +2 -2
  42. package/types/src/Core/Optional.d.ts.map +1 -1
  43. package/types/src/Core/Predicate.d.ts.map +1 -1
  44. package/types/src/Core/Reader.d.ts.map +1 -1
  45. package/types/src/Core/Refinement.d.ts.map +1 -1
  46. package/types/src/Core/RemoteData.d.ts +3 -3
  47. package/types/src/Core/RemoteData.d.ts.map +1 -1
  48. package/types/src/Core/Result.d.ts +1 -1
  49. package/types/src/Core/Result.d.ts.map +1 -1
  50. package/types/src/Core/State.d.ts.map +1 -1
  51. package/types/src/Core/Task.d.ts.map +1 -1
  52. package/types/src/Core/TaskOption.d.ts +1 -1
  53. package/types/src/Core/TaskOption.d.ts.map +1 -1
  54. package/types/src/Core/TaskResult.d.ts.map +1 -1
  55. package/types/src/Core/TaskValidation.d.ts +31 -8
  56. package/types/src/Core/TaskValidation.d.ts.map +1 -1
  57. package/types/src/Core/These.d.ts.map +1 -1
  58. package/types/src/Core/Validation.d.ts +3 -3
  59. package/types/src/Core/Validation.d.ts.map +1 -1
  60. package/types/src/Core/index.d.ts +0 -2
  61. package/types/src/Core/index.d.ts.map +1 -1
  62. package/types/src/Types/Brand.d.ts.map +1 -1
  63. package/types/src/Types/NonEmptyList.d.ts.map +1 -1
  64. package/types/src/{Core → Utils}/Arr.d.ts +25 -3
  65. package/types/src/Utils/Arr.d.ts.map +1 -0
  66. package/types/src/Utils/Num.d.ts +110 -0
  67. package/types/src/Utils/Num.d.ts.map +1 -0
  68. package/types/src/{Core → Utils}/Rec.d.ts +23 -1
  69. package/types/src/Utils/Rec.d.ts.map +1 -0
  70. package/types/src/Utils/Str.d.ts +128 -0
  71. package/types/src/Utils/Str.d.ts.map +1 -0
  72. package/types/src/Utils/index.d.ts +5 -0
  73. package/types/src/Utils/index.d.ts.map +1 -0
  74. package/types/src/Core/Arr.d.ts.map +0 -1
  75. package/types/src/Core/Rec.d.ts.map +0 -1
@@ -0,0 +1,134 @@
1
+ import { Option } from "../Core/Option.js";
2
+ /**
3
+ * String utilities. All transformation functions are data-last and curried so they
4
+ * compose naturally with `pipe`. Safe parsers return `Option` instead of `NaN`.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Str } from "@nlozgachev/pipelined/utils";
9
+ * import { pipe } from "@nlozgachev/pipelined/composition";
10
+ *
11
+ * pipe(" Hello, World! ", Str.trim, Str.toLowerCase); // "hello, world!"
12
+ * ```
13
+ */
14
+ export var Str;
15
+ (function (Str) {
16
+ /**
17
+ * Splits a string by a separator. Data-last: use in `pipe`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * pipe("a,b,c", Str.split(",")); // ["a", "b", "c"]
22
+ * ```
23
+ */
24
+ Str.split = (separator) => (s) => s.split(separator);
25
+ /**
26
+ * Removes leading and trailing whitespace from a string.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * pipe(" hello ", Str.trim); // "hello"
31
+ * ```
32
+ */
33
+ Str.trim = (s) => s.trim();
34
+ /**
35
+ * Returns `true` when the string contains the given substring.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * pipe("hello world", Str.includes("world")); // true
40
+ * pipe("hello world", Str.includes("xyz")); // false
41
+ * ```
42
+ */
43
+ Str.includes = (substring) => (s) => s.includes(substring);
44
+ /**
45
+ * Returns `true` when the string starts with the given prefix.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * pipe("hello world", Str.startsWith("hello")); // true
50
+ * pipe("hello world", Str.startsWith("world")); // false
51
+ * ```
52
+ */
53
+ Str.startsWith = (prefix) => (s) => s.startsWith(prefix);
54
+ /**
55
+ * Returns `true` when the string ends with the given suffix.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * pipe("hello world", Str.endsWith("world")); // true
60
+ * pipe("hello world", Str.endsWith("hello")); // false
61
+ * ```
62
+ */
63
+ Str.endsWith = (suffix) => (s) => s.endsWith(suffix);
64
+ /**
65
+ * Converts a string to uppercase.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * pipe("hello", Str.toUpperCase); // "HELLO"
70
+ * ```
71
+ */
72
+ Str.toUpperCase = (s) => s.toUpperCase();
73
+ /**
74
+ * Converts a string to lowercase.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * pipe("HELLO", Str.toLowerCase); // "hello"
79
+ * ```
80
+ */
81
+ Str.toLowerCase = (s) => s.toLowerCase();
82
+ /**
83
+ * Splits a string into lines, normalising `\r\n` and `\r` line endings.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * Str.lines("one\ntwo\nthree"); // ["one", "two", "three"]
88
+ * Str.lines("a\r\nb"); // ["a", "b"]
89
+ * ```
90
+ */
91
+ Str.lines = (s) => s.split(/\r?\n|\r/);
92
+ /**
93
+ * Splits a string into words on any whitespace boundary, filtering out empty strings.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * Str.words(" hello world "); // ["hello", "world"]
98
+ * ```
99
+ */
100
+ Str.words = (s) => s.trim().split(/\s+/).filter(Boolean);
101
+ /**
102
+ * Safe number parsers that return `Option` instead of `NaN`.
103
+ */
104
+ Str.parse = {
105
+ /**
106
+ * Parses a string as an integer (base 10). Returns `None` if the result is `NaN`.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * Str.parse.int("42"); // Some(42)
111
+ * Str.parse.int("3.7"); // Some(3)
112
+ * Str.parse.int("abc"); // None
113
+ * ```
114
+ */
115
+ int: (s) => {
116
+ const n = parseInt(s, 10);
117
+ return isNaN(n) ? Option.none() : Option.some(n);
118
+ },
119
+ /**
120
+ * Parses a string as a floating-point number. Returns `None` if the result is `NaN`.
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * Str.parse.float("3.14"); // Some(3.14)
125
+ * Str.parse.float("42"); // Some(42)
126
+ * Str.parse.float("abc"); // None
127
+ * ```
128
+ */
129
+ float: (s) => {
130
+ const n = parseFloat(s);
131
+ return isNaN(n) ? Option.none() : Option.some(n);
132
+ },
133
+ };
134
+ })(Str || (Str = {}));
@@ -0,0 +1,4 @@
1
+ export * from "./Arr.js";
2
+ export * from "./Rec.js";
3
+ export * from "./Num.js";
4
+ export * from "./Str.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nlozgachev/pipelined",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Simple functional programming toolkit for TypeScript",
5
5
  "keywords": [
6
6
  "functional",
@@ -37,6 +37,16 @@
37
37
  "default": "./script/src/Core/index.js"
38
38
  }
39
39
  },
40
+ "./utils": {
41
+ "import": {
42
+ "types": "./types/src/Utils/index.d.ts",
43
+ "default": "./esm/src/Utils/index.js"
44
+ },
45
+ "require": {
46
+ "types": "./types/src/Utils/index.d.ts",
47
+ "default": "./script/src/Utils/index.js"
48
+ }
49
+ },
40
50
  "./types": {
41
51
  "import": {
42
52
  "types": "./types/src/Types/index.d.ts",
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Option = void 0;
4
4
  const Result_js_1 = require("./Result.js");
5
+ const _none = { kind: "None" };
5
6
  var Option;
6
7
  (function (Option) {
7
8
  /**
@@ -15,7 +16,7 @@ var Option;
15
16
  /**
16
17
  * Creates a None (empty Option).
17
18
  */
18
- Option.none = () => ({ kind: "None" });
19
+ Option.none = () => _none;
19
20
  /**
20
21
  * Type guard that checks if a Option is None.
21
22
  */
@@ -87,12 +87,12 @@ var Optional;
87
87
  *
88
88
  * @example
89
89
  * ```ts
90
- * pipe(profile, Optional.getOrElse(bioOpt)("no bio"));
90
+ * pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
91
91
  * ```
92
92
  */
93
93
  Optional.getOrElse = (opt) => (defaultValue) => (s) => {
94
94
  const val = opt.get(s);
95
- return val.kind === "Some" ? val.value : defaultValue;
95
+ return val.kind === "Some" ? val.value : defaultValue();
96
96
  };
97
97
  /**
98
98
  * Extracts a value from an Optional focus using handlers for the present
@@ -3,16 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RemoteData = void 0;
4
4
  const Option_js_1 = require("./Option.js");
5
5
  const Result_js_1 = require("./Result.js");
6
+ const _notAsked = { kind: "NotAsked" };
7
+ const _loading = { kind: "Loading" };
6
8
  var RemoteData;
7
9
  (function (RemoteData) {
8
10
  /**
9
11
  * Creates a NotAsked RemoteData.
10
12
  */
11
- RemoteData.notAsked = () => ({ kind: "NotAsked" });
13
+ RemoteData.notAsked = () => _notAsked;
12
14
  /**
13
15
  * Creates a Loading RemoteData.
14
16
  */
15
- RemoteData.loading = () => ({ kind: "Loading" });
17
+ RemoteData.loading = () => _loading;
16
18
  /**
17
19
  * Creates a Failure RemoteData with the given error.
18
20
  */
@@ -162,9 +164,9 @@ var RemoteData;
162
164
  *
163
165
  * @example
164
166
  * ```ts
165
- * pipe(RemoteData.success(5), RemoteData.getOrElse(0)); // 5
166
- * pipe(RemoteData.loading(), RemoteData.getOrElse(0)); // 0
167
- * pipe(RemoteData.loading<string, number>(), RemoteData.getOrElse(null)); // null — typed as number | null
167
+ * pipe(RemoteData.success(5), RemoteData.getOrElse(() => 0)); // 5
168
+ * pipe(RemoteData.loading(), RemoteData.getOrElse(() => 0)); // 0
169
+ * pipe(RemoteData.loading<string, number>(), RemoteData.getOrElse(() => null)); // null — typed as number | null
168
170
  * ```
169
171
  */
170
172
  RemoteData.getOrElse = (defaultValue) => (data) => RemoteData.isSuccess(data) ? data.value : defaultValue();
@@ -208,7 +210,5 @@ var RemoteData;
208
210
  * ); // Ok(42)
209
211
  * ```
210
212
  */
211
- RemoteData.toResult = (onNotReady) => (data) => RemoteData.isSuccess(data)
212
- ? Result_js_1.Result.ok(data.value)
213
- : Result_js_1.Result.err(RemoteData.isFailure(data) ? data.error : onNotReady());
213
+ RemoteData.toResult = (onNotReady) => (data) => RemoteData.isSuccess(data) ? Result_js_1.Result.ok(data.value) : Result_js_1.Result.err(RemoteData.isFailure(data) ? data.error : onNotReady());
214
214
  })(RemoteData || (exports.RemoteData = RemoteData = {}));
@@ -42,15 +42,6 @@ var TaskValidation;
42
42
  * Transforms the success value inside a TaskValidation.
43
43
  */
44
44
  TaskValidation.map = (f) => (data) => Task_js_1.Task.map(Validation_js_1.Validation.map(f))(data);
45
- /**
46
- * Chains TaskValidation computations. If the first is Valid, passes the value
47
- * to f. If the first is Invalid, propagates the errors.
48
- *
49
- * Note: chain short-circuits on first error. Use ap to accumulate errors.
50
- */
51
- TaskValidation.chain = (f) => (data) => Task_js_1.Task.chain((validation) => Validation_js_1.Validation.isValid(validation)
52
- ? f(validation.value)
53
- : Task_js_1.Task.resolve(Validation_js_1.Validation.invalidAll(validation.errors)))(data);
54
45
  /**
55
46
  * Applies a function wrapped in a TaskValidation to a value wrapped in a
56
47
  * TaskValidation. Both Tasks run in parallel and errors from both sides
@@ -100,9 +91,41 @@ var TaskValidation;
100
91
  TaskValidation.tap = (f) => (data) => Task_js_1.Task.map(Validation_js_1.Validation.tap(f))(data);
101
92
  /**
102
93
  * Recovers from an Invalid state by providing a fallback TaskValidation.
94
+ * The fallback receives the accumulated error list so callers can inspect which errors occurred.
103
95
  * The fallback can produce a different success type, widening the result to `TaskValidation<E, A | B>`.
104
96
  */
105
- TaskValidation.recover = (fallback) => (data) => Task_js_1.Task.chain((validation) => Validation_js_1.Validation.isValid(validation)
106
- ? Task_js_1.Task.resolve(validation)
107
- : fallback())(data);
97
+ TaskValidation.recover = (fallback) => (data) => Task_js_1.Task.chain((validation) => Validation_js_1.Validation.isValid(validation) ? Task_js_1.Task.resolve(validation) : fallback(validation.errors))(data);
98
+ /**
99
+ * Runs two TaskValidations concurrently and combines their results into a tuple.
100
+ * If both are Valid, returns Valid with both values. If either fails, accumulates
101
+ * errors from both sides.
102
+ *
103
+ * @example
104
+ * ```ts
105
+ * await TaskValidation.product(
106
+ * validateName(form.name),
107
+ * validateAge(form.age),
108
+ * )(); // Valid(["Alice", 30]) or Invalid([...errors])
109
+ * ```
110
+ */
111
+ TaskValidation.product = (first, second) => Task_js_1.Task.from(() => Promise.all([
112
+ Deferred_js_1.Deferred.toPromise(first()),
113
+ Deferred_js_1.Deferred.toPromise(second()),
114
+ ]).then(([va, vb]) => Validation_js_1.Validation.product(va, vb)));
115
+ /**
116
+ * Runs all TaskValidations concurrently and collects results.
117
+ * If all are Valid, returns Valid with all values as an array.
118
+ * If any fail, returns Invalid with all accumulated errors.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * await TaskValidation.productAll([
123
+ * validateName(form.name),
124
+ * validateEmail(form.email),
125
+ * validateAge(form.age),
126
+ * ])(); // Valid([name, email, age]) or Invalid([...all errors])
127
+ * ```
128
+ */
129
+ TaskValidation.productAll = (data) => Task_js_1.Task.from(() => Promise.all(data.map((t) => Deferred_js_1.Deferred.toPromise(t())))
130
+ .then((results) => Validation_js_1.Validation.productAll(results)));
108
131
  })(TaskValidation || (exports.TaskValidation = TaskValidation = {}));
@@ -122,9 +122,9 @@ var Validation;
122
122
  *
123
123
  * @example
124
124
  * ```ts
125
- * pipe(Validation.valid(5), Validation.getOrElse(0)); // 5
126
- * pipe(Validation.invalid("oops"), Validation.getOrElse(0)); // 0
127
- * pipe(Validation.invalid("oops"), Validation.getOrElse(null)); // null — typed as number | null
125
+ * pipe(Validation.valid(5), Validation.getOrElse(() => 0)); // 5
126
+ * pipe(Validation.invalid("oops"), Validation.getOrElse(() => 0)); // 0
127
+ * pipe(Validation.invalid("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
128
128
  * ```
129
129
  */
130
130
  Validation.getOrElse = (defaultValue) => (data) => Validation.isValid(data) ? data.value : defaultValue();
@@ -14,14 +14,12 @@ 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("./Arr.js"), exports);
18
17
  __exportStar(require("./Logged.js"), exports);
19
18
  __exportStar(require("./Deferred.js"), exports);
20
19
  __exportStar(require("./Lens.js"), exports);
21
20
  __exportStar(require("./Option.js"), exports);
22
21
  __exportStar(require("./Reader.js"), exports);
23
22
  __exportStar(require("./Optional.js"), exports);
24
- __exportStar(require("./Rec.js"), exports);
25
23
  __exportStar(require("./Predicate.js"), exports);
26
24
  __exportStar(require("./Refinement.js"), exports);
27
25
  __exportStar(require("./RemoteData.js"), exports);
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Arr = void 0;
4
- const Deferred_js_1 = require("./Deferred.js");
5
- const Option_js_1 = require("./Option.js");
6
- const Result_js_1 = require("./Result.js");
7
- const Task_js_1 = require("./Task.js");
4
+ const Deferred_js_1 = require("../Core/Deferred.js");
5
+ const Option_js_1 = require("../Core/Option.js");
6
+ const Result_js_1 = require("../Core/Result.js");
7
+ const Task_js_1 = require("../Core/Task.js");
8
8
  const NonEmptyList_js_1 = require("../Types/NonEmptyList.js");
9
9
  /**
10
10
  * Functional array utilities that compose well with pipe.
@@ -113,7 +113,13 @@ var Arr;
113
113
  * pipe([1, 2, 3], Arr.map(n => n * 2)); // [2, 4, 6]
114
114
  * ```
115
115
  */
116
- Arr.map = (f) => (data) => data.map(f);
116
+ Arr.map = (f) => (data) => {
117
+ const n = data.length;
118
+ const result = new Array(n);
119
+ for (let i = 0; i < n; i++)
120
+ result[i] = f(data[i]);
121
+ return result;
122
+ };
117
123
  /**
118
124
  * Filters elements that satisfy the predicate.
119
125
  *
@@ -122,7 +128,15 @@ var Arr;
122
128
  * pipe([1, 2, 3, 4], Arr.filter(n => n % 2 === 0)); // [2, 4]
123
129
  * ```
124
130
  */
125
- Arr.filter = (predicate) => (data) => data.filter(predicate);
131
+ Arr.filter = (predicate) => (data) => {
132
+ const n = data.length;
133
+ const result = [];
134
+ for (let i = 0; i < n; i++) {
135
+ if (predicate(data[i]))
136
+ result.push(data[i]);
137
+ }
138
+ return result;
139
+ };
126
140
  /**
127
141
  * Splits an array into two groups based on a predicate.
128
142
  * First group contains elements that satisfy the predicate,
@@ -216,9 +230,9 @@ var Arr;
216
230
  */
217
231
  Arr.zip = (other) => (data) => {
218
232
  const len = Math.min(data.length, other.length);
219
- const result = [];
233
+ const result = new Array(len);
220
234
  for (let i = 0; i < len; i++) {
221
- result.push([data[i], other[i]]);
235
+ result[i] = [data[i], other[i]];
222
236
  }
223
237
  return result;
224
238
  };
@@ -232,9 +246,9 @@ var Arr;
232
246
  */
233
247
  Arr.zipWith = (f) => (other) => (data) => {
234
248
  const len = Math.min(data.length, other.length);
235
- const result = [];
249
+ const result = new Array(len);
236
250
  for (let i = 0; i < len; i++) {
237
- result.push(f(data[i], other[i]));
251
+ result[i] = f(data[i], other[i]);
238
252
  }
239
253
  return result;
240
254
  };
@@ -289,7 +303,17 @@ var Arr;
289
303
  * pipe([1, 2, 3], Arr.flatMap(n => [n, n * 10])); // [1, 10, 2, 20, 3, 30]
290
304
  * ```
291
305
  */
292
- Arr.flatMap = (f) => (data) => [].concat(...data.map(f));
306
+ Arr.flatMap = (f) => (data) => {
307
+ const n = data.length;
308
+ const result = [];
309
+ for (let i = 0; i < n; i++) {
310
+ const chunk = f(data[i]);
311
+ const m = chunk.length;
312
+ for (let j = 0; j < m; j++)
313
+ result.push(chunk[j]);
314
+ }
315
+ return result;
316
+ };
293
317
  /**
294
318
  * Reduces an array from the left.
295
319
  *
@@ -316,12 +340,13 @@ var Arr;
316
340
  * ```
317
341
  */
318
342
  Arr.traverse = (f) => (data) => {
319
- const result = [];
320
- for (const a of data) {
321
- const mapped = f(a);
322
- if (Option_js_1.Option.isNone(mapped))
343
+ const n = data.length;
344
+ const result = new Array(n);
345
+ for (let i = 0; i < n; i++) {
346
+ const mapped = f(data[i]);
347
+ if (mapped.kind === "None")
323
348
  return Option_js_1.Option.none();
324
- result.push(mapped.value);
349
+ result[i] = mapped.value;
325
350
  }
326
351
  return Option_js_1.Option.some(result);
327
352
  };
@@ -338,12 +363,13 @@ var Arr;
338
363
  * ```
339
364
  */
340
365
  Arr.traverseResult = (f) => (data) => {
341
- const result = [];
342
- for (const a of data) {
343
- const mapped = f(a);
344
- if (Result_js_1.Result.isErr(mapped))
366
+ const n = data.length;
367
+ const result = new Array(n);
368
+ for (let i = 0; i < n; i++) {
369
+ const mapped = f(data[i]);
370
+ if (mapped.kind === "Error")
345
371
  return mapped;
346
- result.push(mapped.value);
372
+ result[i] = mapped.value;
347
373
  }
348
374
  return Result_js_1.Result.ok(result);
349
375
  };
@@ -430,7 +456,13 @@ var Arr;
430
456
  * pipe([1, 2, 3], Arr.some(n => n > 2)); // true
431
457
  * ```
432
458
  */
433
- Arr.some = (predicate) => (data) => data.some(predicate);
459
+ Arr.some = (predicate) => (data) => {
460
+ const n = data.length;
461
+ for (let i = 0; i < n; i++)
462
+ if (predicate(data[i]))
463
+ return true;
464
+ return false;
465
+ };
434
466
  /**
435
467
  * Returns true if all elements satisfy the predicate.
436
468
  *
@@ -439,7 +471,13 @@ var Arr;
439
471
  * pipe([1, 2, 3], Arr.every(n => n > 0)); // true
440
472
  * ```
441
473
  */
442
- Arr.every = (predicate) => (data) => data.every(predicate);
474
+ Arr.every = (predicate) => (data) => {
475
+ const n = data.length;
476
+ for (let i = 0; i < n; i++)
477
+ if (!predicate(data[i]))
478
+ return false;
479
+ return true;
480
+ };
443
481
  /**
444
482
  * Reverses an array. Returns a new array.
445
483
  *
@@ -498,4 +536,38 @@ var Arr;
498
536
  i++;
499
537
  return data.slice(i);
500
538
  };
539
+ /**
540
+ * Like `reduce`, but returns every intermediate accumulator as an array.
541
+ * The initial value is not included — the output has the same length as the input.
542
+ *
543
+ * @example
544
+ * ```ts
545
+ * pipe([1, 2, 3], Arr.scan(0, (acc, n) => acc + n)); // [1, 3, 6]
546
+ * ```
547
+ */
548
+ Arr.scan = (initial, f) => (data) => {
549
+ const n = data.length;
550
+ const result = new Array(n);
551
+ let acc = initial;
552
+ for (let i = 0; i < n; i++) {
553
+ acc = f(acc, data[i]);
554
+ result[i] = acc;
555
+ }
556
+ return result;
557
+ };
558
+ /**
559
+ * Splits an array at an index into a `[before, after]` tuple.
560
+ * Negative indices clamp to 0; indices beyond the array length clamp to the end.
561
+ *
562
+ * @example
563
+ * ```ts
564
+ * pipe([1, 2, 3, 4], Arr.splitAt(2)); // [[1, 2], [3, 4]]
565
+ * pipe([1, 2, 3], Arr.splitAt(0)); // [[], [1, 2, 3]]
566
+ * pipe([1, 2, 3], Arr.splitAt(10)); // [[1, 2, 3], []]
567
+ * ```
568
+ */
569
+ Arr.splitAt = (index) => (data) => {
570
+ const i = Math.max(0, index);
571
+ return [data.slice(0, i), data.slice(i)];
572
+ };
501
573
  })(Arr || (exports.Arr = Arr = {}));
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Num = void 0;
4
+ const Option_js_1 = require("../Core/Option.js");
5
+ /**
6
+ * Number utilities for common operations. All transformation functions are data-last
7
+ * and curried so they compose naturally with `pipe` and `Arr.map`.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { Num } from "@nlozgachev/pipelined/utils";
12
+ * import { pipe } from "@nlozgachev/pipelined/composition";
13
+ *
14
+ * pipe(
15
+ * Num.range(1, 6),
16
+ * Arr.map(Num.multiply(2)),
17
+ * Arr.filter(Num.between(4, 8))
18
+ * ); // [4, 6, 8]
19
+ * ```
20
+ */
21
+ var Num;
22
+ (function (Num) {
23
+ /**
24
+ * Generates an array of numbers from `from` to `to` (both inclusive),
25
+ * stepping by `step` (default `1`). If `step` is negative or zero, or `from > to`,
26
+ * returns an empty array. When `step` does not land exactly on `to`, the last value
27
+ * is the largest reachable value that does not exceed `to`.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * Num.range(0, 5); // [0, 1, 2, 3, 4, 5]
32
+ * Num.range(0, 10, 2); // [0, 2, 4, 6, 8, 10]
33
+ * Num.range(0, 9, 2); // [0, 2, 4, 6, 8]
34
+ * Num.range(5, 0); // []
35
+ * Num.range(3, 3); // [3]
36
+ * ```
37
+ */
38
+ Num.range = (from, to, step = 1) => {
39
+ if (step <= 0 || from > to)
40
+ return [];
41
+ const count = Math.floor((to - from) / step) + 1;
42
+ const result = new Array(count);
43
+ for (let i = 0; i < count; i++) {
44
+ result[i] = from + i * step;
45
+ }
46
+ return result;
47
+ };
48
+ /**
49
+ * Clamps a number between `min` and `max` (both inclusive).
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * pipe(150, Num.clamp(0, 100)); // 100
54
+ * pipe(-5, Num.clamp(0, 100)); // 0
55
+ * pipe(42, Num.clamp(0, 100)); // 42
56
+ * ```
57
+ */
58
+ Num.clamp = (min, max) => (n) => Math.min(Math.max(n, min), max);
59
+ /**
60
+ * Returns `true` when the number is between `min` and `max` (both inclusive).
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * pipe(5, Num.between(1, 10)); // true
65
+ * pipe(0, Num.between(1, 10)); // false
66
+ * pipe(10, Num.between(1, 10)); // true
67
+ * ```
68
+ */
69
+ Num.between = (min, max) => (n) => n >= min && n <= max;
70
+ /**
71
+ * Parses a string as a number. Returns `None` when the result is `NaN`.
72
+ *
73
+ * @example
74
+ * ```ts
75
+ * Num.parse("42"); // Some(42)
76
+ * Num.parse("3.14"); // Some(3.14)
77
+ * Num.parse("abc"); // None
78
+ * Num.parse(""); // None
79
+ * ```
80
+ */
81
+ Num.parse = (s) => {
82
+ if (s.trim() === "")
83
+ return Option_js_1.Option.none();
84
+ const n = Number(s);
85
+ return isNaN(n) ? Option_js_1.Option.none() : Option_js_1.Option.some(n);
86
+ };
87
+ /**
88
+ * Adds `b` to a number. Data-last: use in `pipe` or `Arr.map`.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * pipe(5, Num.add(3)); // 8
93
+ * pipe([1, 2, 3], Arr.map(Num.add(10))); // [11, 12, 13]
94
+ * ```
95
+ */
96
+ Num.add = (b) => (a) => a + b;
97
+ /**
98
+ * Subtracts `b` from a number. Data-last: `subtract(b)(a)` = `a - b`.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * pipe(10, Num.subtract(3)); // 7
103
+ * pipe([5, 10, 15], Arr.map(Num.subtract(2))); // [3, 8, 13]
104
+ * ```
105
+ */
106
+ Num.subtract = (b) => (a) => a - b;
107
+ /**
108
+ * Multiplies a number by `b`. Data-last: use in `pipe` or `Arr.map`.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * pipe(6, Num.multiply(7)); // 42
113
+ * pipe([1, 2, 3], Arr.map(Num.multiply(100))); // [100, 200, 300]
114
+ * ```
115
+ */
116
+ Num.multiply = (b) => (a) => a * b;
117
+ /**
118
+ * Divides a number by `b`. Data-last: `divide(b)(a)` = `a / b`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * pipe(20, Num.divide(4)); // 5
123
+ * pipe([10, 20, 30], Arr.map(Num.divide(10))); // [1, 2, 3]
124
+ * ```
125
+ */
126
+ Num.divide = (b) => (a) => a / b;
127
+ })(Num || (exports.Num = Num = {}));