Skip to content

Commit

Permalink
Add generated documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbasin committed Nov 12, 2024
1 parent b4c983b commit 1ce646f
Show file tree
Hide file tree
Showing 14 changed files with 2,704 additions and 30 deletions.
39 changes: 19 additions & 20 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@
name: Node.js CI

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
build:
runs-on: ubuntu-latest

runs-on: ubuntu-latest
strategy:
matrix:
node-version: [21.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

strategy:
matrix:
node-version: [18.x, 20.x, 21.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm install
- run: npm test
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm install
- run: npm test
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,8 @@ Result.CombineFactories(factories, { concurrency: 2 })
```

### Other handy API
This library also provides API to **retry(), delay() and others**. See inline comments for more documentation
This library also provides API to **retry(), delay() and others**. See inline comments for more documentation

## Documentation

Comprehensive documentation can be found in [**documentation pages**](./docs/globals.md).
200 changes: 200 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
**@vladbasin/ts-result**[**Docs**](globals.md)

***

# ts-result

[![Node.js CI](https://github.com/vladbasin/ts-result/actions/workflows/node.js.yml/badge.svg?branch=master)](https://github.com/vladbasin/ts-result/actions/workflows/node.js.yml)

This library brings elements of functional programming to TypeScript/JavaScript. See Use cases section for details.

## Install

### npm
`npm install @vladbasin/ts-result`

### yarn
`yarn add @vladbasin/ts-result`

## Use cases

### Asynchronous code chaining
Let's assume you have to work with a set of async methods, which load data from the backend and return a Promise. Normally you use try\catch, async\await, then\catch, if\then\else to handle results. Readability isn't really good with this approach.

```typescript
showLoader();
try {
const wallet = await getWalletAsync();
if (wallet.money < 10) {
alert("Not enough money");
return;
}
const item = await getItemAsync();
const response = await purchaseAsync(item);
if (!response.success) {
alert(response.error);
return;
}
log("Purchase success");
}
catch (error) {
alert(error);
}
finally {
hideLoader();
}
```

However, **with this library instead** you can write nice readable chains of methods:

```typescript
import { Result } from "@vladbasin/ts-result";

showLoader();
Result
.FromPromise(getWalletAsync())
.ensure(wallet => wallet.money > 10, "Not enough money")
.onSuccess(() => getItemAsync(itemId))
.onSuccess(item => purchaseAsync(item))
.ensure(response => response.success, response.error)
.onFailure(error => alert(error))
.onSuccess(() => log("Purchase success"))
.onBoth(result => hideLoader())
.run();
```

### Rid of primitive obsession

Without this library (poor readability, code repeats)

```typescript
const usernameValidation = validateUsername(username);
if (!usernameValidation.success) {
alert(usernameValidation.error)
return;
}
const passwordValidation = validatePassword(password);
if (!passwordValidation.success) {
alert(passwordValidation.error)
return;
}
const passwordRepeatValidation = validatePasswordRepeat(passwordRepeat, password);
if (!passwordRepeatValidation.success) {
alert(passwordRepeatValidation.error)
return;
}
```

With this library (readable code, reusable logic)

```typescript
import { Result } from "@vladbasin/ts-result";

Result
.Start()
.onSuccess(() => validateUsername(username))
.onSuccess(() => validatePassword(password))
.onSuccess(() => validatePasswordRepeat(passwordRepeat, password))
.onFailure(error => alert(error))
.run();
```

### Error processing
In complex systems, it's often necessary to handle errors in a way that avoids multiple processing and overriding, especially when multiple services are involved. For example, errors might be localized, and you need to ensure that an error is processed only once and not overridden by subsequent services.

To achieve this, you can use methods like `withProcessedError` to mark errors as processed. This ensures that subsequent error handling logic does not override the already processed error.

Below code processes failure from `getDataAsync()` call and ensures that error is processed by next service only if it was not processed before:

```typescript
import { Result, ProcessedError } from "@vladbasin/ts-result";

Result
.FromPromise(getDataAsync())
.withProcessedFail(response => accountService.processErrors(response))
.withProcessedFail(response => walletService.processErrors(response)) // will not be called if accountService.processErrors() already processed response and found error
.onFailure((error) => {
// do something with errors
})
.onSuccess((data) => {
// execute logic if getDataAsync call was successful
})
```

### Use as Promises
If you don't want to use `Result` as a return type and continue using `Promise` while benefiting from `Result` functionality, you can always:

- Convert `Result` to `Promise`: `result.asPromise()`
- Convert `Promise` to `Result`: `Result.FromPromise(YOUR_PROMISE)`

### Using Combiner
The `Combiner` class provides several methods to combine multiple `Result` instances into one. This is useful when you need to execute multiple asynchronous operations in parallel and handle their results collectively.

#### Combining Two Results
```typescript
import { Result, Combiner } from "@vladbasin/ts-result";

const result1 = Result.FromPromise(fetchData1());
const result2 = Result.FromPromise(fetchData2());

Combiner.Combine2(result1, result2)
.onSuccess(([data1, data2]) => {
console.log("Data1:", data1);
console.log("Data2:", data2);
})
.onFailure(error => {
console.error("Error:", error);
})
.run();
```

#### Combining Multiple Results

```typescript
import { Result, Combiner } from "@vladbasin/ts-result";

const results = [
Result.FromPromise(fetchData1()),
Result.FromPromise(fetchData2()),
Result.FromPromise(fetchData3())
];

Combiner.CombineMany(results)
.onSuccess(dataArray => {
dataArray.forEach((data, index) => {
console.log(`Data${index + 1}:`, data);
});
})
.onFailure(error => {
console.error("Error:", error);
})
.run();
```

### Controlled Parallel Execution

You can execute multiple actions with given parallelism level (concurrency)

```typescript
import { Result } from "@vladbasin/ts-result";

const factories = [
() => Result.FromPromise(fetchData1()),
() => Result.FromPromise(fetchData2()),
() => Result.FromPromise(fetchData3())
];

Result.CombineFactories(factories, { concurrency: 2 })
.onSuccess(dataArray => {
dataArray.forEach((data, index) => {
console.log(`Data${index + 1}:`, data);
});
})
.onFailure(error => {
console.error("Error:", error);
})
.run();
```

### Other handy API
This library also provides API to **retry(), delay() and others**. See inline comments for more documentation
Loading

0 comments on commit 1ce646f

Please sign in to comment.