@rotomeca/rop 0.0.2
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/.prettierc.json +9 -0
- package/README.md +141 -0
- package/index.ts +14 -0
- package/package.json +18 -0
- package/src/classes/Fail.ts +92 -0
- package/src/classes/Success.ts +91 -0
- package/src/classes/abstracts/ATresult.ts +74 -0
- package/src/decorators/ErrorPath.internal/functions.ts +37 -0
- package/src/decorators/ErrorPath.ts +28 -0
- package/src/decorators/HappyPath.internal/functions.ts +37 -0
- package/src/decorators/HappyPath.ts +28 -0
- package/src/decorators/Risky.internal/functions.ts +40 -0
- package/src/decorators/Risky.ts +27 -0
- package/src/functions/applyMatch.ts +29 -0
- package/src/interfaces/ITResult.ts +86 -0
- package/src/types/ResultMatch.ts +23 -0
- package/src/types/resultsCallbacks.ts +41 -0
package/.prettierc.json
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# 🚂 TS Railway Result
|
|
2
|
+
|
|
3
|
+
A robust, lightweight, and type-safe implementation of **Railway Oriented Programming (ROP)** for TypeScript.
|
|
4
|
+
Eliminate `try/catch` spaghetti code and handle errors elegantly using **Results** and **Decorators**.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## 📦 Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @rotomeca/rop
|
|
13
|
+
# or
|
|
14
|
+
yarn add @rotomeca/rop
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 🚀 Quick Start
|
|
18
|
+
|
|
19
|
+
Transform your risky operations into safe "Rails" using decorators.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { Risky, HappyPath, ErrorPath, Result } from '@rotomeca/rop';
|
|
23
|
+
|
|
24
|
+
class UserService {
|
|
25
|
+
|
|
26
|
+
@ErrorPath((err) => console.error(`[Admin Alert] Failed to create user: ${err.message}`))
|
|
27
|
+
@HappyPath((user) => console.log(`[Analytics] User created: ${user.name}`))
|
|
28
|
+
@Risky() // Automatically catches exceptions and converts return value to Result
|
|
29
|
+
async createUser(name: string, age: number): Promise<Result<{ name: string }>> {
|
|
30
|
+
|
|
31
|
+
if (name.length < 3) {
|
|
32
|
+
throw new Error("Name too short"); // Will be converted to Fail(Error)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Simulate DB call
|
|
36
|
+
return { name }; // Will be converted to Success({ name })
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Usage
|
|
41
|
+
async function main() {
|
|
42
|
+
const service = new UserService();
|
|
43
|
+
|
|
44
|
+
const result = await service.createUser("Alice", 25);
|
|
45
|
+
|
|
46
|
+
result.match({
|
|
47
|
+
Ok: (user) => console.log(`Welcome ${user.name}!`),
|
|
48
|
+
Err: (error) => console.log(`Oops: ${error.message}`)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## ✨ Features
|
|
54
|
+
|
|
55
|
+
* **🛡️ Type-Safe Error Handling**: No more guessing if a function throws. Returns `Result<T, E>`.
|
|
56
|
+
* **✨ Powerful Decorators**:
|
|
57
|
+
* `@Risky`: Wraps methods to catch exceptions and return `Success` or `Fail`.
|
|
58
|
+
* `@HappyPath`: Execute side effects (logging, events) only on success.
|
|
59
|
+
* `@ErrorPath`: Execute side effects (monitoring, alerts) only on failure.
|
|
60
|
+
* **⛓️ Fluent API**: Chain operations with `map`, `andThen` (flatMap), and `unwrapOr`.
|
|
61
|
+
* **🔗 Sync & Async Support**: Works seamlessly with both synchronous functions and Promises.
|
|
62
|
+
|
|
63
|
+
## 📖 Core Concepts
|
|
64
|
+
|
|
65
|
+
### 1. The Result Object (`Result`)
|
|
66
|
+
Instead of throwing exceptions, your functions return an `Result`. It has two states:
|
|
67
|
+
* **`Success<T>`**: The operation succeeded and contains a value of type `T`.
|
|
68
|
+
* **`Fail<E>`**: The operation failed and contains an error of type `E` (default is `Error`).
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { Success, Fail, Result } from '@rotomeca/rop';
|
|
72
|
+
|
|
73
|
+
function divide(a: number, b: number): Result<number> {
|
|
74
|
+
if (b === 0) {
|
|
75
|
+
return Fail.Create(new Error("Cannot divide by zero"));
|
|
76
|
+
}
|
|
77
|
+
return Success.Create(a / b);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 2. Matching (Pattern Matching)
|
|
82
|
+
Force yourself to handle both success and failure cases.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const result = divide(10, 2);
|
|
86
|
+
|
|
87
|
+
const message = result.match({
|
|
88
|
+
Ok: (val) => `Result is ${val}`,
|
|
89
|
+
Err: (err) => `Calculation failed: ${err.message}`
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Decorators
|
|
94
|
+
|
|
95
|
+
#### `@Risky()`
|
|
96
|
+
Automatically wraps the method execution in a `try/catch` block.
|
|
97
|
+
* If the method returns a value, it becomes `Success(value)`.
|
|
98
|
+
* If the method throws, it becomes `Fail(error)`.
|
|
99
|
+
* Works with `async/await` and synchronous code.
|
|
100
|
+
|
|
101
|
+
#### `@HappyPath(fn)` & `@ErrorPath(fn)`
|
|
102
|
+
Perfect for **Side Effects** (logging, notifications) without polluting your business logic. These decorators act as "Taps": they inspect the result but **do not** modify the return value.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
@ErrorPath((e) => Sentry.captureException(e)) // Only if fails
|
|
106
|
+
@HappyPath((data) => Analytics.track('success', data)) // Only if success
|
|
107
|
+
@Risky()
|
|
108
|
+
saveData(data: any) { ... }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 📚 API Reference
|
|
112
|
+
|
|
113
|
+
### `Result<T, E>` Methods
|
|
114
|
+
|
|
115
|
+
| Method | Description |
|
|
116
|
+
| :--- | :--- |
|
|
117
|
+
| **`match({ Ok, Err })`** | Executes `Ok` fn if success, `Err` fn if failure. Returns the result of the function. |
|
|
118
|
+
| **`map(fn)`** | Transforms the inner value `T` to `U` only if Success. |
|
|
119
|
+
| **`mapError(fn)`** | Transforms the inner error `E` to `NewError` only if Fail. |
|
|
120
|
+
| **`andThen(fn)`** | Chains operations. `fn` must return a new `Result`. (Often called `flatMap`). |
|
|
121
|
+
| **`unwrapOr(default)`** | Returns the value if Success, otherwise returns `default`. |
|
|
122
|
+
| **`throwIfError()`** | Unsafe. Returns value if Success, throws the error if Fail. |
|
|
123
|
+
| **`isSuccess() / isError()`** | Boolean checks for the state. |
|
|
124
|
+
|
|
125
|
+
## 🧩 Advanced Usage: Chaining
|
|
126
|
+
|
|
127
|
+
You can build complex pipelines that stop at the first error:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const result = validateInput(input) // returns Result<Input>
|
|
131
|
+
.andThen(parsed => processData(parsed)) // returns Result<Data>
|
|
132
|
+
.andThen(data => saveToDb(data)) // returns Result<Id>
|
|
133
|
+
.map(id => `Created object with ID: ${id}`); // returns Result<string>
|
|
134
|
+
|
|
135
|
+
// If any step failed, 'result' is a Fail with the error of that step.
|
|
136
|
+
// If all succeeded, 'result' is a Success with the final string.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## 📄 License
|
|
140
|
+
|
|
141
|
+
MIT
|
package/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Décorateurs (API Publique principale)
|
|
2
|
+
export * from './src/decorators/Risky';
|
|
3
|
+
export * from './src/decorators/HappyPath';
|
|
4
|
+
export * from './src/decorators/ErrorPath';
|
|
5
|
+
|
|
6
|
+
// Classes & Abstractions (Pour le typage et création manuelle)
|
|
7
|
+
export * from './src/classes/Fail';
|
|
8
|
+
export * from './src/classes/Success';
|
|
9
|
+
export {ATresult as Result} from './src/classes/abstracts/ATresult';
|
|
10
|
+
|
|
11
|
+
// Types (Pour l'IntelliSense)
|
|
12
|
+
export * from './src/types/resultsCallbacks';
|
|
13
|
+
export * from './src/types/ResultMatch';
|
|
14
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rotomeca/rop",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"main": "index.ts",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
},
|
|
8
|
+
"author": "Rotomeca",
|
|
9
|
+
"license": "ISC",
|
|
10
|
+
"description": "A robust, lightweight, and type-safe implementation of Railway Oriented Programming (ROP) for TypeScript.",
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
13
|
+
"eslint": "^8.57.1",
|
|
14
|
+
"prettier": "^3.8.1",
|
|
15
|
+
"prettier-eslint": "^16.4.2",
|
|
16
|
+
"typescript": "^4.9.5"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// type: class
|
|
2
|
+
// description: Class representing a error result.
|
|
3
|
+
|
|
4
|
+
import { ResultState, ITResult } from "../interfaces/ITResult";
|
|
5
|
+
import { ResultMatch } from "../types/ResultMatch";
|
|
6
|
+
import { ChainedCallback, SuccessMapCallback, ErrorMapCallback } from "../types/resultsCallbacks";
|
|
7
|
+
import { ATresult } from "./abstracts/ATresult";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Class representing a failed result.
|
|
11
|
+
* @template TSuccess - The type of the success value.
|
|
12
|
+
* @template TE - The type of the error value (default is Error).
|
|
13
|
+
*/
|
|
14
|
+
export class Fail<TSuccess, TE = Error> extends ATresult<TSuccess, TE> {
|
|
15
|
+
/**
|
|
16
|
+
* Creates an instance of Fail.
|
|
17
|
+
* @param error The error value.
|
|
18
|
+
*/
|
|
19
|
+
constructor(public readonly error: TE) { super(); }
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the state of the result.
|
|
23
|
+
* @returns The state indicating failure.
|
|
24
|
+
*/
|
|
25
|
+
state(): ResultState {
|
|
26
|
+
return ResultState.Error;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Matches the result with the provided matcher functions.
|
|
30
|
+
* @param matcher The matcher object containing functions for success and error cases.
|
|
31
|
+
* @returns The result of the matched function.
|
|
32
|
+
*/
|
|
33
|
+
match<Result>(matcher: ResultMatch<TSuccess, TE, Result>): Result {
|
|
34
|
+
return matcher.Err(this.error);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Chains the result with another operation that returns a new result.
|
|
38
|
+
* @param fn The function to apply if the result is successful.
|
|
39
|
+
* @returns The result of the chained operation.
|
|
40
|
+
*/
|
|
41
|
+
andThen<NewSuccess>(_: ChainedCallback<TSuccess, NewSuccess, TE>): ITResult<NewSuccess, TE> {
|
|
42
|
+
return new Fail<NewSuccess, TE>(this.error);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Maps the success value to a new value.
|
|
46
|
+
* @param fn The function to apply to the success value.
|
|
47
|
+
* @returns A new Success instance containing the mapped value.
|
|
48
|
+
*/
|
|
49
|
+
map<NewSuccess>(_: SuccessMapCallback<TSuccess, NewSuccess>): ITResult<NewSuccess, TE> {
|
|
50
|
+
return new Fail<NewSuccess, TE>(this.error);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Maps the error value to a new error value.
|
|
54
|
+
* @param _ The function to apply to the error value.
|
|
55
|
+
* @returns A new Success instance containing the original success value.
|
|
56
|
+
*/
|
|
57
|
+
mapError<NewError>(fn: ErrorMapCallback<TE, NewError>): ITResult<TSuccess, NewError> {
|
|
58
|
+
return new Fail<TSuccess, NewError>(fn(this.error));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the success value or throws an error if the result is an error.
|
|
63
|
+
* @throws The error value if the result is an error.
|
|
64
|
+
* @returns The success value.
|
|
65
|
+
*/
|
|
66
|
+
throwIfError(): TSuccess {
|
|
67
|
+
throw this.error;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Retrieves the success value or returns the provided default value if the result is an error.
|
|
72
|
+
* @param defaultValue The value to return if the result is an error.
|
|
73
|
+
* @returns The success value if the result is a success, otherwise the default value.
|
|
74
|
+
*/
|
|
75
|
+
unwrapOr(defaultValue: TSuccess): TSuccess {
|
|
76
|
+
return defaultValue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates a new Fail instance.
|
|
81
|
+
* @param error The error value.
|
|
82
|
+
* @returns A new Fail instance containing the error.
|
|
83
|
+
*
|
|
84
|
+
* @template TSuccess - The type of the success value.
|
|
85
|
+
* @template TE - The type of the error value (default is Error).
|
|
86
|
+
*
|
|
87
|
+
* @static
|
|
88
|
+
*/
|
|
89
|
+
static Create<TSuccess, TE = Error>(error: TE): Fail<TSuccess, TE> {
|
|
90
|
+
return new Fail(error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// type: class
|
|
2
|
+
// description: Class representing a successful result.
|
|
3
|
+
|
|
4
|
+
import { ResultState, ITResult } from "../interfaces/ITResult";
|
|
5
|
+
import { ResultMatch } from "../types/ResultMatch";
|
|
6
|
+
import { ChainedCallback, SuccessMapCallback, ErrorMapCallback } from "../types/resultsCallbacks";
|
|
7
|
+
import { ATresult } from "./abstracts/ATresult";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Class representing a successful result.
|
|
11
|
+
* @template TSuccess - The type of the success value.
|
|
12
|
+
* @template TE - The type of the error value (default is Error).
|
|
13
|
+
*/
|
|
14
|
+
export class Success<TSuccess, TE = Error> extends ATresult<TSuccess, TE> {
|
|
15
|
+
/**
|
|
16
|
+
* Creates an instance of Success.
|
|
17
|
+
* @param value The success value.
|
|
18
|
+
*/
|
|
19
|
+
constructor(public readonly value: TSuccess) { super(); }
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the state of the result.
|
|
23
|
+
* @returns The state indicating success.
|
|
24
|
+
*/
|
|
25
|
+
state(): ResultState {
|
|
26
|
+
return ResultState.Success;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Matches the result with the provided matcher functions.
|
|
30
|
+
* @param matcher The matcher object containing functions for success and error cases.
|
|
31
|
+
* @returns The result of the matched function.
|
|
32
|
+
*/
|
|
33
|
+
match<Result>(matcher: ResultMatch<TSuccess, TE, Result>): Result {
|
|
34
|
+
return matcher.Ok(this.value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Chains the result with another operation that returns a new result.
|
|
38
|
+
* @param fn The function to apply if the result is successful.
|
|
39
|
+
* @returns The result of the chained operation.
|
|
40
|
+
*/
|
|
41
|
+
andThen<NewSuccess>(fn: ChainedCallback<TSuccess, NewSuccess, TE>): ITResult<NewSuccess, TE> {
|
|
42
|
+
return fn(this.value);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Maps the success value to a new value.
|
|
46
|
+
* @param fn The function to apply to the success value.
|
|
47
|
+
* @returns A new Success instance containing the mapped value.
|
|
48
|
+
*/
|
|
49
|
+
map<NewSuccess>(fn: SuccessMapCallback<TSuccess, NewSuccess>): ITResult<NewSuccess, TE> {
|
|
50
|
+
return new Success(fn(this.value));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Maps the error value to a new error value.
|
|
54
|
+
* @param _ The function to apply to the error value.
|
|
55
|
+
* @returns A new Success instance containing the original success value.
|
|
56
|
+
*/
|
|
57
|
+
mapError<NewError>(_: ErrorMapCallback<TE, NewError>): ITResult<TSuccess, NewError> {
|
|
58
|
+
return new Success<TSuccess, NewError>(this.value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the success value or throws an error if the result is an error.
|
|
63
|
+
* @returns The success value.
|
|
64
|
+
*/
|
|
65
|
+
throwIfError(): TSuccess {
|
|
66
|
+
return this.value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Retrieves the success value or returns the provided default value if the result is an error.
|
|
71
|
+
* @param _ The value to return if the result is an error.
|
|
72
|
+
* @returns The success value if the result is a success, otherwise the default value.
|
|
73
|
+
*/
|
|
74
|
+
unwrapOr(_: TSuccess): TSuccess {
|
|
75
|
+
return this.value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a new Success instance.
|
|
80
|
+
* @param value The success value.
|
|
81
|
+
* @returns A new Success instance containing the value.
|
|
82
|
+
*
|
|
83
|
+
* @template TSuccess - The type of the success value.
|
|
84
|
+
* @template TE - The type of the error value (default is Error).
|
|
85
|
+
*
|
|
86
|
+
* @static
|
|
87
|
+
*/
|
|
88
|
+
static Create<TSuccess, TE = Error>(value: TSuccess): Success<TSuccess, TE> {
|
|
89
|
+
return new Success(value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// type: class
|
|
2
|
+
// description: Abstract class implementing the ITResult interface.
|
|
3
|
+
|
|
4
|
+
import { ResultState, ITResult } from "../../interfaces/ITResult";
|
|
5
|
+
import { ResultMatch } from "../../types/ResultMatch";
|
|
6
|
+
import { ChainedCallback, ErrorMapCallback, SuccessMapCallback } from "../../types/resultsCallbacks";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Abstract class representing a result that can be either a success or an error.
|
|
10
|
+
*/
|
|
11
|
+
export abstract class ATresult<Success, E = Error> implements ITResult<Success, E> {
|
|
12
|
+
/**
|
|
13
|
+
* Gets the current state of the result.
|
|
14
|
+
*
|
|
15
|
+
* @returns The state of the result, either Success or Error.
|
|
16
|
+
*/
|
|
17
|
+
abstract state(): ResultState;
|
|
18
|
+
/**
|
|
19
|
+
* Matches the result with the provided matcher functions.
|
|
20
|
+
*
|
|
21
|
+
* @param matcher - An object containing callback functions for success and error cases.
|
|
22
|
+
* @returns The result of applying the appropriate matcher function.
|
|
23
|
+
*/
|
|
24
|
+
abstract match<Result>(matcher: ResultMatch<Success, E, Result>): Result;
|
|
25
|
+
/**
|
|
26
|
+
* Chains the result with another operation that returns a new result.
|
|
27
|
+
*
|
|
28
|
+
* @param fn - A callback function that takes the success value and returns a new result.
|
|
29
|
+
* @returns A new result after applying the chained operation.
|
|
30
|
+
*/
|
|
31
|
+
abstract andThen<NewSuccess>(fn: ChainedCallback<Success, NewSuccess, E>): ITResult<NewSuccess, E>;
|
|
32
|
+
/**
|
|
33
|
+
* Maps the success value to a new value.
|
|
34
|
+
*
|
|
35
|
+
* @param fn - A callback function that takes the success value and returns a new success value.
|
|
36
|
+
* @returns A new result with the mapped success value.
|
|
37
|
+
*/
|
|
38
|
+
abstract map<NewSuccess>(fn: SuccessMapCallback<Success, NewSuccess>): ITResult<NewSuccess, E>;
|
|
39
|
+
/**
|
|
40
|
+
* Maps the error value to a new value.
|
|
41
|
+
*
|
|
42
|
+
* @param fn - A callback function that takes the error value and returns a new error value.
|
|
43
|
+
* @returns A new result with the mapped error value.
|
|
44
|
+
*/
|
|
45
|
+
abstract mapError<NewError>(fn: ErrorMapCallback<E, NewError>): ITResult<Success, NewError>;
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves the success value or throws an error if the result is an error.
|
|
48
|
+
* @throws The error value if the result is an error.
|
|
49
|
+
* @returns The success value if the result is a success.
|
|
50
|
+
*/
|
|
51
|
+
abstract throwIfError(): Success;
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the success value or returns the provided default value if the result is an error.
|
|
54
|
+
* @param defaultValue The value to return if the result is an error.
|
|
55
|
+
* @returns The success value if the result is a success, otherwise the default value.
|
|
56
|
+
*/
|
|
57
|
+
abstract unwrapOr(defaultValue: Success): Success;
|
|
58
|
+
/**
|
|
59
|
+
* Checks if the result is a success.
|
|
60
|
+
*
|
|
61
|
+
* @returns True if the result is a success, false otherwise.
|
|
62
|
+
*/
|
|
63
|
+
isSuccess(): boolean {
|
|
64
|
+
return this.state() === ResultState.Success;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Checks if the result is an error.
|
|
68
|
+
*
|
|
69
|
+
* @returns True if the result is an error, false otherwise.
|
|
70
|
+
*/
|
|
71
|
+
isError(): boolean {
|
|
72
|
+
return this.state() === ResultState.Error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//type: functions
|
|
2
|
+
//description: Functions to handle error path operations by executing a callback on errored results.
|
|
3
|
+
import { ATresult } from "../../classes/abstracts/ATresult";
|
|
4
|
+
import { applyMatch } from "../../functions/applyMatch";
|
|
5
|
+
import { ErrorCallback } from "../../types/resultsCallbacks";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Handles the error path for synchronous functions by executing a callback on errored results.
|
|
9
|
+
* @param this The context in which the original function is called.
|
|
10
|
+
* @param original The original function to be wrapped.
|
|
11
|
+
* @param path The error callback to be executed on errored results.
|
|
12
|
+
* @param args Arguments to be passed to the original function.
|
|
13
|
+
* @returns The result of the original function or the result of the error callback.
|
|
14
|
+
*/
|
|
15
|
+
export function errorPathSync(this: any, original: Function, path: ErrorCallback<any, any>, ...args: any[]): any {
|
|
16
|
+
const result = original.call(this, ...args);
|
|
17
|
+
|
|
18
|
+
return result instanceof ATresult
|
|
19
|
+
? applyMatch(result, undefined, path)
|
|
20
|
+
: result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handles the error path for asynchronous functions by executing a callback on errored results.
|
|
25
|
+
* @param this The context in which the original function is called.
|
|
26
|
+
* @param original The original function to be wrapped.
|
|
27
|
+
* @param path The error callback to be executed on errored results.
|
|
28
|
+
* @param args Arguments to be passed to the original function.
|
|
29
|
+
* @returns The result of the original function or the result of the error callback.
|
|
30
|
+
*/
|
|
31
|
+
export async function errorPathAsync(this: any, original: Function, path: ErrorCallback<any, any>, ...args: any[]): any {
|
|
32
|
+
const result = await original.call(this, ...args);
|
|
33
|
+
|
|
34
|
+
return result instanceof ATresult
|
|
35
|
+
? applyMatch(result, undefined, path)
|
|
36
|
+
: result;
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//type: decorator
|
|
2
|
+
//description: Decorator to handle error path operations by executing a callback on errored results.
|
|
3
|
+
|
|
4
|
+
import { ErrorCallback } from "../types/resultsCallbacks";
|
|
5
|
+
import { errorPathAsync, errorPathSync } from "./ErrorPath.internal/functions";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Decorator to handle error path operations by executing a callback on errored results.
|
|
9
|
+
* @param fn Error path callback to be executed on errored results.
|
|
10
|
+
* @returns A method decorator that wraps the original method with error path handling.
|
|
11
|
+
*/
|
|
12
|
+
export function ErrorPath<T>(fn: ErrorCallback<T, void>) {
|
|
13
|
+
return function (target: any, key: string, descriptor: PropertyDescriptor) {
|
|
14
|
+
const original = descriptor.value;
|
|
15
|
+
const isAsync = original.constructor.name === "AsyncFunction";
|
|
16
|
+
|
|
17
|
+
if (isAsync) {
|
|
18
|
+
descriptor.value = async function (this: any, ...args: any[]) {
|
|
19
|
+
return await errorPathAsync.call(this, original, fn, ...args);
|
|
20
|
+
};
|
|
21
|
+
} else {
|
|
22
|
+
descriptor.value = function (this: any, ...args: any[]) {
|
|
23
|
+
return errorPathSync.call(this, original, fn, ...args);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return descriptor;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//type: functions
|
|
2
|
+
//description: Functions to handle happy path operations by executing a callback on successful results.
|
|
3
|
+
import { ATresult } from "../../classes/abstracts/ATresult";
|
|
4
|
+
import { applyMatch } from "../../functions/applyMatch";
|
|
5
|
+
import { SuccessCallback } from "../../types/resultsCallbacks";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Handles the happy path for synchronous functions by executing a callback on successful results.
|
|
9
|
+
* @param this The context in which the original function is called.
|
|
10
|
+
* @param original The original function to be wrapped.
|
|
11
|
+
* @param path The success callback to be executed on successful results.
|
|
12
|
+
* @param args Arguments to be passed to the original function.
|
|
13
|
+
* @returns The result of the original function or the result of the success callback.
|
|
14
|
+
*/
|
|
15
|
+
export function happyPathSync(this: any, original: Function, path: SuccessCallback<any, any>, ...args: any[]): any {
|
|
16
|
+
const result = original.call(this, ...args);
|
|
17
|
+
|
|
18
|
+
return result instanceof ATresult
|
|
19
|
+
? applyMatch(result, path, undefined)
|
|
20
|
+
: result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handles the happy path for asynchronous functions by executing a callback on successful results.
|
|
25
|
+
* @param this The context in which the original function is called.
|
|
26
|
+
* @param original The original function to be wrapped.
|
|
27
|
+
* @param path The success callback to be executed on successful results.
|
|
28
|
+
* @param args Arguments to be passed to the original function.
|
|
29
|
+
* @returns The result of the original function or the result of the success callback.
|
|
30
|
+
*/
|
|
31
|
+
export async function happyPathASync(this: any, original: Function, path: SuccessCallback<any, any>, ...args: any[]): any {
|
|
32
|
+
const result = await original.call(this, ...args);
|
|
33
|
+
|
|
34
|
+
return result instanceof ATresult
|
|
35
|
+
? applyMatch(result, path, undefined)
|
|
36
|
+
: result;
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//type: decorator
|
|
2
|
+
//description: Decorator to handle happy path operations by executing a callback on successful results.
|
|
3
|
+
|
|
4
|
+
import { SuccessCallback } from "../types/resultsCallbacks";
|
|
5
|
+
import { happyPathASync, happyPathSync } from "./HappyPath.internal/functions";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Decorator to handle happy path operations by executing a callback on successful results.
|
|
9
|
+
* @param fn Happy path callback to be executed on successful results.
|
|
10
|
+
* @returns A method decorator that wraps the original method with happy path handling.
|
|
11
|
+
*/
|
|
12
|
+
export function HappyPath<T>(fn: SuccessCallback<T, void>) {
|
|
13
|
+
return function (target: any, key: string, descriptor: PropertyDescriptor) {
|
|
14
|
+
const original = descriptor.value;
|
|
15
|
+
const isAsync = original.constructor.name === "AsyncFunction";
|
|
16
|
+
|
|
17
|
+
if (isAsync) {
|
|
18
|
+
descriptor.value = async function (this: any, ...args: any[]) {
|
|
19
|
+
return await happyPathASync.call(this, original, fn, ...args);
|
|
20
|
+
};
|
|
21
|
+
} else {
|
|
22
|
+
descriptor.value = function (this: any, ...args: any[]) {
|
|
23
|
+
return happyPathSync.call(this, original, fn, ...args);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return descriptor;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// type: functions
|
|
2
|
+
// description: Functions to handle risky operations by converting exceptions into Result types.
|
|
3
|
+
|
|
4
|
+
import { ATresult } from "../../classes/abstracts/ATresult";
|
|
5
|
+
import { Fail } from "../../classes/Fail";
|
|
6
|
+
import { Success } from "../../classes/Success";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Handles synchronous risky operations by converting exceptions into Result types.
|
|
10
|
+
* @param this The context in which the original function is called.
|
|
11
|
+
* @param original The original function to be executed.
|
|
12
|
+
* @param args Arguments to be passed to the original function.
|
|
13
|
+
* @returns An ATresult representing success or failure.
|
|
14
|
+
*/
|
|
15
|
+
export function riskySync(this: any, original: Function, ...args: any[]): ATresult<any> {
|
|
16
|
+
try {
|
|
17
|
+
const result = original.apply(this, args);
|
|
18
|
+
|
|
19
|
+
return result instanceof ATresult ? result : Success.Create(result);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return error instanceof ATresult ? error : Fail.Create(error as Error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Handles asynchronous risky operations by converting exceptions into Result types.
|
|
27
|
+
* @param this The context in which the original function is called.
|
|
28
|
+
* @param original The original function to be executed.
|
|
29
|
+
* @param args Arguments to be passed to the original function.
|
|
30
|
+
* @returns A Promise that resolves to an ATresult representing success or failure.
|
|
31
|
+
*/
|
|
32
|
+
export async function riskyAsync(this: any, original: Function, ...args: any[]): Promise<ATresult<any>> {
|
|
33
|
+
try {
|
|
34
|
+
const result = await original.apply(this, args);
|
|
35
|
+
|
|
36
|
+
return result instanceof ATresult ? result : Success.Create(result);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return error instanceof ATresult ? error : Fail.Create(error as Error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// type: decorator
|
|
2
|
+
// description: Decorator to handle risky operations by converting exceptions into Result types.
|
|
3
|
+
import { riskyAsync, riskySync } from "./Risky.internal/functions";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Decorator to handle risky operations by converting exceptions into Result types.
|
|
7
|
+
* @returns A method decorator that wraps the original method with error handling.
|
|
8
|
+
*/
|
|
9
|
+
export function Risky() {
|
|
10
|
+
return function (target: any, key: string, descriptor: PropertyDescriptor) {
|
|
11
|
+
const original = descriptor.value;
|
|
12
|
+
|
|
13
|
+
const isAsync = original.constructor.name === "AsyncFunction";
|
|
14
|
+
|
|
15
|
+
if (isAsync) {
|
|
16
|
+
descriptor.value = async function (this: any, ...args: any[]) {
|
|
17
|
+
return riskyAsync.call(this, original, ...args);
|
|
18
|
+
};
|
|
19
|
+
} else {
|
|
20
|
+
descriptor.value = function (this: any, ...args: any[]) {
|
|
21
|
+
return riskySync.call(this, original, ...args);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return descriptor;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//type: function
|
|
2
|
+
//description: Function to apply match on a result with optional callbacks.
|
|
3
|
+
|
|
4
|
+
import { ATresult } from "../classes/abstracts/ATresult";
|
|
5
|
+
import { SuccessCallback, ErrorCallback } from "../types/resultsCallbacks";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Applies match on the given result with optional success and error callbacks.
|
|
9
|
+
* @param result Result to apply match on.
|
|
10
|
+
* @param onSuccess Additional callback for success case.
|
|
11
|
+
* @param onError Additional callback for error case.
|
|
12
|
+
* @returns Returns the original result after applying the match.
|
|
13
|
+
*/
|
|
14
|
+
export function applyMatch(
|
|
15
|
+
result: ATresult<any>,
|
|
16
|
+
onSuccess?: SuccessCallback<any, any>,
|
|
17
|
+
onError?: ErrorCallback<any, any>
|
|
18
|
+
): ATresult<any> {
|
|
19
|
+
return result.match({
|
|
20
|
+
Ok: (val) => {
|
|
21
|
+
if (onSuccess) onSuccess(val);
|
|
22
|
+
return result;
|
|
23
|
+
},
|
|
24
|
+
Err: (err) => {
|
|
25
|
+
if (onError) onError(err);
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// type: interface
|
|
2
|
+
// description: Interface for a result type that can represent either a success or an error.
|
|
3
|
+
|
|
4
|
+
import { ResultMatch } from "../types/ResultMatch";
|
|
5
|
+
import { ChainedCallback, ErrorMapCallback, SuccessMapCallback } from "../types/resultsCallbacks";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enumeration representing the state of the result.
|
|
9
|
+
*/
|
|
10
|
+
export enum ResultState {
|
|
11
|
+
/**
|
|
12
|
+
* The result represents a successful outcome.
|
|
13
|
+
*/
|
|
14
|
+
Success,
|
|
15
|
+
/**
|
|
16
|
+
* The result represents an error outcome.
|
|
17
|
+
*/
|
|
18
|
+
Error
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Interface representing a result that can be either a success or an error.
|
|
23
|
+
*
|
|
24
|
+
* @template Success - The type of the success value.
|
|
25
|
+
* @template Error - The type of the error value.
|
|
26
|
+
*/
|
|
27
|
+
export declare interface ITResult<Success, Error> {
|
|
28
|
+
/**
|
|
29
|
+
* Gets the current state of the result.
|
|
30
|
+
*
|
|
31
|
+
* @returns The state of the result, either Success or Error.
|
|
32
|
+
*/
|
|
33
|
+
state(): ResultState;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the result is a success.
|
|
36
|
+
*
|
|
37
|
+
* @returns True if the result is a success, false otherwise.
|
|
38
|
+
*/
|
|
39
|
+
isSuccess(): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Checks if the result is an error.
|
|
42
|
+
*
|
|
43
|
+
* @returns True if the result is an error, false otherwise.
|
|
44
|
+
*/
|
|
45
|
+
isError(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Matches the result with the provided matcher functions.
|
|
48
|
+
*
|
|
49
|
+
* @param matcher An object containing functions to handle success and error cases.
|
|
50
|
+
* @returns The result of applying the appropriate matcher function.
|
|
51
|
+
*/
|
|
52
|
+
match<Result>(matcher: ResultMatch<Success, Error, Result>): Result;
|
|
53
|
+
/**
|
|
54
|
+
* Chains another result-producing function to be executed if this result is a success.
|
|
55
|
+
*
|
|
56
|
+
* @param fn A function that takes the success value and returns a new result.
|
|
57
|
+
* @returns The new result produced by the function, or the current error result.
|
|
58
|
+
*/
|
|
59
|
+
andThen<NewSuccess>(fn: ChainedCallback<Success, NewSuccess, Error>): ITResult<NewSuccess, Error>;
|
|
60
|
+
/**
|
|
61
|
+
* Transforms the success value using the provided function.
|
|
62
|
+
*
|
|
63
|
+
* @param fn A function that takes the success value and returns a new success value.
|
|
64
|
+
* @returns A new result with the transformed success value, or the current error result.
|
|
65
|
+
*/
|
|
66
|
+
map<NewSuccess>(fn: SuccessMapCallback<Success, NewSuccess>): ITResult<NewSuccess, Error>;
|
|
67
|
+
/**
|
|
68
|
+
* Transforms the error value using the provided function.
|
|
69
|
+
*
|
|
70
|
+
* @param fn A function that takes the error value and returns a new error value.
|
|
71
|
+
* @returns A new result with the transformed error value, or the current success result.
|
|
72
|
+
*/
|
|
73
|
+
mapError<NewError>(fn: ErrorMapCallback<Error, NewError>): ITResult<Success, NewError>;
|
|
74
|
+
/**
|
|
75
|
+
* Retrieves the success value or throws an error if the result is an error.
|
|
76
|
+
* @throws The error value if the result is an error.
|
|
77
|
+
* @returns The success value if the result is a success.
|
|
78
|
+
*/
|
|
79
|
+
throwIfError(): Success;
|
|
80
|
+
/**
|
|
81
|
+
* Retrieves the success value or returns the provided default value if the result is an error.
|
|
82
|
+
* @param defaultValue The value to return if the result is an error.
|
|
83
|
+
* @returns The success value if the result is a success, otherwise the default value.
|
|
84
|
+
*/
|
|
85
|
+
unwrapOr(defaultValue: Success): Success;
|
|
86
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// type: type
|
|
2
|
+
// description: Type representing the matcher functions for a result type.
|
|
3
|
+
|
|
4
|
+
import { ErrorCallback, SuccessCallback } from "./resultsCallbacks";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Type representing the matcher functions for a result type.
|
|
8
|
+
*
|
|
9
|
+
* @template Success - The type of the success value.
|
|
10
|
+
* @template Error - The type of the error value.
|
|
11
|
+
* @template Result - The type of the result produced by the matcher functions.
|
|
12
|
+
*/
|
|
13
|
+
export type ResultMatch<Success, Error, Result> = {
|
|
14
|
+
/**
|
|
15
|
+
* Callback function to handle the success case.
|
|
16
|
+
*/
|
|
17
|
+
Ok: SuccessCallback<Success, Result>;
|
|
18
|
+
/**
|
|
19
|
+
* Callback function to handle the error case.
|
|
20
|
+
*/
|
|
21
|
+
Err: ErrorCallback<Error, Result>;
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// type: types
|
|
2
|
+
// description: Callback types for handling results in a functional way.
|
|
3
|
+
|
|
4
|
+
import { ITResult } from "../interfaces/ITResult";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Callback type for handling success values.
|
|
8
|
+
*
|
|
9
|
+
* @template Success - The type of the success value.
|
|
10
|
+
* @template Result - The type of the result produced by the callback.
|
|
11
|
+
*/
|
|
12
|
+
export declare type SuccessCallback<Success, Result> = (value: Success) => Result;
|
|
13
|
+
/**
|
|
14
|
+
* Callback type for handling error values.
|
|
15
|
+
*
|
|
16
|
+
* @template Error - The type of the error value.
|
|
17
|
+
* @template Result - The type of the result produced by the callback.
|
|
18
|
+
*/
|
|
19
|
+
export declare type ErrorCallback<Error, Result> = (error: Error) => Result;
|
|
20
|
+
/**
|
|
21
|
+
* Callback type for chaining result-producing functions.
|
|
22
|
+
*
|
|
23
|
+
* @template Success - The type of the success value.
|
|
24
|
+
* @template NewSuccess - The type of the new success value produced by the chained function.
|
|
25
|
+
* @template Error - The type of the error value.
|
|
26
|
+
*/
|
|
27
|
+
export declare type ChainedCallback<Success, NewSuccess, Error> = (value: Success) => ITResult<NewSuccess, Error>;
|
|
28
|
+
/**
|
|
29
|
+
* Callback type for transforming success values.
|
|
30
|
+
*
|
|
31
|
+
* @template Success - The type of the success value.
|
|
32
|
+
* @template NewSuccess - The type of the new success value after transformation.
|
|
33
|
+
*/
|
|
34
|
+
export declare type SuccessMapCallback<Success, NewSuccess> = (value: Success) => NewSuccess
|
|
35
|
+
/**
|
|
36
|
+
* Callback type for transforming error values.
|
|
37
|
+
*
|
|
38
|
+
* @template Error - The type of the error value.
|
|
39
|
+
* @template NewError - The type of the new error value after transformation.
|
|
40
|
+
*/
|
|
41
|
+
export declare type ErrorMapCallback<Error, NewError> = (value: Error) => NewError
|