@dangayle/rustlike 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +864 -0
- package/dist/async-iter-1OXm1ncF.d.mts +468 -0
- package/dist/async-iter-1OXm1ncF.d.mts.map +1 -0
- package/dist/async-iter-3iu4aRtf.cjs +1129 -0
- package/dist/async-iter-3iu4aRtf.cjs.map +1 -0
- package/dist/async-iter-D7Pj6knS.d.cts +468 -0
- package/dist/async-iter-D7Pj6knS.d.cts.map +1 -0
- package/dist/async-iter-aLdg-qp2.mjs +1009 -0
- package/dist/async-iter-aLdg-qp2.mjs.map +1 -0
- package/dist/index.cjs +477 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +342 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +342 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +443 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node.cjs +118 -0
- package/dist/node.cjs.map +1 -0
- package/dist/node.d.cts +46 -0
- package/dist/node.d.cts.map +1 -0
- package/dist/node.d.mts +46 -0
- package/dist/node.d.mts.map +1 -0
- package/dist/node.mjs +87 -0
- package/dist/node.mjs.map +1 -0
- package/package.json +80 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { _ as isNone, a as asyncIterFromIterable, b as toPanicString, c as iterFromArray, d as None, f as Ok, g as isErr, h as Some, i as asyncIterFromGenerator, l as iterFromGenerator, m as Result, n as asyncIter, o as Iter, p as Option, r as asyncIterFromArray, s as iter, t as AsyncIter, u as Err, v as isOk, y as isSome } from "./async-iter-aLdg-qp2.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/async.ts
|
|
4
|
+
/**
|
|
5
|
+
* AsyncResult<T, E> - Handling asynchronous Results chaining
|
|
6
|
+
*/
|
|
7
|
+
var AsyncResult = class AsyncResult {
|
|
8
|
+
constructor(promise) {
|
|
9
|
+
this.promise = promise;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create an AsyncResult from a Promise<Result<T, E>>
|
|
13
|
+
*/
|
|
14
|
+
static fromPromise(promise) {
|
|
15
|
+
return new AsyncResult(promise);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create an AsyncResult that resolves to Ok(value)
|
|
19
|
+
*/
|
|
20
|
+
static ok(value) {
|
|
21
|
+
return new AsyncResult(Promise.resolve(Ok(value)));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create an AsyncResult that resolves to Err(error)
|
|
25
|
+
*/
|
|
26
|
+
static err(error) {
|
|
27
|
+
return new AsyncResult(Promise.resolve(Err(error)));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Wrap an async function that might reject into an AsyncResult.
|
|
31
|
+
* This is the async equivalent of Result.fromThrowable().
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const result = await AsyncResult.fromThrowable(() => fetch('/api/users'));
|
|
35
|
+
* // AsyncResult<Response, unknown>
|
|
36
|
+
*/
|
|
37
|
+
static fromThrowable(fn) {
|
|
38
|
+
try {
|
|
39
|
+
return new AsyncResult(fn().then((value) => Ok(value)).catch((error) => Err(error)));
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return new AsyncResult(Promise.resolve(Err(e)));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Map the inner Ok value using a synchronous or asynchronous function.
|
|
46
|
+
* If the function returns a Promise, it is awaited.
|
|
47
|
+
*/
|
|
48
|
+
map(fn) {
|
|
49
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
50
|
+
if (res.isErr()) return res;
|
|
51
|
+
return Ok(await fn(res.value));
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Map the inner Err value using a synchronous or asynchronous function.
|
|
56
|
+
*/
|
|
57
|
+
mapErr(fn) {
|
|
58
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
59
|
+
if (res.isOk()) return res;
|
|
60
|
+
return Err(await fn(res.error));
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Chain another Result-returning operation (sync or async).
|
|
65
|
+
* Supports returning: Result, AsyncResult, or Promise<Result>.
|
|
66
|
+
*/
|
|
67
|
+
andThen(fn) {
|
|
68
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
69
|
+
if (res.isErr()) return res;
|
|
70
|
+
const next = fn(res.value);
|
|
71
|
+
if (next instanceof AsyncResult) return await next.toPromise();
|
|
72
|
+
return await next;
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle the error case with another Result-returning operation.
|
|
77
|
+
*/
|
|
78
|
+
orElse(fn) {
|
|
79
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
80
|
+
if (res.isOk()) return res;
|
|
81
|
+
const next = fn(res.error);
|
|
82
|
+
if (next instanceof AsyncResult) return await next.toPromise();
|
|
83
|
+
return await next;
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Inspect the Ok value if present, without modifying it.
|
|
88
|
+
* The callback can be synchronous or asynchronous.
|
|
89
|
+
*/
|
|
90
|
+
inspect(fn) {
|
|
91
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
92
|
+
if (res.isOk()) await fn(res.value);
|
|
93
|
+
return res;
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Inspect the Err value if present, without modifying it.
|
|
98
|
+
* The callback can be synchronous or asynchronous.
|
|
99
|
+
*/
|
|
100
|
+
inspectErr(fn) {
|
|
101
|
+
return new AsyncResult(this.promise.then(async (res) => {
|
|
102
|
+
if (res.isErr()) await fn(res.error);
|
|
103
|
+
return res;
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Pattern match on the result (async).
|
|
108
|
+
*/
|
|
109
|
+
match(handlers) {
|
|
110
|
+
return this.promise.then((res) => res.match(handlers));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Unwrap the value or throw (reject).
|
|
114
|
+
*/
|
|
115
|
+
async unwrap() {
|
|
116
|
+
return (await this.promise).unwrap();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Unwrap or return default.
|
|
120
|
+
*/
|
|
121
|
+
async unwrapOr(defaultValue) {
|
|
122
|
+
return (await this.promise).unwrapOr(defaultValue);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Unwrap or compute default.
|
|
126
|
+
*/
|
|
127
|
+
async unwrapOrElse(fn) {
|
|
128
|
+
const res = await this.promise;
|
|
129
|
+
if (res.isOk()) return res.value;
|
|
130
|
+
return await fn(res.error);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Returns true if the result is Ok and contains the given value.
|
|
134
|
+
*/
|
|
135
|
+
contains(value) {
|
|
136
|
+
return this.promise.then((r) => r.contains(value));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Returns true if the result is Err and contains the given error.
|
|
140
|
+
*/
|
|
141
|
+
containsErr(error) {
|
|
142
|
+
return this.promise.then((r) => r.containsErr(error));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Returns `other` if the result is Ok, otherwise returns the Err value of self.
|
|
146
|
+
*/
|
|
147
|
+
and(other) {
|
|
148
|
+
return new AsyncResult(this.promise.then((r) => r.isOk() ? other.promise : Promise.resolve(r)));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns `other` if the result is Err, otherwise returns the Ok value of self.
|
|
152
|
+
*/
|
|
153
|
+
or(other) {
|
|
154
|
+
return new AsyncResult(this.promise.then((r) => r.isErr() ? other.promise : Promise.resolve(r)));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Converts from AsyncResult<Result<U, E>, E> to AsyncResult<U, E>.
|
|
158
|
+
*/
|
|
159
|
+
flatten() {
|
|
160
|
+
return new AsyncResult(this.promise.then((r) => r.flatten()));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Converts from Result<T, E> to Option<T>, discarding the error if any.
|
|
164
|
+
*/
|
|
165
|
+
toOption() {
|
|
166
|
+
return this.promise.then((r) => r.toOption());
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Converts from Result<T, E> to Option<E>, discarding the success value if any.
|
|
170
|
+
*/
|
|
171
|
+
err() {
|
|
172
|
+
return this.promise.then((r) => r.err());
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Returns the contained Ok value, or throws with the provided message.
|
|
176
|
+
*/
|
|
177
|
+
expect(message) {
|
|
178
|
+
return this.promise.then((r) => r.expect(message));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Returns the contained Err value, or throws if Ok.
|
|
182
|
+
*/
|
|
183
|
+
unwrapErr() {
|
|
184
|
+
return this.promise.then((r) => r.unwrapErr());
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns the contained Err value, or throws with the provided message.
|
|
188
|
+
*/
|
|
189
|
+
expectErr(message) {
|
|
190
|
+
return this.promise.then((r) => r.expectErr(message));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get the underlying Promise<Result<T, E>>
|
|
194
|
+
*/
|
|
195
|
+
toPromise() {
|
|
196
|
+
return this.promise;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Implement PromiseLike to allow `await asyncResult`
|
|
200
|
+
*/
|
|
201
|
+
then(onfulfilled, onrejected) {
|
|
202
|
+
return this.promise.then(onfulfilled, onrejected);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/match.ts
|
|
208
|
+
/**
|
|
209
|
+
* Exhaustive pattern matching utilities
|
|
210
|
+
*
|
|
211
|
+
* Ensures all cases are handled in discriminated unions.
|
|
212
|
+
*/
|
|
213
|
+
/**
|
|
214
|
+
* Use in the default case of a switch to ensure exhaustiveness.
|
|
215
|
+
* If the switch is not exhaustive, TypeScript will error because
|
|
216
|
+
* the unhandled case type cannot be assigned to 'never'.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* type Shape = { kind: 'circle'; radius: number } | { kind: 'rect'; w: number; h: number };
|
|
220
|
+
*
|
|
221
|
+
* function area(s: Shape): number {
|
|
222
|
+
* switch (s.kind) {
|
|
223
|
+
* case 'circle': return Math.PI * s.radius ** 2;
|
|
224
|
+
* case 'rect': return s.w * s.h;
|
|
225
|
+
* default: return assertNever(s);
|
|
226
|
+
* }
|
|
227
|
+
* }
|
|
228
|
+
*/
|
|
229
|
+
function assertNever(x, message) {
|
|
230
|
+
if (message) throw new Error(message);
|
|
231
|
+
throw new Error(`Unexpected value: ${toPanicString(x)}`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Type-safe exhaustive matching for discriminated unions.
|
|
235
|
+
* Supports an optional catch-all '_' handler.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* type Action =
|
|
239
|
+
* | { type: 'increment'; amount: number }
|
|
240
|
+
* | { type: 'decrement'; amount: number }
|
|
241
|
+
* | { type: 'reset' };
|
|
242
|
+
*
|
|
243
|
+
* const result = match(action, 'type', {
|
|
244
|
+
* increment: (a) => state + a.amount,
|
|
245
|
+
* decrement: (a) => state - a.amount,
|
|
246
|
+
* reset: () => 0,
|
|
247
|
+
* });
|
|
248
|
+
*
|
|
249
|
+
* // With catch-all
|
|
250
|
+
* const result = match(action, 'type', {
|
|
251
|
+
* increment: (a) => state + a.amount,
|
|
252
|
+
* _: () => state // catch-all
|
|
253
|
+
* });
|
|
254
|
+
*/
|
|
255
|
+
function match(value, discriminant, handlers) {
|
|
256
|
+
const key = value[discriminant];
|
|
257
|
+
const handlersRecord = handlers;
|
|
258
|
+
const handler = handlersRecord[key];
|
|
259
|
+
if (handler) return handler(value);
|
|
260
|
+
const catchAll = handlersRecord._;
|
|
261
|
+
if (catchAll) return catchAll(value);
|
|
262
|
+
return assertNever(value, `Unhandled variant: ${key}`);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Match on a discriminated union using the 'kind' discriminant (common pattern).
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* type Shape =
|
|
269
|
+
* | { kind: 'circle'; radius: number }
|
|
270
|
+
* | { kind: 'rect'; w: number; h: number };
|
|
271
|
+
*
|
|
272
|
+
* const area = matchKind(shape, {
|
|
273
|
+
* circle: (s) => Math.PI * s.radius ** 2,
|
|
274
|
+
* rect: (s) => s.w * s.h,
|
|
275
|
+
* });
|
|
276
|
+
*
|
|
277
|
+
* // With catch-all
|
|
278
|
+
* const isCircle = matchKind(shape, {
|
|
279
|
+
* circle: () => true,
|
|
280
|
+
* _: () => false
|
|
281
|
+
* });
|
|
282
|
+
*/
|
|
283
|
+
function matchKind(value, handlers) {
|
|
284
|
+
return match(value, "kind", handlers);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Match on a discriminated union using the 'type' discriminant (common pattern).
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* type Action =
|
|
291
|
+
* | { type: 'add'; item: string }
|
|
292
|
+
* | { type: 'remove'; id: number };
|
|
293
|
+
*
|
|
294
|
+
* const result = matchType(action, {
|
|
295
|
+
* add: (a) => [...items, a.item],
|
|
296
|
+
* remove: (a) => items.filter((_, i) => i !== a.id),
|
|
297
|
+
* });
|
|
298
|
+
*/
|
|
299
|
+
function matchType(value, handlers) {
|
|
300
|
+
return match(value, "type", handlers);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/types.ts
|
|
305
|
+
/**
|
|
306
|
+
* Immutability and utility types for Rust-like TypeScript
|
|
307
|
+
*/
|
|
308
|
+
/**
|
|
309
|
+
* Create a branded type constructor
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* const UserId = brand<number, 'UserId'>();
|
|
313
|
+
* const id = UserId(42); // type is Brand<number, 'UserId'>
|
|
314
|
+
*/
|
|
315
|
+
const brand = () => (value) => value;
|
|
316
|
+
/**
|
|
317
|
+
* Check if array is non-empty (type guard)
|
|
318
|
+
*/
|
|
319
|
+
const isNonEmpty = (arr) => arr.length > 0;
|
|
320
|
+
/**
|
|
321
|
+
* Create a non-empty array from values
|
|
322
|
+
*/
|
|
323
|
+
const nonEmpty = (first, ...rest) => [first, ...rest];
|
|
324
|
+
/**
|
|
325
|
+
* Get the first element of a non-empty array (guaranteed to exist)
|
|
326
|
+
*/
|
|
327
|
+
const head = (arr) => arr[0];
|
|
328
|
+
/**
|
|
329
|
+
* Create a newtype with validation (Rust's newtype pattern + smart constructor).
|
|
330
|
+
* Implements the "parse, don't validate" pattern - make invalid states unrepresentable.
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* const EmailAddress = newtype<string, 'Email'>(
|
|
334
|
+
* (s) => s.includes('@'),
|
|
335
|
+
* "Invalid email"
|
|
336
|
+
* );
|
|
337
|
+
*
|
|
338
|
+
* const email = EmailAddress.parse(userInput);
|
|
339
|
+
* // Result<Brand<string, 'Email'>, string>
|
|
340
|
+
*
|
|
341
|
+
* @example
|
|
342
|
+
* const PositiveNumber = newtype<number, 'Positive'>(
|
|
343
|
+
* (n) => n > 0,
|
|
344
|
+
* (n) => `Expected positive, got ${n}`
|
|
345
|
+
* );
|
|
346
|
+
*/
|
|
347
|
+
const newtype = (validate, error) => {
|
|
348
|
+
const getError = (value) => {
|
|
349
|
+
if (typeof error === "function") return error(value);
|
|
350
|
+
return error;
|
|
351
|
+
};
|
|
352
|
+
return {
|
|
353
|
+
parse: (value) => {
|
|
354
|
+
if (validate(value)) return Ok(value);
|
|
355
|
+
return Err(getError(value));
|
|
356
|
+
},
|
|
357
|
+
unsafe: (value) => value
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
//#endregion
|
|
362
|
+
//#region src/interop.ts
|
|
363
|
+
/**
|
|
364
|
+
* Interop helpers for wrapping third-party and standard library code
|
|
365
|
+
*/
|
|
366
|
+
/**
|
|
367
|
+
* One-shot: wrap a single throwing operation in a Result.
|
|
368
|
+
* Use {@link safeTry} to create a reusable safe wrapper instead.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* const result = tryCatch(() => JSON.parse(userInput));
|
|
372
|
+
* // Result<unknown, unknown>
|
|
373
|
+
*/
|
|
374
|
+
const tryCatch = (fn) => {
|
|
375
|
+
try {
|
|
376
|
+
return Ok(fn());
|
|
377
|
+
} catch (e) {
|
|
378
|
+
return Err(e);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Wrap any async function that might reject to return Result
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* const result = await tryAsync(() => axios.get('/api/users'));
|
|
386
|
+
* // Result<AxiosResponse, AxiosError>
|
|
387
|
+
*/
|
|
388
|
+
const tryAsync = async (fn) => {
|
|
389
|
+
try {
|
|
390
|
+
return Ok(await fn());
|
|
391
|
+
} catch (e) {
|
|
392
|
+
return Err(e);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
/**
|
|
396
|
+
* Create a reusable Option-returning version of any function that may return
|
|
397
|
+
* T | null | undefined or throw. Returns None on null, undefined, or throw.
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* const safeFind = safeCall((id: number) => users.find(u => u.id === id));
|
|
401
|
+
* const user = safeFind(42); // Option<User>
|
|
402
|
+
*/
|
|
403
|
+
const safeCall = (fn) => (...args) => {
|
|
404
|
+
try {
|
|
405
|
+
return Option.from(fn(...args));
|
|
406
|
+
} catch {
|
|
407
|
+
return None;
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
/**
|
|
411
|
+
* Create a reusable Option-returning version of any async function that may return
|
|
412
|
+
* T | null | undefined or reject. Returns None on null, undefined, or rejection.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* const safeFetch = safeCallAsync((url: string) => fetch(url).then(r => r.ok ? r : null));
|
|
416
|
+
* const response = await safeFetch('/api'); // Option<Response>
|
|
417
|
+
*/
|
|
418
|
+
const safeCallAsync = (fn) => async (...args) => {
|
|
419
|
+
try {
|
|
420
|
+
return Option.from(await fn(...args));
|
|
421
|
+
} catch {
|
|
422
|
+
return None;
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* Reusable: wrap a throwing function so every call returns a Result.
|
|
427
|
+
* Use {@link tryCatch} for one-shot operations instead.
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* const safeJsonParse = safeTry(JSON.parse);
|
|
431
|
+
* const data = safeJsonParse(input); // Result<unknown, unknown>
|
|
432
|
+
*/
|
|
433
|
+
const safeTry = (fn) => (...args) => {
|
|
434
|
+
try {
|
|
435
|
+
return Ok(fn(...args));
|
|
436
|
+
} catch (e) {
|
|
437
|
+
return Err(e);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
//#endregion
|
|
442
|
+
export { AsyncIter, AsyncResult, Err, Iter, None, Ok, Option, Result, Some, assertNever, asyncIter, asyncIterFromArray, asyncIterFromGenerator, asyncIterFromIterable, brand, head, isErr, isNonEmpty, isNone, isOk, isSome, iter, iterFromArray, iterFromGenerator, match, matchKind, matchType, newtype, nonEmpty, safeCall, safeCallAsync, safeTry, tryAsync, tryCatch };
|
|
443
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/async.ts","../src/match.ts","../src/types.ts","../src/interop.ts"],"sourcesContent":["/**\n * AsyncResult<T, E> - Handling asynchronous Results chaining\n */\n\nimport { Result, Ok, Err, Option } from \"./core\";\n\nexport class AsyncResult<T, E> implements PromiseLike<Result<T, E>> {\n constructor(private readonly promise: Promise<Result<T, E>>) {}\n\n /**\n * Create an AsyncResult from a Promise<Result<T, E>>\n */\n static fromPromise<T, E>(promise: Promise<Result<T, E>>): AsyncResult<T, E> {\n return new AsyncResult(promise);\n }\n\n /**\n * Create an AsyncResult that resolves to Ok(value)\n */\n static ok<T, E = never>(value: T): AsyncResult<T, E> {\n return new AsyncResult(Promise.resolve(Ok(value)));\n }\n\n /**\n * Create an AsyncResult that resolves to Err(error)\n */\n static err<E, T = never>(error: E): AsyncResult<T, E> {\n return new AsyncResult(Promise.resolve(Err(error)));\n }\n\n /**\n * Wrap an async function that might reject into an AsyncResult.\n * This is the async equivalent of Result.fromThrowable().\n *\n * @example\n * const result = await AsyncResult.fromThrowable(() => fetch('/api/users'));\n * // AsyncResult<Response, unknown>\n */\n static fromThrowable<T, E = unknown>(fn: () => Promise<T>): AsyncResult<T, E> {\n try {\n return new AsyncResult(\n fn()\n .then((value) => Ok(value) as Result<T, E>)\n // Cast: TypeScript catch blocks type errors as `unknown`. The caller\n // narrows via the E parameter (defaulting to `unknown`).\n .catch((error: unknown) => Err(error as E) as Result<T, E>),\n );\n } catch (e) {\n return new AsyncResult(Promise.resolve(Err(e as E) as Result<T, E>));\n }\n }\n\n /**\n * Map the inner Ok value using a synchronous or asynchronous function.\n * If the function returns a Promise, it is awaited.\n */\n map<U>(fn: (value: T) => U | Promise<U>): AsyncResult<U, E> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isErr()) return res as unknown as Result<U, E>;\n // If the mapping function throws, we let Promise rejection propagate\n // to stay consistent with sync map throwing (Rust panics on map errors).\n const value = await fn(res.value);\n return Ok(value);\n }),\n );\n }\n\n /**\n * Map the inner Err value using a synchronous or asynchronous function.\n */\n mapErr<F>(fn: (error: E) => F | Promise<F>): AsyncResult<T, F> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isOk()) return res as unknown as Result<T, F>;\n const error = await fn(res.error);\n return Err(error);\n }),\n );\n }\n\n /**\n * Chain another Result-returning operation (sync or async).\n * Supports returning: Result, AsyncResult, or Promise<Result>.\n */\n andThen<U>(\n fn: (value: T) => Result<U, E> | AsyncResult<U, E> | Promise<Result<U, E>>,\n ): AsyncResult<U, E> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isErr()) return res as unknown as Result<U, E>;\n\n const next = fn(res.value);\n if (next instanceof AsyncResult) {\n return await next.toPromise();\n }\n return await next;\n }),\n );\n }\n\n /**\n * Handle the error case with another Result-returning operation.\n */\n orElse<F>(\n fn: (error: E) => Result<T, F> | AsyncResult<T, F> | Promise<Result<T, F>>,\n ): AsyncResult<T, F> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isOk()) return res as unknown as Result<T, F>;\n\n const next = fn(res.error);\n if (next instanceof AsyncResult) {\n return await next.toPromise();\n }\n return await next;\n }),\n );\n }\n\n /**\n * Inspect the Ok value if present, without modifying it.\n * The callback can be synchronous or asynchronous.\n */\n inspect(fn: (value: T) => void | Promise<void>): AsyncResult<T, E> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isOk()) {\n await fn(res.value);\n }\n return res;\n }),\n );\n }\n\n /**\n * Inspect the Err value if present, without modifying it.\n * The callback can be synchronous or asynchronous.\n */\n inspectErr(fn: (error: E) => void | Promise<void>): AsyncResult<T, E> {\n return new AsyncResult(\n this.promise.then(async (res) => {\n if (res.isErr()) {\n await fn(res.error);\n }\n return res;\n }),\n );\n }\n\n /**\n * Pattern match on the result (async).\n */\n match<U>(handlers: {\n ok: (value: T) => U | Promise<U>;\n err: (error: E) => U | Promise<U>;\n }): Promise<U> {\n return this.promise.then((res) => res.match(handlers));\n }\n\n /**\n * Unwrap the value or throw (reject).\n */\n async unwrap(): Promise<T> {\n const res = await this.promise;\n return res.unwrap();\n }\n\n /**\n * Unwrap or return default.\n */\n async unwrapOr(defaultValue: T): Promise<T> {\n const res = await this.promise;\n return res.unwrapOr(defaultValue);\n }\n\n /**\n * Unwrap or compute default.\n */\n async unwrapOrElse(fn: (error: E) => T | Promise<T>): Promise<T> {\n const res = await this.promise;\n if (res.isOk()) return res.value;\n return await fn(res.error);\n }\n\n /**\n * Returns true if the result is Ok and contains the given value.\n */\n contains(value: T): Promise<boolean> {\n return this.promise.then((r) => r.contains(value));\n }\n\n /**\n * Returns true if the result is Err and contains the given error.\n */\n containsErr(error: E): Promise<boolean> {\n return this.promise.then((r) => r.containsErr(error));\n }\n\n /**\n * Returns `other` if the result is Ok, otherwise returns the Err value of self.\n */\n and<U>(other: AsyncResult<U, E>): AsyncResult<U, E> {\n return new AsyncResult(\n this.promise.then((r) =>\n r.isOk() ? other.promise : Promise.resolve(r as unknown as Result<U, E>),\n ),\n );\n }\n\n /**\n * Returns `other` if the result is Err, otherwise returns the Ok value of self.\n */\n or<F>(other: AsyncResult<T, F>): AsyncResult<T, F> {\n return new AsyncResult(\n this.promise.then((r) =>\n r.isErr() ? other.promise : Promise.resolve(r as unknown as Result<T, F>),\n ),\n );\n }\n\n /**\n * Converts from AsyncResult<Result<U, E>, E> to AsyncResult<U, E>.\n */\n flatten<U>(this: AsyncResult<Result<U, E>, E>): AsyncResult<U, E> {\n return new AsyncResult(this.promise.then((r) => r.flatten()));\n }\n\n /**\n * Converts from Result<T, E> to Option<T>, discarding the error if any.\n */\n toOption(): Promise<Option<T>> {\n return this.promise.then((r) => r.toOption());\n }\n\n /**\n * Converts from Result<T, E> to Option<E>, discarding the success value if any.\n */\n err(): Promise<Option<E>> {\n return this.promise.then((r) => r.err());\n }\n\n /**\n * Returns the contained Ok value, or throws with the provided message.\n */\n expect(message: string): Promise<T> {\n return this.promise.then((r) => r.expect(message));\n }\n\n /**\n * Returns the contained Err value, or throws if Ok.\n */\n unwrapErr(): Promise<E> {\n return this.promise.then((r) => r.unwrapErr());\n }\n\n /**\n * Returns the contained Err value, or throws with the provided message.\n */\n expectErr(message: string): Promise<E> {\n return this.promise.then((r) => r.expectErr(message));\n }\n\n /**\n * Get the underlying Promise<Result<T, E>>\n */\n toPromise(): Promise<Result<T, E>> {\n return this.promise;\n }\n\n /**\n * Implement PromiseLike to allow `await asyncResult`\n */\n then<TResult1 = Result<T, E>, TResult2 = never>(\n onfulfilled?: ((value: Result<T, E>) => TResult1 | PromiseLike<TResult1>) | null,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required by PromiseLike interface\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.promise.then(onfulfilled, onrejected);\n }\n}\n","/**\n * Exhaustive pattern matching utilities\n *\n * Ensures all cases are handled in discriminated unions.\n */\n\nimport { toPanicString } from \"./core\";\n\n/**\n * Use in the default case of a switch to ensure exhaustiveness.\n * If the switch is not exhaustive, TypeScript will error because\n * the unhandled case type cannot be assigned to 'never'.\n *\n * @example\n * type Shape = { kind: 'circle'; radius: number } | { kind: 'rect'; w: number; h: number };\n *\n * function area(s: Shape): number {\n * switch (s.kind) {\n * case 'circle': return Math.PI * s.radius ** 2;\n * case 'rect': return s.w * s.h;\n * default: return assertNever(s);\n * }\n * }\n */\nexport function assertNever(x: never, message?: string): never {\n if (message) {\n throw new Error(message);\n }\n throw new Error(`Unexpected value: ${toPanicString(x)}`);\n}\n\n/**\n * Type-safe exhaustive matching for discriminated unions.\n * Supports an optional catch-all '_' handler.\n *\n * @example\n * type Action =\n * | { type: 'increment'; amount: number }\n * | { type: 'decrement'; amount: number }\n * | { type: 'reset' };\n *\n * const result = match(action, 'type', {\n * increment: (a) => state + a.amount,\n * decrement: (a) => state - a.amount,\n * reset: () => 0,\n * });\n *\n * // With catch-all\n * const result = match(action, 'type', {\n * increment: (a) => state + a.amount,\n * _: () => state // catch-all\n * });\n */\nexport function match<T extends Record<K, string>, K extends keyof T, R>(\n value: T,\n discriminant: K,\n handlers:\n | { [P in T[K]]: (value: Extract<T, Record<K, P>>) => R }\n | ({ [P in T[K]]?: (value: Extract<T, Record<K, P>>) => R } & { _: (value: T) => R }),\n): R {\n const key = value[discriminant] as T[K];\n const handlersRecord = handlers as Record<PropertyKey, ((value: T) => R) | undefined>;\n const handler = handlersRecord[key];\n\n if (handler) {\n return handler(value);\n }\n\n const catchAll = handlersRecord._;\n if (catchAll) {\n return catchAll(value);\n }\n\n // This should be unreachable if types are correct\n return assertNever(value as never, `Unhandled variant: ${key}`);\n}\n\n/**\n * Match on a discriminated union using the 'kind' discriminant (common pattern).\n *\n * @example\n * type Shape =\n * | { kind: 'circle'; radius: number }\n * | { kind: 'rect'; w: number; h: number };\n *\n * const area = matchKind(shape, {\n * circle: (s) => Math.PI * s.radius ** 2,\n * rect: (s) => s.w * s.h,\n * });\n *\n * // With catch-all\n * const isCircle = matchKind(shape, {\n * circle: () => true,\n * _: () => false\n * });\n */\nexport function matchKind<T extends { kind: string }, R>(\n value: T,\n handlers:\n | { [P in T[\"kind\"]]: (value: Extract<T, { kind: P }>) => R }\n | ({ [P in T[\"kind\"]]?: (value: Extract<T, { kind: P }>) => R } & { _: (value: T) => R }),\n): R {\n return match(\n value,\n \"kind\",\n handlers as { [P in T[\"kind\"]]: (value: Extract<T, Record<\"kind\", P>>) => R },\n );\n}\n\n/**\n * Match on a discriminated union using the 'type' discriminant (common pattern).\n *\n * @example\n * type Action =\n * | { type: 'add'; item: string }\n * | { type: 'remove'; id: number };\n *\n * const result = matchType(action, {\n * add: (a) => [...items, a.item],\n * remove: (a) => items.filter((_, i) => i !== a.id),\n * });\n */\nexport function matchType<T extends { type: string }, R>(\n value: T,\n handlers:\n | { [P in T[\"type\"]]: (value: Extract<T, { type: P }>) => R }\n | ({ [P in T[\"type\"]]?: (value: Extract<T, { type: P }>) => R } & { _: (value: T) => R }),\n): R {\n return match(\n value,\n \"type\",\n handlers as { [P in T[\"type\"]]: (value: Extract<T, Record<\"type\", P>>) => R },\n );\n}\n","/**\n * Immutability and utility types for Rust-like TypeScript\n */\n\nimport { Result, Ok, Err } from \"./core\";\n\n/**\n * Recursively make all properties readonly (deep immutability)\n */\nexport type DeepReadonly<T> = T extends (infer U)[]\n ? readonly DeepReadonly<U>[]\n : T extends Map<infer K, infer V>\n ? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>\n : T extends Set<infer U>\n ? ReadonlySet<DeepReadonly<U>>\n : T extends object\n ? { readonly [P in keyof T]: DeepReadonly<T[P]> }\n : T;\n\n/**\n * Make specific properties readonly\n */\nexport type ReadonlyPick<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>;\n\n/**\n * Branded type for nominal typing (like Rust's newtype pattern)\n *\n * @example\n * type UserId = Brand<number, 'UserId'>;\n * type OrderId = Brand<number, 'OrderId'>;\n *\n * // These are now incompatible even though both are numbers\n * const userId: UserId = 1 as UserId;\n * const orderId: OrderId = userId; // Error!\n */\nexport type Brand<T, B> = T & { readonly __brand: B };\n\n/**\n * Create a branded type constructor\n *\n * @example\n * const UserId = brand<number, 'UserId'>();\n * const id = UserId(42); // type is Brand<number, 'UserId'>\n */\nexport const brand =\n <T, B>() =>\n (value: T): Brand<T, B> =>\n value as Brand<T, B>;\n\n/**\n * NonEmpty array type - guarantees at least one element\n */\nexport type NonEmptyArray<T> = readonly [T, ...T[]];\n\n/**\n * Check if array is non-empty (type guard)\n */\nexport const isNonEmpty = <T>(arr: readonly T[]): arr is NonEmptyArray<T> => arr.length > 0;\n\n/**\n * Create a non-empty array from values\n */\nexport const nonEmpty = <T>(first: T, ...rest: T[]): NonEmptyArray<T> => [first, ...rest];\n\n/**\n * Get the first element of a non-empty array (guaranteed to exist)\n */\nexport const head = <T>(arr: NonEmptyArray<T>): T => arr[0];\n\n/**\n * Create a newtype with validation (Rust's newtype pattern + smart constructor).\n * Implements the \"parse, don't validate\" pattern - make invalid states unrepresentable.\n *\n * @example\n * const EmailAddress = newtype<string, 'Email'>(\n * (s) => s.includes('@'),\n * \"Invalid email\"\n * );\n *\n * const email = EmailAddress.parse(userInput);\n * // Result<Brand<string, 'Email'>, string>\n *\n * @example\n * const PositiveNumber = newtype<number, 'Positive'>(\n * (n) => n > 0,\n * (n) => `Expected positive, got ${n}`\n * );\n */\nexport const newtype = <T, B, E = string>(\n validate: (value: T) => boolean,\n error: E | ((value: T) => E),\n): {\n parse: (value: T) => Result<Brand<T, B>, E>;\n unsafe: (value: T) => Brand<T, B>;\n} => {\n const getError = (value: T): E => {\n if (typeof error === \"function\") {\n return (error as (value: T) => E)(value);\n }\n return error;\n };\n\n return {\n /**\n * Parse and validate the input, returning a Result with the branded type on success.\n */\n parse: (value: T): Result<Brand<T, B>, E> => {\n if (validate(value)) {\n return Ok(value as Brand<T, B>);\n }\n return Err(getError(value));\n },\n\n /**\n * Unsafely cast a value to the branded type without validation.\n * Use only when you know the value is valid (e.g., from a trusted source).\n */\n unsafe: (value: T): Brand<T, B> => value as Brand<T, B>,\n };\n};\n","/**\n * Interop helpers for wrapping third-party and standard library code\n */\n\nimport { Option, None, Result, Ok, Err } from \"./core\";\n\n/**\n * One-shot: wrap a single throwing operation in a Result.\n * Use {@link safeTry} to create a reusable safe wrapper instead.\n *\n * @example\n * const result = tryCatch(() => JSON.parse(userInput));\n * // Result<unknown, unknown>\n */\nexport const tryCatch = <T, E = unknown>(fn: () => T): Result<T, E> => {\n try {\n return Ok(fn());\n } catch (e) {\n // Cast: TypeScript catch blocks type errors as `unknown`. The caller\n // narrows via the E parameter (defaulting to `unknown`). This is safe\n // because the caller opts into the cast by specifying E.\n return Err(e as E);\n }\n};\n\n/**\n * Wrap any async function that might reject to return Result\n *\n * @example\n * const result = await tryAsync(() => axios.get('/api/users'));\n * // Result<AxiosResponse, AxiosError>\n */\nexport const tryAsync = async <T, E = unknown>(fn: () => Promise<T>): Promise<Result<T, E>> => {\n try {\n return Ok(await fn());\n } catch (e) {\n // Cast: see tryCatch — caller narrows E via the type parameter.\n return Err(e as E);\n }\n};\n\n/**\n * Create a reusable Option-returning version of any function that may return\n * T | null | undefined or throw. Returns None on null, undefined, or throw.\n *\n * @example\n * const safeFind = safeCall((id: number) => users.find(u => u.id === id));\n * const user = safeFind(42); // Option<User>\n */\nexport const safeCall =\n <Args extends unknown[], T>(fn: (...args: Args) => T | null | undefined) =>\n (...args: Args): Option<T> => {\n try {\n return Option.from(fn(...args));\n } catch {\n return None;\n }\n };\n\n/**\n * Create a reusable Option-returning version of any async function that may return\n * T | null | undefined or reject. Returns None on null, undefined, or rejection.\n *\n * @example\n * const safeFetch = safeCallAsync((url: string) => fetch(url).then(r => r.ok ? r : null));\n * const response = await safeFetch('/api'); // Option<Response>\n */\nexport const safeCallAsync =\n <Args extends unknown[], T>(fn: (...args: Args) => Promise<T | null | undefined>) =>\n async (...args: Args): Promise<Option<T>> => {\n try {\n return Option.from(await fn(...args));\n } catch {\n return None;\n }\n };\n\n/**\n * Reusable: wrap a throwing function so every call returns a Result.\n * Use {@link tryCatch} for one-shot operations instead.\n *\n * @example\n * const safeJsonParse = safeTry(JSON.parse);\n * const data = safeJsonParse(input); // Result<unknown, unknown>\n */\nexport const safeTry =\n <Args extends unknown[], T, E = unknown>(fn: (...args: Args) => T) =>\n (...args: Args): Result<T, E> => {\n try {\n return Ok(fn(...args));\n } catch (e) {\n // Cast: see tryCatch — caller narrows E via the type parameter.\n return Err(e as E);\n }\n };\n"],"mappings":"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"}
|
package/dist/node.cjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
const require_async_iter = require('./async-iter-3iu4aRtf.cjs');
|
|
30
|
+
let fs = require("fs");
|
|
31
|
+
fs = __toESM(fs);
|
|
32
|
+
let readline = require("readline");
|
|
33
|
+
readline = __toESM(readline);
|
|
34
|
+
|
|
35
|
+
//#region src/node.ts
|
|
36
|
+
/**
|
|
37
|
+
* Node.js-specific utilities for rustlike.
|
|
38
|
+
*
|
|
39
|
+
* This module contains functions that depend on Node.js built-in modules
|
|
40
|
+
* (fs, readline) and should only be imported in Node.js environments.
|
|
41
|
+
* Browser and edge runtime consumers should use the main 'rustlike' entry point.
|
|
42
|
+
*
|
|
43
|
+
* Import from 'rustlike/node' to access these functions.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* Create an Iter that lazily reads lines from a file.
|
|
47
|
+
* Uses Node.js fs.readFileSync but yields lines lazily via generator.
|
|
48
|
+
*
|
|
49
|
+
* Note: This reads the entire file into memory but yields lines lazily.
|
|
50
|
+
* For truly streaming line-by-line reading, use asyncIterLines.
|
|
51
|
+
*
|
|
52
|
+
* @param filepath - Path to the file to read
|
|
53
|
+
* @returns Result with Iter<string> on success, error message on failure
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const lines = iterLinesSync('data.txt');
|
|
57
|
+
* lines.match({
|
|
58
|
+
* ok: (iter) => iter.skip(1).map(parseLine).collect(),
|
|
59
|
+
* err: (e) => console.error(e)
|
|
60
|
+
* });
|
|
61
|
+
*/
|
|
62
|
+
function iterLinesSync(filepath) {
|
|
63
|
+
try {
|
|
64
|
+
const lines = fs.readFileSync(filepath, "utf-8").split("\n");
|
|
65
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
66
|
+
return require_async_iter.Ok(require_async_iter.iter(lines));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error instanceof Error) return require_async_iter.Err(`Failed to read file '${filepath}': ${error.message}`);
|
|
69
|
+
return require_async_iter.Err(`Failed to read file '${filepath}': ${String(error)}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create an AsyncIter that reads lines from a file using streaming.
|
|
74
|
+
* Truly memory-efficient - reads lines on-demand without loading entire file.
|
|
75
|
+
*
|
|
76
|
+
* Uses Node.js readline with createReadStream for efficient streaming.
|
|
77
|
+
*
|
|
78
|
+
* @param filepath - Path to the file to read
|
|
79
|
+
* @returns Promise of Result with AsyncIter<string> on success, error message on failure
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const result = await asyncIterLines('large-log.txt');
|
|
83
|
+
* result.match({
|
|
84
|
+
* ok: async (iter) => {
|
|
85
|
+
* const errors = await iter
|
|
86
|
+
* .filter(line => line.includes('ERROR'))
|
|
87
|
+
* .take(100)
|
|
88
|
+
* .collect();
|
|
89
|
+
* },
|
|
90
|
+
* err: (e) => console.error(e)
|
|
91
|
+
* });
|
|
92
|
+
*/
|
|
93
|
+
async function asyncIterLines(filepath) {
|
|
94
|
+
try {
|
|
95
|
+
await fs.promises.access(filepath, fs.constants.R_OK);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error instanceof Error) return require_async_iter.Err(`Failed to access file '${filepath}': ${error.message}`);
|
|
98
|
+
return require_async_iter.Err(`Failed to access file '${filepath}': ${String(error)}`);
|
|
99
|
+
}
|
|
100
|
+
return require_async_iter.Ok(require_async_iter.asyncIter((async function* () {
|
|
101
|
+
const fileStream = fs.createReadStream(filepath, { encoding: "utf-8" });
|
|
102
|
+
const rl = readline.createInterface({
|
|
103
|
+
input: fileStream,
|
|
104
|
+
crlfDelay: Infinity
|
|
105
|
+
});
|
|
106
|
+
try {
|
|
107
|
+
for await (const line of rl) yield line;
|
|
108
|
+
} finally {
|
|
109
|
+
rl.close();
|
|
110
|
+
fileStream.destroy();
|
|
111
|
+
}
|
|
112
|
+
})()));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
exports.asyncIterLines = asyncIterLines;
|
|
117
|
+
exports.iterLinesSync = iterLinesSync;
|
|
118
|
+
//# sourceMappingURL=node.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.cjs","names":["Ok","iter","Err","asyncIter"],"sources":["../src/node.ts"],"sourcesContent":["/**\n * Node.js-specific utilities for rustlike.\n *\n * This module contains functions that depend on Node.js built-in modules\n * (fs, readline) and should only be imported in Node.js environments.\n * Browser and edge runtime consumers should use the main 'rustlike' entry point.\n *\n * Import from 'rustlike/node' to access these functions.\n */\n\nimport * as fs from \"fs\";\nimport * as readline from \"readline\";\nimport { Result, Ok, Err } from \"./core\";\nimport { iter } from \"./iter\";\nimport { asyncIter } from \"./async-iter\";\nimport type { Iter } from \"./iter\";\nimport type { AsyncIter } from \"./async-iter\";\n\n// ============================================================================\n// File Reading (Sync)\n// ============================================================================\n\n/**\n * Create an Iter that lazily reads lines from a file.\n * Uses Node.js fs.readFileSync but yields lines lazily via generator.\n *\n * Note: This reads the entire file into memory but yields lines lazily.\n * For truly streaming line-by-line reading, use asyncIterLines.\n *\n * @param filepath - Path to the file to read\n * @returns Result with Iter<string> on success, error message on failure\n *\n * @example\n * const lines = iterLinesSync('data.txt');\n * lines.match({\n * ok: (iter) => iter.skip(1).map(parseLine).collect(),\n * err: (e) => console.error(e)\n * });\n */\nexport function iterLinesSync(filepath: string): Result<Iter<string>, string> {\n try {\n const content = fs.readFileSync(filepath, \"utf-8\");\n const lines = content.split(\"\\n\");\n // Remove trailing empty line if file ends with newline\n if (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n return Ok(iter(lines));\n } catch (error) {\n if (error instanceof Error) {\n return Err(`Failed to read file '${filepath}': ${error.message}`);\n }\n return Err(`Failed to read file '${filepath}': ${String(error)}`);\n }\n}\n\n// ============================================================================\n// File Reading (Async)\n// ============================================================================\n\n/**\n * Create an AsyncIter that reads lines from a file using streaming.\n * Truly memory-efficient - reads lines on-demand without loading entire file.\n *\n * Uses Node.js readline with createReadStream for efficient streaming.\n *\n * @param filepath - Path to the file to read\n * @returns Promise of Result with AsyncIter<string> on success, error message on failure\n *\n * @example\n * const result = await asyncIterLines('large-log.txt');\n * result.match({\n * ok: async (iter) => {\n * const errors = await iter\n * .filter(line => line.includes('ERROR'))\n * .take(100)\n * .collect();\n * },\n * err: (e) => console.error(e)\n * });\n */\nexport async function asyncIterLines(filepath: string): Promise<Result<AsyncIter<string>, string>> {\n // Check if file exists first\n try {\n await fs.promises.access(filepath, fs.constants.R_OK);\n } catch (error) {\n if (error instanceof Error) {\n return Err(`Failed to access file '${filepath}': ${error.message}`);\n }\n return Err(`Failed to access file '${filepath}': ${String(error)}`);\n }\n\n // Create the async iterator using readline\n const asyncIterator = (async function* () {\n const fileStream = fs.createReadStream(filepath, { encoding: \"utf-8\" });\n const rl = readline.createInterface({\n input: fileStream,\n crlfDelay: Infinity, // Handle both \\n and \\r\\n\n });\n\n try {\n for await (const line of rl) {\n yield line;\n }\n } finally {\n rl.close();\n fileStream.destroy();\n }\n })();\n\n return Ok(asyncIter(asyncIterator));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,cAAc,UAAgD;AAC5E,KAAI;EAEF,MAAM,QADU,GAAG,aAAa,UAAU,QAAQ,CAC5B,MAAM,KAAK;AAEjC,MAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,GAClD,OAAM,KAAK;AAEb,SAAOA,sBAAGC,wBAAK,MAAM,CAAC;UACf,OAAO;AACd,MAAI,iBAAiB,MACnB,QAAOC,uBAAI,wBAAwB,SAAS,KAAK,MAAM,UAAU;AAEnE,SAAOA,uBAAI,wBAAwB,SAAS,KAAK,OAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;AA6BrE,eAAsB,eAAe,UAA8D;AAEjG,KAAI;AACF,QAAM,GAAG,SAAS,OAAO,UAAU,GAAG,UAAU,KAAK;UAC9C,OAAO;AACd,MAAI,iBAAiB,MACnB,QAAOA,uBAAI,0BAA0B,SAAS,KAAK,MAAM,UAAU;AAErE,SAAOA,uBAAI,0BAA0B,SAAS,KAAK,OAAO,MAAM,GAAG;;AAqBrE,QAAOF,sBAAGG,8BAjBa,mBAAmB;EACxC,MAAM,aAAa,GAAG,iBAAiB,UAAU,EAAE,UAAU,SAAS,CAAC;EACvE,MAAM,KAAK,SAAS,gBAAgB;GAClC,OAAO;GACP,WAAW;GACZ,CAAC;AAEF,MAAI;AACF,cAAW,MAAM,QAAQ,GACvB,OAAM;YAEA;AACR,MAAG,OAAO;AACV,cAAW,SAAS;;KAEpB,CAE8B,CAAC"}
|
package/dist/node.d.cts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { g as Result, s as Iter, t as AsyncIter } from "./async-iter-D7Pj6knS.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/node.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create an Iter that lazily reads lines from a file.
|
|
6
|
+
* Uses Node.js fs.readFileSync but yields lines lazily via generator.
|
|
7
|
+
*
|
|
8
|
+
* Note: This reads the entire file into memory but yields lines lazily.
|
|
9
|
+
* For truly streaming line-by-line reading, use asyncIterLines.
|
|
10
|
+
*
|
|
11
|
+
* @param filepath - Path to the file to read
|
|
12
|
+
* @returns Result with Iter<string> on success, error message on failure
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const lines = iterLinesSync('data.txt');
|
|
16
|
+
* lines.match({
|
|
17
|
+
* ok: (iter) => iter.skip(1).map(parseLine).collect(),
|
|
18
|
+
* err: (e) => console.error(e)
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
declare function iterLinesSync(filepath: string): Result<Iter<string>, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Create an AsyncIter that reads lines from a file using streaming.
|
|
24
|
+
* Truly memory-efficient - reads lines on-demand without loading entire file.
|
|
25
|
+
*
|
|
26
|
+
* Uses Node.js readline with createReadStream for efficient streaming.
|
|
27
|
+
*
|
|
28
|
+
* @param filepath - Path to the file to read
|
|
29
|
+
* @returns Promise of Result with AsyncIter<string> on success, error message on failure
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* const result = await asyncIterLines('large-log.txt');
|
|
33
|
+
* result.match({
|
|
34
|
+
* ok: async (iter) => {
|
|
35
|
+
* const errors = await iter
|
|
36
|
+
* .filter(line => line.includes('ERROR'))
|
|
37
|
+
* .take(100)
|
|
38
|
+
* .collect();
|
|
39
|
+
* },
|
|
40
|
+
* err: (e) => console.error(e)
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
43
|
+
declare function asyncIterLines(filepath: string): Promise<Result<AsyncIter<string>, string>>;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { asyncIterLines, iterLinesSync };
|
|
46
|
+
//# sourceMappingURL=node.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.cts","names":[],"sources":["../src/node.ts"],"mappings":";;;AAiFA;;;;;;;;;;;;;;;;;AAAA,iBA1CgB,aAAA,CAAc,QAAA,WAAmB,MAAA,CAAO,IAAA;;;;;;;;;;;;;;;;;;;;;;iBA0ClC,cAAA,CAAe,QAAA,WAAmB,OAAA,CAAQ,MAAA,CAAO,SAAA"}
|