ferric-oxide 1.0.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/README.md +225 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/maybe/maybe.js +51 -0
- package/dist/maybe/maybe.js.map +1 -0
- package/dist/maybe/maybe.test.js +81 -0
- package/dist/maybe/maybe.test.js.map +1 -0
- package/dist/result/result.js +51 -0
- package/dist/result/result.js.map +1 -0
- package/dist/result/result.test.js +101 -0
- package/dist/result/result.test.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/maybe/maybe.d.ts +13 -0
- package/dist/types/maybe/maybe.d.ts.map +1 -0
- package/dist/types/maybe/maybe.test.d.ts +2 -0
- package/dist/types/maybe/maybe.test.d.ts.map +1 -0
- package/dist/types/result/result.d.ts +17 -0
- package/dist/types/result/result.d.ts.map +1 -0
- package/dist/types/result/result.test.d.ts +2 -0
- package/dist/types/result/result.test.d.ts.map +1 -0
- package/package.json +54 -0
- package/src/index.ts +3 -0
- package/src/maybe/maybe.test.ts +91 -0
- package/src/maybe/maybe.ts +48 -0
- package/src/result/result.test.ts +126 -0
- package/src/result/result.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Rust like utils for typescript
|
|
2
|
+
|
|
3
|
+
Rust is famous for its exceptional design choices that helps reduce some class of bugs beforehand. It also force us to wrtite good code. You can now taste these features in typesriupt too.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @mr-m1m3/rusts
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Basically rusts exports classes that implements spceific rust standard library modules.
|
|
14
|
+
|
|
15
|
+
Currently rusts exports following classes:
|
|
16
|
+
|
|
17
|
+
* [Maybe](#Maybe) (`Option<T>` equivalent of rust)
|
|
18
|
+
* [Result](#Result)
|
|
19
|
+
|
|
20
|
+
#### Maybe `<T>`
|
|
21
|
+
|
|
22
|
+
Basically a wrapper around `null`. Use it when a value can either be something or nothing.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
|
|
26
|
+
import {Maybe} from "@mr-m1m3/rusts";
|
|
27
|
+
|
|
28
|
+
// contains some value
|
|
29
|
+
const maybe_a_number = new Maybe(100);
|
|
30
|
+
|
|
31
|
+
// doesn't contain value
|
|
32
|
+
const or_maybe_not = new Maybe(null);
|
|
33
|
+
|
|
34
|
+
// methods
|
|
35
|
+
/*
|
|
36
|
+
* .is_value() -> returns `true` because it contains a value otherwise resturns false
|
|
37
|
+
*/
|
|
38
|
+
maybe_a_number.is_value(); // true
|
|
39
|
+
or_maybe_not.is_value(); //false
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* is_not_a_value() -> opposite of .is_value()
|
|
43
|
+
*/
|
|
44
|
+
or_maybe_not.is_not_a_value(); // true
|
|
45
|
+
maybe_a_number.is_not_a_value(); // false
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
* .unwrap() -> returns the value if it contains any or throws if it doesn't
|
|
49
|
+
*/
|
|
50
|
+
maybe_a_number.unwrap(); // 100
|
|
51
|
+
or_maybe_not.unwrap(); // throws
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* .expect(msg: string) -> same as .unwrap() but you can specify a message to be displayed as error
|
|
56
|
+
*/
|
|
57
|
+
maybe_a_number.expect('oops!'); // logs: 100
|
|
58
|
+
or_maybe_not.expect('oops!'); // throws an error showing: oops!
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
* .unwrap_or(default: T) -> returns the value if it contains any; provided default if it doesn't
|
|
63
|
+
*/
|
|
64
|
+
maybe_a_number.unwrap_or(420); // 100
|
|
65
|
+
or_maybe_not.unwrap_or(420); // 420
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* .unwrap_or_else(fn: () => T) -> same as .unwrap_or() but takes a function calulate the default value
|
|
69
|
+
*/
|
|
70
|
+
maybe_a_number.unwrap_or_else(() => Math.random() * 15); // 100
|
|
71
|
+
or_maybe_not.unwrap_or_else(() => Math.random() * 15); // a random number
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* .map() -> converts `Maybe` of one type to Maybe of another type.
|
|
75
|
+
*/
|
|
76
|
+
maybe_a_number.map((n) => `number is one hundred`); // Maybe<string>
|
|
77
|
+
or_maybe_not.map((n) => `contains null`); // Maybe<string>
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* .transform(fn: (T) => U) -> transform the whole Maybe<T> to another type
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
maybe_a_number.transform((val) => {
|
|
85
|
+
if(val.is_value()){
|
|
86
|
+
return {
|
|
87
|
+
is_value: true
|
|
88
|
+
}
|
|
89
|
+
}else{
|
|
90
|
+
return {
|
|
91
|
+
is_value: false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}); // {is_value: true}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### Result `<T, E>`
|
|
98
|
+
|
|
99
|
+
typescript equivalent of rust `Result<T, E>`. It is use extensively in error handling. If a function can fail, it should always return `Result<T, E>` instead of throwing. Whoever calling the function should be the one to decide what to do with it. This approach also helps easily type a function that can fail. It takes advantage of typescript\'s discriminated union. Here, `T` represents the expected value and `E` represent the value if something happens really bad.
|
|
100
|
+
|
|
101
|
+
You can call two static methods from this function.
|
|
102
|
+
|
|
103
|
+
- `Result.Ok(expected_val)` returns an instance that contains the value we expect when all went well.
|
|
104
|
+
- `Result.Err(err_val)` returns an instance that contains the value that will be returned when an error happens.
|
|
105
|
+
|
|
106
|
+
Imagine, you have a function that looks like this:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
function could_fail(): Data{
|
|
110
|
+
//..//
|
|
111
|
+
if(condition){
|
|
112
|
+
return {/*...*/}
|
|
113
|
+
}
|
|
114
|
+
throw Error(/**/);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
However, the caller can't really tell beforehand that this function can throw. Also, it is now difficult to return organized error details to the caller. What we can do now is use `Result<Data, ErrMsg>`. What we are expressing is that the function can return either of type `Data` or `ErrMsg` and the caller must check explicitely before using the value. Now, inside the function body, we return `Result.Ok(data: Data)` and instead of throwing, we return `Result.Err(err_msg: ErrMsg)`.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
function could_fail(): Result<Data, ErrMsg>{
|
|
122
|
+
//..//
|
|
123
|
+
if(condition){
|
|
124
|
+
return Result.Ok({/*...*/});
|
|
125
|
+
}
|
|
126
|
+
throw Result.Err({/**/});
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The instance comes with some useful methods:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import Result from "@mr-m1m3/rusts/result";
|
|
134
|
+
|
|
135
|
+
type Data = {
|
|
136
|
+
name: string;
|
|
137
|
+
age: number;
|
|
138
|
+
};
|
|
139
|
+
type ErrMsg = {
|
|
140
|
+
msg: string;
|
|
141
|
+
status: number;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// +-------> ok variant or the value of a successfull operation
|
|
145
|
+
// | +-----> error variant or the value of a failed operation
|
|
146
|
+
// | |
|
|
147
|
+
// Result<T, E>
|
|
148
|
+
|
|
149
|
+
const ok_variant: Result<Data, ErrMsg> = Result.Ok({
|
|
150
|
+
name: "John Doe",
|
|
151
|
+
age: 30,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const err_variant: Result<Data, ErrMsg> = Result.Err({
|
|
155
|
+
msg: "oops!",
|
|
156
|
+
status: 500,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* .is_ok() -> returns true if the instance contains the value of a successfull operation aka if it was instantiated with Result.Ok();
|
|
161
|
+
*/
|
|
162
|
+
ok_variant.is_ok(); // true
|
|
163
|
+
err_variant.is_ok(); // false
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* .is_error() -> returns true if the instance contains the value of a failed operation aka if it was instantiated with Result.Err();
|
|
167
|
+
*/
|
|
168
|
+
ok_variant.is_error(); // false
|
|
169
|
+
err_variant.is_error(); // true
|
|
170
|
+
|
|
171
|
+
/*
|
|
172
|
+
* .ok_value() -> returns Maybe<T>.
|
|
173
|
+
*/
|
|
174
|
+
ok_variant.ok_value();
|
|
175
|
+
err_variant.ok_value();
|
|
176
|
+
|
|
177
|
+
/*
|
|
178
|
+
* .err_value() -> returns Maybe<E>.
|
|
179
|
+
*/
|
|
180
|
+
ok_variant.err_value();
|
|
181
|
+
err_variant.err_value();
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* .map<U, Q>(
|
|
185
|
+
ok_mapper: (ok_val: T) => U,
|
|
186
|
+
err_mapper: (err_val: E) => Q,
|
|
187
|
+
) -> converts to another instcance of Result that has `U` as Ok variant and `Q` as Error variant
|
|
188
|
+
calls first callback with the ok value to get the new ok value if exists otherwise calls second callback with error value to get the new error value.
|
|
189
|
+
returned Result variant will be an ok variant if it itself is the ok variant.
|
|
190
|
+
*/
|
|
191
|
+
ok_variant.map(
|
|
192
|
+
(ok_val) => "mission passed",
|
|
193
|
+
(error_val) => 0,
|
|
194
|
+
); // Result<string, number>
|
|
195
|
+
err_variant.map(
|
|
196
|
+
(ok_val) => new Date(),
|
|
197
|
+
(error_val) => "aura ---",
|
|
198
|
+
); // Result<Date, string>
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* .map_ok<U>((ok_val) => U) -> same as .map() but only takes in one callback that is called with ok value to get the new ok value
|
|
202
|
+
returned Result contains the same error value as it itself contains
|
|
203
|
+
*/
|
|
204
|
+
ok_variant.map_ok((ok_val) => "mission passed"); // Result<string, ErrMsg>
|
|
205
|
+
err_variant.map_ok((ok_val) => "mission passed"); // Result<string, ErrMsg>
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* .map_err<Q>((ok_val) => Q) -> same as .map() but only takes in one callback that is called with error value to get the new error value
|
|
209
|
+
returned Result contains the same ok value as it itself contains
|
|
210
|
+
*/
|
|
211
|
+
ok_variant.map_err((err_val) => "mission failed"); // Result<Data, string>
|
|
212
|
+
err_variant.map_err((err_val) => "mission failed"); // Result<Data, string>
|
|
213
|
+
|
|
214
|
+
/*
|
|
215
|
+
* .transform(callback) -> transformsthe entire Result instance to another type and returns. applies the provided callback on the instance to get the new type.
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
ok_variant.transform((result_instnce) => {
|
|
219
|
+
return {
|
|
220
|
+
is_ok: result_instnce.is_ok(),
|
|
221
|
+
is_error: result_instnce.is_error(),
|
|
222
|
+
};
|
|
223
|
+
}); // {is_ok: true, is_error: false}
|
|
224
|
+
|
|
225
|
+
```
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export default class Maybe {
|
|
2
|
+
constructor(val = null) {
|
|
3
|
+
this.value = val;
|
|
4
|
+
}
|
|
5
|
+
//useful methods
|
|
6
|
+
is_value() {
|
|
7
|
+
if (this.value === null) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
is_not_a_value() {
|
|
15
|
+
return !this.is_value();
|
|
16
|
+
}
|
|
17
|
+
expect(msg) {
|
|
18
|
+
if (this.is_value()) {
|
|
19
|
+
return this.value;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
throw new Error(msg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
unwrap() {
|
|
26
|
+
return this.expect('Expected a value but didnt get one.');
|
|
27
|
+
}
|
|
28
|
+
unwrap_or(def) {
|
|
29
|
+
if (this.is_value()) {
|
|
30
|
+
return this.value;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return def;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
unwrap_or_else(fn) {
|
|
37
|
+
return this.unwrap_or(fn());
|
|
38
|
+
}
|
|
39
|
+
map(fn) {
|
|
40
|
+
if (this.is_value()) {
|
|
41
|
+
return new Maybe(fn(this.value));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return new Maybe(null);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
transform(fn) {
|
|
48
|
+
return fn(this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=maybe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maybe.js","sourceRoot":"","sources":["../../src/maybe/maybe.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,KAAK;IAGxB,YAAY,MAAgB,IAAI;QAC9B,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;IACnB,CAAC;IACD,gBAAgB;IACT,QAAQ;QACb,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACM,cAAc;QACnB,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IACM,MAAM,CAAC,GAAW;QACvB,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,KAAU,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACM,MAAM;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,qCAAqC,CAAC,CAAA;IAC3D,CAAC;IACM,SAAS,CAAC,GAAM;QACrB,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,KAAU,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACM,cAAc,CAAC,EAAW;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAA;IAC7B,CAAC;IACM,GAAG,CAAI,EAAe;QAC3B,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YACpB,OAAO,IAAI,KAAK,CAAI,EAAE,CAAC,IAAI,CAAC,KAAU,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,KAAK,CAAI,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACM,SAAS,CAAK,EAA6B;QAChD,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { Maybe } from "@/index.js";
|
|
3
|
+
const has_value = new Maybe("value");
|
|
4
|
+
const not_a_value = new Maybe(null);
|
|
5
|
+
describe("Maybe<T>", () => {
|
|
6
|
+
describe(".is_value()", () => {
|
|
7
|
+
test("should be true", () => {
|
|
8
|
+
expect.soft(has_value.is_value()).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
test("should be false", () => {
|
|
11
|
+
expect.soft(not_a_value.is_value()).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe(".is_not_a_value()", () => {
|
|
15
|
+
test("should be false", () => {
|
|
16
|
+
expect.soft(has_value.is_not_a_value()).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
test("should be true", () => {
|
|
19
|
+
expect.soft(not_a_value.is_not_a_value()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe(".expect.soft(msg: string)", () => {
|
|
23
|
+
test("should be the actual value it holds", () => {
|
|
24
|
+
expect.soft(has_value.expect("doesn't hold a value")).toBe("value");
|
|
25
|
+
});
|
|
26
|
+
test("should throw with the message passed", () => {
|
|
27
|
+
expect.soft(() => not_a_value.expect("error msg")).toThrow("error msg");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe(".unwrap()", () => {
|
|
31
|
+
test("should be the actual value it holds", () => {
|
|
32
|
+
expect.soft(has_value.unwrap()).toBe("value");
|
|
33
|
+
});
|
|
34
|
+
test("should throw with default message: `Expected a value but didnt get one.`", () => {
|
|
35
|
+
expect.soft(() => {
|
|
36
|
+
not_a_value.unwrap();
|
|
37
|
+
}).toThrow("Expected a value but didnt get one.");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe(".unwrap_or()", () => {
|
|
41
|
+
test("should be the actual value it holds", () => {
|
|
42
|
+
expect.soft(has_value.unwrap_or("default")).toBe("value");
|
|
43
|
+
});
|
|
44
|
+
test("should be the provided default value`", () => {
|
|
45
|
+
expect.soft(not_a_value.unwrap_or("default")).toBe("default");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe(".unwrap_or_else()", () => {
|
|
49
|
+
test("should be the actual value it holds", () => {
|
|
50
|
+
expect.soft(has_value.unwrap_or_else(() => "calulated default")).toBe("value");
|
|
51
|
+
});
|
|
52
|
+
test("should be the return value of the provided function`", () => {
|
|
53
|
+
expect.soft(not_a_value.unwrap_or_else(() => "calulated default")).toBe("calulated default");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe(".map()", () => {
|
|
57
|
+
test("should be a new instance of Maybe holding the returned value of the provided function", () => {
|
|
58
|
+
const new_maybe_with_val = has_value.map((val) => val.length);
|
|
59
|
+
expect.soft(new_maybe_with_val).toBeInstanceOf(Maybe);
|
|
60
|
+
expect.soft(new_maybe_with_val.unwrap()).toBe(5 /*length*/);
|
|
61
|
+
});
|
|
62
|
+
test("should be the a new instance of maybe that holds no value`", () => {
|
|
63
|
+
const new_maybe_with_no_val = not_a_value.map((val) => val.length);
|
|
64
|
+
expect.soft(new_maybe_with_no_val).toBeInstanceOf(Maybe);
|
|
65
|
+
expect.soft(() => {
|
|
66
|
+
new_maybe_with_no_val.unwrap();
|
|
67
|
+
}).toThrow();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe(".transform()", () => {
|
|
71
|
+
test("should transform the whole Maybe<T> class to boolean", () => {
|
|
72
|
+
const tr_maybe_with_val = has_value.transform(val => true);
|
|
73
|
+
expect.soft(tr_maybe_with_val).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
test("should transform the whole Maybe<T> class to Date object", () => {
|
|
76
|
+
const tr_maybe_with_no_val = not_a_value.transform(val => new Date());
|
|
77
|
+
expect.soft(tr_maybe_with_no_val).toBeInstanceOf(Date);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=maybe.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maybe.test.js","sourceRoot":"","sources":["../../src/maybe/maybe.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Maybe from "../maybe/maybe.js";
|
|
2
|
+
export default class Result {
|
|
3
|
+
constructor(ok, err) {
|
|
4
|
+
if (ok === null && err === null) {
|
|
5
|
+
throw Error(`both \`Ok\` and \'Err\' can't be null at the same time`);
|
|
6
|
+
}
|
|
7
|
+
if (ok !== null && err !== null) {
|
|
8
|
+
throw Error(`both \`Ok\` and \'Err\' can't be other than null at the same time`);
|
|
9
|
+
}
|
|
10
|
+
this.ok = new Maybe(ok);
|
|
11
|
+
this.err = new Maybe(err);
|
|
12
|
+
}
|
|
13
|
+
//public interface to construct an instance
|
|
14
|
+
static Ok(val) {
|
|
15
|
+
return new Result(val, null);
|
|
16
|
+
}
|
|
17
|
+
static Err(err) {
|
|
18
|
+
return new Result(null, err);
|
|
19
|
+
}
|
|
20
|
+
//useful methods
|
|
21
|
+
is_ok() {
|
|
22
|
+
return this.ok.is_value();
|
|
23
|
+
}
|
|
24
|
+
is_error() {
|
|
25
|
+
return this.err.is_value();
|
|
26
|
+
}
|
|
27
|
+
ok_value() {
|
|
28
|
+
return this.ok;
|
|
29
|
+
}
|
|
30
|
+
err_value() {
|
|
31
|
+
return this.err;
|
|
32
|
+
}
|
|
33
|
+
map(ok_mapper, err_mapper) {
|
|
34
|
+
if (this.is_ok()) {
|
|
35
|
+
return Result.Ok(ok_mapper(this.ok_value().unwrap()));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return Result.Err(err_mapper(this.err_value().unwrap()));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
map_ok(fn) {
|
|
42
|
+
return this.map(fn, (err) => err);
|
|
43
|
+
}
|
|
44
|
+
map_err(fn) {
|
|
45
|
+
return this.map((v) => v, fn);
|
|
46
|
+
}
|
|
47
|
+
transform(fn) {
|
|
48
|
+
return fn(this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/result/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAEtC,MAAM,CAAC,OAAO,OAAO,MAAM;IAIzB,YAAoB,EAAY,EAAE,GAAa;QAC7C,IAAI,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,KAAK,CACT,mEAAmE,CACpE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,CAAI,EAAE,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,CAAI,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,2CAA2C;IACpC,MAAM,CAAC,EAAE,CAAO,GAAM;QAC3B,OAAO,IAAI,MAAM,CAAO,GAAG,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IACM,MAAM,CAAC,GAAG,CAAO,GAAM;QAC5B,OAAO,IAAI,MAAM,CAAO,IAAI,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IACD,gBAAgB;IACT,KAAK;QACV,OAAO,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;IACM,QAAQ;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;IACM,QAAQ;QACb,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IACM,SAAS;QACd,OAAO,IAAI,CAAC,GAAG,CAAC;IAClB,CAAC;IACM,GAAG,CACR,SAAwB,EACxB,UAAyB;QAEzB,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;YACjB,OAAO,MAAM,CAAC,EAAE,CAAO,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,CAAC,GAAG,CAAO,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IACM,MAAM,CAAI,EAAiB;QAChC,OAAO,IAAI,CAAC,GAAG,CAAO,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC;IACM,OAAO,CAAI,EAAiB;QACjC,OAAO,IAAI,CAAC,GAAG,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;IACM,SAAS,CAAK,EAA6B;QAChD,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { Maybe, Result } from "@/index.js";
|
|
3
|
+
const ok_variant = Result.Ok({
|
|
4
|
+
data: "ok data",
|
|
5
|
+
});
|
|
6
|
+
const err_variant = Result.Err({
|
|
7
|
+
status: 400,
|
|
8
|
+
});
|
|
9
|
+
describe("Result<T, E>", () => {
|
|
10
|
+
describe(".is_ok()", () => {
|
|
11
|
+
test("should be true", () => {
|
|
12
|
+
expect.soft(ok_variant.is_ok()).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
test("should be false", () => {
|
|
15
|
+
expect.soft(err_variant.is_ok()).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe(".is_error()", () => {
|
|
19
|
+
test("should be false", () => {
|
|
20
|
+
expect.soft(ok_variant.is_error()).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
test("should be true", () => {
|
|
23
|
+
expect.soft(err_variant.is_error()).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
describe(".ok_value()", () => {
|
|
27
|
+
test("should be an instance of Maybe<T> containing the expected value", () => {
|
|
28
|
+
const ok_variant_ok_value = ok_variant.ok_value();
|
|
29
|
+
expect.soft(ok_variant_ok_value).toBeInstanceOf(Maybe);
|
|
30
|
+
expect.soft(ok_variant_ok_value.unwrap()).toStrictEqual({
|
|
31
|
+
data: "ok data",
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
test("should be an instance of Maybe<T> containing nothing", () => {
|
|
35
|
+
const err_variant_ok_value = err_variant.ok_value();
|
|
36
|
+
expect.soft(err_variant_ok_value).toBeInstanceOf(Maybe);
|
|
37
|
+
expect
|
|
38
|
+
.soft(() => {
|
|
39
|
+
err_variant_ok_value.unwrap();
|
|
40
|
+
})
|
|
41
|
+
.toThrow();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe(".err_value()", () => {
|
|
45
|
+
test("should be an instance of Maybe<T> containing the nothing", () => {
|
|
46
|
+
const ok_variant_err_value = ok_variant.err_value();
|
|
47
|
+
expect.soft(ok_variant_err_value).toBeInstanceOf(Maybe);
|
|
48
|
+
expect
|
|
49
|
+
.soft(() => {
|
|
50
|
+
ok_variant_err_value.unwrap();
|
|
51
|
+
})
|
|
52
|
+
.toThrow();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
test("should be an instance of Maybe<T> containing error details", () => {
|
|
56
|
+
const err_variant_err_value = err_variant.err_value();
|
|
57
|
+
expect.soft(err_variant_err_value).toBeInstanceOf(Maybe);
|
|
58
|
+
expect.soft(err_variant_err_value.unwrap()).toStrictEqual({
|
|
59
|
+
status: 400,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe(".map()", () => {
|
|
63
|
+
test("should be ok variant of another Result with new calulated ok and error value", () => {
|
|
64
|
+
const mapped_ok_variant = ok_variant.map((ok_data) => "was ok variant", (err_data) => "was error variant");
|
|
65
|
+
expect.soft(mapped_ok_variant).toBeInstanceOf(Result);
|
|
66
|
+
expect.soft(mapped_ok_variant.is_ok()).toBe(true);
|
|
67
|
+
expect.soft(mapped_ok_variant.ok_value().unwrap()).toBe("was ok variant");
|
|
68
|
+
});
|
|
69
|
+
test("should be err variant of another Result with new calulated ok and error value", () => {
|
|
70
|
+
const mapped_err_variant = err_variant.map((ok_data) => "was ok variant", (err_data) => "was error variant");
|
|
71
|
+
expect.soft(mapped_err_variant).toBeInstanceOf(Result);
|
|
72
|
+
expect.soft(mapped_err_variant.is_error()).toBe(true);
|
|
73
|
+
expect.soft(mapped_err_variant.err_value().unwrap()).toBe("was error variant");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe(".map_ok()", () => {
|
|
77
|
+
test("should be ok variant of another Result with new calculated ok value but old error value", () => {
|
|
78
|
+
const map_ok_of_ok_variant = ok_variant.map_ok((ok_data) => "was ok variant");
|
|
79
|
+
expect.soft(map_ok_of_ok_variant).toBeInstanceOf(Result);
|
|
80
|
+
expect.soft(map_ok_of_ok_variant.is_ok()).toBe(true);
|
|
81
|
+
expect.soft(map_ok_of_ok_variant.ok_value().unwrap()).toBe("was ok variant");
|
|
82
|
+
});
|
|
83
|
+
test("should be ok variant of another Result with new calculated error value but old ok value", () => {
|
|
84
|
+
const map_err_of_err_variant = err_variant.map_err((err_data) => "was error variant");
|
|
85
|
+
expect.soft(map_err_of_err_variant).toBeInstanceOf(Result);
|
|
86
|
+
expect.soft(map_err_of_err_variant.is_error()).toBe(true);
|
|
87
|
+
expect.soft(map_err_of_err_variant.err_value().unwrap()).toBe("was error variant");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe(".transform()", () => {
|
|
91
|
+
test("should transform the whole Result<T, E> class to type string", () => {
|
|
92
|
+
const tr_maybe_with_val = ok_variant.transform(val => 'success');
|
|
93
|
+
expect.soft(tr_maybe_with_val).toBe('success');
|
|
94
|
+
});
|
|
95
|
+
test("should transform the whole Result<T, E> class to number", () => {
|
|
96
|
+
const tr_maybe_with_no_val = err_variant.transform(val => 500);
|
|
97
|
+
expect.soft(tr_maybe_with_no_val).toBe(500);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=result.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.test.js","sourceRoot":"","sources":["../../src/result/result.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAO3C,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAkB;IAC5C,IAAI,EAAE,SAAS;CAChB,CAAC,CAAC;AACH,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAkB;IAC9C,MAAM,EAAE,GAAG;CACZ,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE;YAC1B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC3B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC3B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE;YAC1B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,IAAI,CAAC,iEAAiE,EAAE,GAAG,EAAE;YAC3E,MAAM,mBAAmB,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa,CAAC;gBACtD,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAChE,MAAM,oBAAoB,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACxD,MAAM;iBACH,IAAI,CAAC,GAAG,EAAE;gBACT,oBAAoB,CAAC,MAAM,EAAE,CAAC;YAChC,CAAC,CAAC;iBACD,OAAO,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;YACpE,MAAM,oBAAoB,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YACxD,MAAM;iBACH,IAAI,CAAC,GAAG,EAAE;gBACT,oBAAoB,CAAC,MAAM,EAAE,CAAC;YAChC,CAAC,CAAC;iBACD,OAAO,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACtE,MAAM,qBAAqB,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa,CAAC;YACxD,MAAM,EAAE,GAAG;SACZ,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,IAAI,CAAC,8EAA8E,EAAE,GAAG,EAAE;YACxF,MAAM,iBAAiB,GAAG,UAAU,CAAC,GAAG,CACtC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,EAC7B,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAClC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC3E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,+EAA+E,EAAE,GAAG,EAAE;YACzF,MAAM,kBAAkB,GAAG,WAAW,CAAC,GAAG,CACxC,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,EAC7B,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAClC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtD,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,IAAI,CAAC,yFAAyF,EAAE,GAAG,EAAE;YACnG,MAAM,oBAAoB,GAAG,UAAU,CAAC,MAAM,CAC5C,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAC9B,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,yFAAyF,EAAE,GAAG,EAAE;YACnG,MAAM,sBAAsB,GAAG,WAAW,CAAC,OAAO,CAChD,CAAC,QAAQ,EAAE,EAAE,CAAC,mBAAmB,CAClC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1D,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACrF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEJ,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC3B,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACxE,MAAM,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;YACjE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACnE,MAAM,oBAAoB,GAAG,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,kBAAkB,CAAC;AACrC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default class Maybe<T> {
|
|
2
|
+
private value;
|
|
3
|
+
constructor(val?: T | null);
|
|
4
|
+
is_value(): boolean;
|
|
5
|
+
is_not_a_value(): boolean;
|
|
6
|
+
expect(msg: string): T;
|
|
7
|
+
unwrap(): T;
|
|
8
|
+
unwrap_or(def: T): T;
|
|
9
|
+
unwrap_or_else(fn: () => T): T;
|
|
10
|
+
map<U>(fn: (v: T) => U): Maybe<U>;
|
|
11
|
+
transform<To>(fn: (from: typeof this) => To): To;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=maybe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maybe.d.ts","sourceRoot":"","sources":["../../../src/maybe/maybe.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,KAAK,CAAC,CAAC;IAC1B,OAAO,CAAC,KAAK,CAAW;gBAEZ,GAAG,GAAE,CAAC,GAAG,IAAW;IAIzB,QAAQ,IAAI,OAAO;IAOnB,cAAc,IAAI,OAAO;IAGzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC;IAOtB,MAAM,IAAI,CAAC;IAGX,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;IAOpB,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAG9B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAOjC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,IAAI,KAAK,EAAE,GAAG,EAAE;CAGxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maybe.test.d.ts","sourceRoot":"","sources":["../../../src/maybe/maybe.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Maybe from "../maybe/maybe.js";
|
|
2
|
+
export default class Result<T, E> {
|
|
3
|
+
private ok;
|
|
4
|
+
private err;
|
|
5
|
+
private constructor();
|
|
6
|
+
static Ok<T, E>(val: T): Result<T, E>;
|
|
7
|
+
static Err<T, E>(err: E): Result<T, E>;
|
|
8
|
+
is_ok(): boolean;
|
|
9
|
+
is_error(): boolean;
|
|
10
|
+
ok_value(): Maybe<T>;
|
|
11
|
+
err_value(): Maybe<E>;
|
|
12
|
+
map<U, Q>(ok_mapper: (val: T) => U, err_mapper: (err: E) => Q): Result<U, Q>;
|
|
13
|
+
map_ok<U>(fn: (val: T) => U): Result<U, E>;
|
|
14
|
+
map_err<Q>(fn: (val: E) => Q): Result<T, Q>;
|
|
15
|
+
transform<To>(fn: (from: typeof this) => To): To;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../../src/result/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAEtC,MAAM,CAAC,OAAO,OAAO,MAAM,CAAC,CAAC,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,GAAG,CAAW;IAEtB,OAAO;WAcO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;WAG9B,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAItC,KAAK,IAAI,OAAO;IAGhB,QAAQ,IAAI,OAAO;IAGnB,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC;IAGpB,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC;IAGrB,GAAG,CAAC,CAAC,EAAE,CAAC,EACb,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EACxB,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GACxB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAOR,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAG1C,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;IAG3C,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,IAAI,KAAK,EAAE,GAAG,EAAE;CAGxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.test.d.ts","sourceRoot":"","sources":["../../../src/result/result.test.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ferric-oxide",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Rust liike utilities for typescript",
|
|
5
|
+
"homepage": "https://github.com/mr-m1m3/rsts",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/mr-m1m3/rsts/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/mr-m1m3/rsts.git"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test:watch": "vitest",
|
|
16
|
+
"test": "vitest run"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/types/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./maybe": {
|
|
24
|
+
"types": "./dist/types/maybe/maybe.d.ts",
|
|
25
|
+
"default": "./dist/maybe/maybe.js"
|
|
26
|
+
},
|
|
27
|
+
"./result": {
|
|
28
|
+
"types": "./dist/types/result/result.d.ts",
|
|
29
|
+
"default": "./dist/result/result.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"./src",
|
|
34
|
+
"./dist"
|
|
35
|
+
],
|
|
36
|
+
"keywords": [
|
|
37
|
+
"rust",
|
|
38
|
+
"utilities",
|
|
39
|
+
"result",
|
|
40
|
+
"option",
|
|
41
|
+
"enum",
|
|
42
|
+
"error-handling",
|
|
43
|
+
"null-handling"
|
|
44
|
+
],
|
|
45
|
+
"author": "@mr-m1m3",
|
|
46
|
+
"license": "ISC",
|
|
47
|
+
"packageManager": "pnpm@10.28.1",
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^25.1.0",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^4.0.18"
|
|
52
|
+
},
|
|
53
|
+
"type": "module"
|
|
54
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { Maybe } from "@/index.js";
|
|
3
|
+
|
|
4
|
+
const has_value = new Maybe("value");
|
|
5
|
+
const not_a_value = new Maybe<string>(null);
|
|
6
|
+
describe("Maybe<T>", () => {
|
|
7
|
+
describe(".is_value()", () => {
|
|
8
|
+
test("should be true", () => {
|
|
9
|
+
expect.soft(has_value.is_value()).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
test("should be false", () => {
|
|
12
|
+
expect.soft(not_a_value.is_value()).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe(".is_not_a_value()", () => {
|
|
17
|
+
test("should be false", () => {
|
|
18
|
+
expect.soft(has_value.is_not_a_value()).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
test("should be true", () => {
|
|
21
|
+
expect.soft(not_a_value.is_not_a_value()).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe(".expect.soft(msg: string)", () => {
|
|
26
|
+
test("should be the actual value it holds", () => {
|
|
27
|
+
expect.soft(has_value.expect("doesn't hold a value")).toBe("value");
|
|
28
|
+
});
|
|
29
|
+
test("should throw with the message passed", () => {
|
|
30
|
+
expect.soft(() => not_a_value.expect("error msg")).toThrow("error msg");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe(".unwrap()", () => {
|
|
35
|
+
test("should be the actual value it holds", () => {
|
|
36
|
+
expect.soft(has_value.unwrap()).toBe("value");
|
|
37
|
+
});
|
|
38
|
+
test("should throw with default message: `Expected a value but didnt get one.`", () => {
|
|
39
|
+
expect.soft(() => {
|
|
40
|
+
not_a_value.unwrap();
|
|
41
|
+
}).toThrow("Expected a value but didnt get one.");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe(".unwrap_or()", () => {
|
|
46
|
+
test("should be the actual value it holds", () => {
|
|
47
|
+
expect.soft(has_value.unwrap_or("default")).toBe("value");
|
|
48
|
+
});
|
|
49
|
+
test("should be the provided default value`", () => {
|
|
50
|
+
expect.soft(not_a_value.unwrap_or("default")).toBe("default");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe(".unwrap_or_else()", () => {
|
|
55
|
+
test("should be the actual value it holds", () => {
|
|
56
|
+
expect.soft(has_value.unwrap_or_else(() => "calulated default")).toBe("value");
|
|
57
|
+
});
|
|
58
|
+
test("should be the return value of the provided function`", () => {
|
|
59
|
+
expect.soft(not_a_value.unwrap_or_else(() => "calulated default")).toBe(
|
|
60
|
+
"calulated default",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe(".map()", () => {
|
|
66
|
+
test("should be a new instance of Maybe holding the returned value of the provided function", () => {
|
|
67
|
+
const new_maybe_with_val = has_value.map<number>((val) => val.length);
|
|
68
|
+
expect.soft(new_maybe_with_val).toBeInstanceOf(Maybe);
|
|
69
|
+
expect.soft(new_maybe_with_val.unwrap()).toBe(5 /*length*/);
|
|
70
|
+
});
|
|
71
|
+
test("should be the a new instance of maybe that holds no value`", () => {
|
|
72
|
+
const new_maybe_with_no_val = not_a_value.map((val) => val.length);
|
|
73
|
+
expect.soft(new_maybe_with_no_val).toBeInstanceOf(Maybe);
|
|
74
|
+
expect.soft(() => {
|
|
75
|
+
new_maybe_with_no_val.unwrap();
|
|
76
|
+
}).toThrow();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe(".transform()", () => {
|
|
81
|
+
test("should transform the whole Maybe<T> class to boolean", () => {
|
|
82
|
+
const tr_maybe_with_val = has_value.transform(val => true);
|
|
83
|
+
expect.soft(tr_maybe_with_val).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("should transform the whole Maybe<T> class to Date object", () => {
|
|
87
|
+
const tr_maybe_with_no_val = not_a_value.transform(val => new Date());
|
|
88
|
+
expect.soft(tr_maybe_with_no_val).toBeInstanceOf(Date);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export default class Maybe<T> {
|
|
2
|
+
private value: T | null;
|
|
3
|
+
|
|
4
|
+
constructor(val: T | null = null) {
|
|
5
|
+
this.value = val;
|
|
6
|
+
}
|
|
7
|
+
//useful methods
|
|
8
|
+
public is_value(): boolean {
|
|
9
|
+
if (this.value === null) {
|
|
10
|
+
return false;
|
|
11
|
+
} else {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
public is_not_a_value(): boolean {
|
|
16
|
+
return !this.is_value();
|
|
17
|
+
}
|
|
18
|
+
public expect(msg: string): T {
|
|
19
|
+
if (this.is_value()) {
|
|
20
|
+
return this.value as T;
|
|
21
|
+
} else {
|
|
22
|
+
throw new Error(msg);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
public unwrap(): T {
|
|
26
|
+
return this.expect('Expected a value but didnt get one.')
|
|
27
|
+
}
|
|
28
|
+
public unwrap_or(def: T): T {
|
|
29
|
+
if (this.is_value()) {
|
|
30
|
+
return this.value as T;
|
|
31
|
+
} else {
|
|
32
|
+
return def;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
public unwrap_or_else(fn: () => T): T {
|
|
36
|
+
return this.unwrap_or(fn())
|
|
37
|
+
}
|
|
38
|
+
public map<U>(fn: (v: T) => U): Maybe<U> {
|
|
39
|
+
if (this.is_value()) {
|
|
40
|
+
return new Maybe<U>(fn(this.value as T));
|
|
41
|
+
} else {
|
|
42
|
+
return new Maybe<U>(null);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
public transform<To>(fn: (from: typeof this) => To): To {
|
|
46
|
+
return fn(this);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { Maybe, Result } from "@/index.js";
|
|
3
|
+
type OkData = {
|
|
4
|
+
data: string;
|
|
5
|
+
};
|
|
6
|
+
type ErrData = {
|
|
7
|
+
status: number;
|
|
8
|
+
};
|
|
9
|
+
const ok_variant = Result.Ok<OkData, ErrData>({
|
|
10
|
+
data: "ok data",
|
|
11
|
+
});
|
|
12
|
+
const err_variant = Result.Err<OkData, ErrData>({
|
|
13
|
+
status: 400,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("Result<T, E>", () => {
|
|
17
|
+
describe(".is_ok()", () => {
|
|
18
|
+
test("should be true", () => {
|
|
19
|
+
expect.soft(ok_variant.is_ok()).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
test("should be false", () => {
|
|
22
|
+
expect.soft(err_variant.is_ok()).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe(".is_error()", () => {
|
|
27
|
+
test("should be false", () => {
|
|
28
|
+
expect.soft(ok_variant.is_error()).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
test("should be true", () => {
|
|
31
|
+
expect.soft(err_variant.is_error()).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe(".ok_value()", () => {
|
|
36
|
+
test("should be an instance of Maybe<T> containing the expected value", () => {
|
|
37
|
+
const ok_variant_ok_value = ok_variant.ok_value();
|
|
38
|
+
expect.soft(ok_variant_ok_value).toBeInstanceOf(Maybe);
|
|
39
|
+
expect.soft(ok_variant_ok_value.unwrap()).toStrictEqual({
|
|
40
|
+
data: "ok data",
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
test("should be an instance of Maybe<T> containing nothing", () => {
|
|
44
|
+
const err_variant_ok_value = err_variant.ok_value();
|
|
45
|
+
expect.soft(err_variant_ok_value).toBeInstanceOf(Maybe);
|
|
46
|
+
expect
|
|
47
|
+
.soft(() => {
|
|
48
|
+
err_variant_ok_value.unwrap();
|
|
49
|
+
})
|
|
50
|
+
.toThrow();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe(".err_value()", () => {
|
|
55
|
+
test("should be an instance of Maybe<T> containing the nothing", () => {
|
|
56
|
+
const ok_variant_err_value = ok_variant.err_value();
|
|
57
|
+
expect.soft(ok_variant_err_value).toBeInstanceOf(Maybe);
|
|
58
|
+
expect
|
|
59
|
+
.soft(() => {
|
|
60
|
+
ok_variant_err_value.unwrap();
|
|
61
|
+
})
|
|
62
|
+
.toThrow();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
test("should be an instance of Maybe<T> containing error details", () => {
|
|
66
|
+
const err_variant_err_value = err_variant.err_value();
|
|
67
|
+
expect.soft(err_variant_err_value).toBeInstanceOf(Maybe);
|
|
68
|
+
expect.soft(err_variant_err_value.unwrap()).toStrictEqual({
|
|
69
|
+
status: 400,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe(".map()", () => {
|
|
74
|
+
test("should be ok variant of another Result with new calulated ok and error value", () => {
|
|
75
|
+
const mapped_ok_variant = ok_variant.map(
|
|
76
|
+
(ok_data) => "was ok variant",
|
|
77
|
+
(err_data) => "was error variant",
|
|
78
|
+
);
|
|
79
|
+
expect.soft(mapped_ok_variant).toBeInstanceOf(Result);
|
|
80
|
+
expect.soft(mapped_ok_variant.is_ok()).toBe(true);
|
|
81
|
+
expect.soft(mapped_ok_variant.ok_value().unwrap()).toBe("was ok variant")
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("should be err variant of another Result with new calulated ok and error value", () => {
|
|
85
|
+
const mapped_err_variant = err_variant.map(
|
|
86
|
+
(ok_data) => "was ok variant",
|
|
87
|
+
(err_data) => "was error variant",
|
|
88
|
+
);
|
|
89
|
+
expect.soft(mapped_err_variant).toBeInstanceOf(Result);
|
|
90
|
+
expect.soft(mapped_err_variant.is_error()).toBe(true);
|
|
91
|
+
expect.soft(mapped_err_variant.err_value().unwrap()).toBe("was error variant");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe(".map_ok()", () => {
|
|
96
|
+
test("should be ok variant of another Result with new calculated ok value but old error value", () => {
|
|
97
|
+
const map_ok_of_ok_variant = ok_variant.map_ok(
|
|
98
|
+
(ok_data) => "was ok variant",
|
|
99
|
+
);
|
|
100
|
+
expect.soft(map_ok_of_ok_variant).toBeInstanceOf(Result);
|
|
101
|
+
expect.soft(map_ok_of_ok_variant.is_ok()).toBe(true);
|
|
102
|
+
expect.soft(map_ok_of_ok_variant.ok_value().unwrap()).toBe("was ok variant");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("should be ok variant of another Result with new calculated error value but old ok value", () => {
|
|
106
|
+
const map_err_of_err_variant = err_variant.map_err(
|
|
107
|
+
(err_data) => "was error variant",
|
|
108
|
+
);
|
|
109
|
+
expect.soft(map_err_of_err_variant).toBeInstanceOf(Result);
|
|
110
|
+
expect.soft(map_err_of_err_variant.is_error()).toBe(true);
|
|
111
|
+
expect.soft(map_err_of_err_variant.err_value().unwrap()).toBe("was error variant");
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe(".transform()", () => {
|
|
116
|
+
test("should transform the whole Result<T, E> class to type string", () => {
|
|
117
|
+
const tr_maybe_with_val = ok_variant.transform(val => 'success');
|
|
118
|
+
expect.soft(tr_maybe_with_val).toBe('success');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("should transform the whole Result<T, E> class to number", () => {
|
|
122
|
+
const tr_maybe_with_no_val = err_variant.transform(val => 500);
|
|
123
|
+
expect.soft(tr_maybe_with_no_val).toBe(500);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Maybe from "../maybe/maybe.js";
|
|
2
|
+
|
|
3
|
+
export default class Result<T, E> {
|
|
4
|
+
private ok: Maybe<T>;
|
|
5
|
+
private err: Maybe<E>;
|
|
6
|
+
|
|
7
|
+
private constructor(ok: T | null, err: E | null) {
|
|
8
|
+
if (ok === null && err === null) {
|
|
9
|
+
throw Error(`both \`Ok\` and \'Err\' can't be null at the same time`);
|
|
10
|
+
}
|
|
11
|
+
if (ok !== null && err !== null) {
|
|
12
|
+
throw Error(
|
|
13
|
+
`both \`Ok\` and \'Err\' can't be other than null at the same time`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
this.ok = new Maybe<T>(ok);
|
|
17
|
+
this.err = new Maybe<E>(err);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//public interface to construct an instance
|
|
21
|
+
public static Ok<T, E>(val: T): Result<T, E> {
|
|
22
|
+
return new Result<T, E>(val, null);
|
|
23
|
+
}
|
|
24
|
+
public static Err<T, E>(err: E): Result<T, E> {
|
|
25
|
+
return new Result<T, E>(null, err);
|
|
26
|
+
}
|
|
27
|
+
//useful methods
|
|
28
|
+
public is_ok(): boolean {
|
|
29
|
+
return this.ok.is_value();
|
|
30
|
+
}
|
|
31
|
+
public is_error(): boolean {
|
|
32
|
+
return this.err.is_value();
|
|
33
|
+
}
|
|
34
|
+
public ok_value(): Maybe<T> {
|
|
35
|
+
return this.ok;
|
|
36
|
+
}
|
|
37
|
+
public err_value(): Maybe<E> {
|
|
38
|
+
return this.err;
|
|
39
|
+
}
|
|
40
|
+
public map<U, Q>(
|
|
41
|
+
ok_mapper: (val: T) => U,
|
|
42
|
+
err_mapper: (err: E) => Q,
|
|
43
|
+
): Result<U, Q> {
|
|
44
|
+
if (this.is_ok()) {
|
|
45
|
+
return Result.Ok<U, Q>(ok_mapper(this.ok_value().unwrap()));
|
|
46
|
+
} else {
|
|
47
|
+
return Result.Err<U, Q>(err_mapper(this.err_value().unwrap()));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
public map_ok<U>(fn: (val: T) => U): Result<U, E> {
|
|
51
|
+
return this.map<U, E>(fn, (err) => err);
|
|
52
|
+
}
|
|
53
|
+
public map_err<Q>(fn: (val: E) => Q): Result<T, Q> {
|
|
54
|
+
return this.map<T, Q>((v) => v, fn);
|
|
55
|
+
}
|
|
56
|
+
public transform<To>(fn: (from: typeof this) => To): To {
|
|
57
|
+
return fn(this);
|
|
58
|
+
}
|
|
59
|
+
}
|