-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #140 from seasonedcc/composable-functions
Composable functions
- Loading branch information
Showing
95 changed files
with
11,335 additions
and
11,077 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
## Environments | ||
|
||
Sometimes you want to ensure the safety of certain values that are constant accross sequential compositions. | ||
This parameter is called an environment. And to simplify the composition of this kind of Composable | ||
we always define it with a single input. Therefore we have the type | ||
|
||
```ts | ||
Composable<(input: I, environment: E) => O> | ||
``` | ||
|
||
A common use case would be a sequence of functions that depend on an authorization system. | ||
The currently authenticated user would have to be propagated every time there is a sequential composition. | ||
To avoid such awkwardness we use environments: | ||
|
||
```tsx | ||
import { environment } from 'composable-functions' | ||
const dangerousFunction = composable(async (input: string, { user } : { user: { name: string, admin: boolean } }) => { | ||
// do something that only the admin can do | ||
}) | ||
|
||
const carryUser = environment.pipe(gatherInput, dangerousFunction) | ||
``` | ||
|
||
## Composing with environments | ||
|
||
These combinators are useful for composing functions with environment. Note that the standard parallel compositions will work just fine with the concept of environments. | ||
|
||
### `pipe` | ||
|
||
The environment.pipe function allows you to compose multiple functions in a sequence, forwarding the environment to each function in the chain. | ||
|
||
```ts | ||
import { environment } from 'composable-functions' | ||
|
||
const a = composable((str: string, env: { user: User }) => str === '1') | ||
const b = composable((bool: boolean, env: { user: User }) => bool && env.user.admin) | ||
|
||
const pipeline = environment.pipe(a, b) | ||
|
||
const result = await pipeline('1', { user: { admin: true } }) | ||
/* | ||
result = { | ||
success: true, | ||
data: true, | ||
errors: [] | ||
} | ||
*/ | ||
``` | ||
|
||
### `sequence` | ||
The environment.sequence function works similarly to pipe, but it returns a tuple containing the result of each function in the sequence. | ||
|
||
```ts | ||
import { environment } from 'composable-functions' | ||
|
||
const a = composable((str: string, env: { user: User }) => str === '1') | ||
const b = composable((bool: boolean, env: { user: User }) => bool && env.user.admin) | ||
|
||
const sequence = environment.sequence(a, b) | ||
|
||
const result = await sequence('1', { user: { admin: true } }) | ||
/* | ||
result = { | ||
success: true, | ||
data: [true, true], | ||
errors: [] | ||
} | ||
*/ | ||
``` | ||
|
||
### `branch` | ||
|
||
The environment.branch function adds conditional logic to your compositions, forwarding the environment to each branch as needed. | ||
|
||
```ts | ||
import { composable, environment } from 'composable-functions' | ||
|
||
const adminIncrement = composable((a: number, { user }: { user: { admin: boolean } }) => | ||
user.admin ? a + 1 : a | ||
) | ||
const adminMakeItEven = (sum: number) => sum % 2 != 0 ? adminIncrement : null | ||
const incrementUntilEven = environment.branch(adminIncrement, adminMakeItEven) | ||
|
||
const result = await incrementUntilEven(1, { user: { admin: true } }) | ||
/* | ||
result = { | ||
success: true, | ||
data: 2, | ||
errors: [] | ||
} | ||
*/ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Use composable-functions with a custom parser | ||
|
||
This simple example can be a reference to adapt composable-functions to any other parser library. | ||
|
||
There are two approaches to use composable-functions with a custom parser: | ||
- Create an adapter function that will receive a schema and return a schema in the shape of a `ParserSchena`. Example: [the `adapt` function](./src/adapters.ts). | ||
- Create your custom `withSchema` and `applySchema` that will validate your input and environment and return a `Result`. Example: [the `withArkSchema` and `applyArkSchema` functions](./src/adapters.ts). | ||
|
||
Check out the [`./src`](./src/) directory to understand how we implemented both approaches with [`arktype`](https://github.com/arktypeio/arktype). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "composable-functions-arktype-example", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"main": "src/usage.ts", | ||
"scripts": { | ||
"dev": "tsx src/usage.ts" | ||
}, | ||
"devDependencies": { | ||
"tsx": "^4.7.2" | ||
}, | ||
"dependencies": { | ||
"arktype": "2.0.0-dev.7", | ||
"composable-functions": "file:../../npm", | ||
"typescript": "^5.4.5" | ||
} | ||
} |
Oops, something went wrong.