Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: fix runtime errors in docs examples for playground #247

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/array/list.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ _.list(0, 3, 'y') // [y, y, y, y]
_.list(0, 3, () => 'y') // [y, y, y, y]
_.list(0, 3, i => i) // [0, 1, 2, 3]
_.list(0, 3, i => `y${i}`) // [y0, y1, y2, y3]
_.list(0, 3, obj) // [obj, obj, obj, obj]
_.list(0, 3, {}) // [{}, {}, {}, {}]
_.list(0, 6, i => i, 2) // [0, 2, 4, 6]
```

Expand Down
63 changes: 51 additions & 12 deletions docs/async/defer.mdx
Original file line number Diff line number Diff line change
@@ -1,41 +1,80 @@
---
title: defer
description: Run an async function with deferred functions
description: Defer work until an async function completes
since: 12.1.0
---

### Usage

The `_.defer` functions lets you run an async function, registering functions as you go
that should be deferred until the async function completes, and then executed. This is
really useful in scripts where failure up to or after a specific point will require some
cleanup. It's a bit like a `finally` block.
The `defer` function allows you to run an async function while registering cleanup functions that will execute after it completes. This is useful when you need to clean up resources regardless of whether the main function succeeds or fails, similar to a `finally` block.

A hat tip to Swift's `defer` for the inspiration.
The function passed to `defer` receives a `register` function as its argument. Use this to register cleanup work that should run after the main function finishes.

The function passed to `_.defer` is called with a single `register` function argument that
can be used to register the work you want to be called when the function completes. If your function throws an error and then a registered cleanup function throws
and error it is ignored by default. The register
function supports an optional second `options` argument that lets you configure a rethrow
strategy so that error in the cleanup function is rethrown.
By default, if a cleanup function throws an error after the main function has thrown an error, the cleanup error will be ignored. You can customize this behavior by passing `{ rethrow: true }` to the `register` function to have it rethrow cleanup errors instead.

#### Clean up temporary files

```ts
import * as _ from 'radashi'

// Placeholder functions
const createBuildDir = async () => {
console.log('Creating build directory...')
await _.sleep(100)
console.log('Build directory created.')
return 'build'
}
const build = async () => {
console.log('Building project...')
await _.sleep(100)
console.log('Project built.')
}

await _.defer(async cleanup => {
const buildDir = await createBuildDir()

cleanup(() => fs.unlink(buildDir))

await build()
})
```

#### Clean up resources in an API

```ts
// Placeholder API
const api = {
org: {
create: async () => ({ id: 1 }),
delete: async () => {
console.log('Deleting organization...')
await _.sleep(100)
console.log('Deleted organization.')
},
},
user: {
create: async () => ({ id: 2 }),
delete: async () => {
console.log('Deleting user...')
await _.sleep(100)
console.log('Deleted user.')
},
},
}

// Placeholder test function
const executeTest = async () => {
console.log('Executing test...')
await _.sleep(100)
console.log('Test complete.')
}

await _.defer(async register => {
const org = await api.org.create()
register(async () => api.org.delete(org.id), { rethrow: true })

const user = await api.user.create()
register(async () => api.users.delete(user.id), { rethrow: true })
register(async () => api.user.delete(user.id), { rethrow: true })

await executeTest(org, user)
})
Expand Down
53 changes: 47 additions & 6 deletions docs/async/guard.mdx
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
---
title: guard
description: Have a function return undefined if it errors out
description: Make an async function return undefined if it rejects
since: 12.1.0
---

### Usage

This lets you set a default value if an async function errors out.
The `guard` function allows you to make an async function return `undefined` if it rejects. This is useful when you want to handle errors in a functional way, such as returning a default value.

```ts
const users = (await guard(fetchUsers)) ?? []
import * as _ from 'radashi'

const example = async () => {
throw new Error()
}

const result = (await _.guard(example)) ?? []
// []
```

You can choose to guard only specific errors too
#### Guard only specific errors

The 2nd argument to `guard` is an error predicate. If provided, the function will only return `undefined` if the error matches the predicate.

```ts
const isInvalidUserError = (err: any) => err.code === 'INVALID_ID'
const user = (await guard(fetchUser, isInvalidUserError)) ?? DEFAULT_USER
import * as _ from 'radashi'

const DEFAULT_USER = { name: 'John Doe' }

async function fetchUser(id: string) {
if (id === 'unknown') throw new Error('User does not exist')
if (id === 'oops') throw new ReferenceError()
return { name: 'Jim Jimmy' }
}

const isPlainError = (err: any) => err.name === 'Error'

const userA =
(await _.guard(() => fetchUser('unknown'), isPlainError)) ?? DEFAULT_USER
// { name: "John Doe"}

// This one will reject.
const userB = await _.guard(() => fetchUser('oops'), isPlainError).catch(e => e)
// [object ReferenceError]
```

#### Synchronous guards

The `guard` function also works with synchronous functions.

```ts
import * as _ from 'radashi'

function example() {
throw new Error()
}

const result = _.guard(example) ?? []
// []
```
11 changes: 7 additions & 4 deletions docs/async/map.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ since: 12.1.0

### Usage

A map that handles callback functions that return a promise.
The `map` function is like `Array.prototype.map`, but it works with async functions. Only one item is processed at a time.

```ts
import * as _ from 'radashi'

const userIds = [1, 2, 3, 4]
const api = {
users: {
find: async (id: number) => id < 3,
},
}

const users = await _.map(userIds, async userId => {
return await api.users.find(userId)
})
}) // [true, true, false, false]
```
9 changes: 8 additions & 1 deletion docs/async/reduce.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ A reduce that handles callback functions that return a promise.
import * as _ from 'radashi'

const userIds = [1, 2, 3, 4]
const api = {
users: {
async find(id: number) {
return { name: `person ${id}` }
},
},
}

const users = await _.reduce(
userIds,
Expand All @@ -23,5 +30,5 @@ const users = await _.reduce(
}
},
{},
)
) // { 1: { name: 'person 1' }, 2: { name: 'person 2' }, 3: { name: 'person 3' }, 4: { name: 'person 4' } }
```
19 changes: 15 additions & 4 deletions docs/async/retry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,21 @@ The `backoff` option is like delay but uses a function to sleep -- makes for eas
```ts
import * as _ from 'radashi'

await _.retry({}, api.users.list)
await _.retry({ times: 10 }, api.users.list)
await _.retry({ times: 2, delay: 1000 }, api.users.list)
const api = {
users: {
async list() {
if (Math.random() < 0.5) {
throw new Error('Random error')
}
return []
},
},
}

await _.retry({}, api.users.list) // try 3 times before failing
await _.retry({ times: 10 }, api.users.list) // try 10 times before failing
await _.retry({ times: 2, delay: 1000 }, api.users.list) // try 2 times with 1 second delay

// exponential backoff
await _.retry({ backoff: i => 10 ** i }, api.users.list)
await _.retry({ backoff: i => 10 ** i }, api.users.list) // try 3 times with 10, 100, 1000 ms delay
```
11 changes: 10 additions & 1 deletion docs/async/tryit.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@ The `tryit` function let's you wrap a function to convert it to an error-first f
```ts
import * as _ from 'radashi'

const [err, user] = await _.tryit(api.users.find)(userId)
const api = {
users: {
find: async (id: number) => id < 3 ? { id, name: 'Alice' } : throw new Error('Not found'),
},
}
const userIdA = 1
const userIdB = 3

const [err, user] = await _.tryit(api.users.find)(userId) // [null, { id: 1, name: 'Alice' }]
const [err, user] = await _.tryit(api.users.find)(userIdB) // [Error('Not found'), undefined]
```

### Currying
Expand Down
4 changes: 3 additions & 1 deletion docs/async/withResolvers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ Creates a new promise and returns the resolve and reject functions along with th
The ponyfill for https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers

```ts
const { resolve, reject, promise } = withResolvers()
import * as _ from 'radashi'

const { resolve, reject, promise } = _.withResolvers()

resolve(42)
```
20 changes: 12 additions & 8 deletions docs/curry/debounce.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ If called again during this waiting period, it resets the timer. Your source fun
```ts
import * as _ from 'radashi'

// Send a search request to the API server when the user stops typing
// for at least 100ms.
input.addEventListener(
'change',
_.debounce({ delay: 100 }, (event: InputEvent) => {
api.movies.search(event.target.value)
}),
)
const processData = (data: string) => {
console.log(`Processing data: "${data}"...`)
}
const debouncedProcessData = _.debounce({ delay: 100 }, processData)

debouncedProcessData('data1') // Never logs
debouncedProcessData('data2') // Never logs
debouncedProcessData('data3') // Processing data: "data3"...

setTimeout(() => {
debouncedProcessData('data4') // Processing data: "data4"... (200ms later)
}, 200)
```

## Options
Expand Down
2 changes: 1 addition & 1 deletion docs/curry/once.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Create a wrapper around a given function such that it executes at most once. Sub
```ts
import * as _ from 'radashi'

const fn = once(() => Math.random())
const fn = _.once(() => Math.random())
fn() // 0.5
fn() // 0.5
```
Expand Down
6 changes: 3 additions & 3 deletions docs/curry/throttle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ The returned throttled function also includes these methods:
- `trigger(...args): void`: To invoke the wrapped function without waiting for the next interval

```typescript
import { throttle } from 'radashi'
import * as _ from 'radashi'

// Throttle a scroll event handler
const handleScroll = () => {
console.log('Scroll position:', window.scrollY)
}
const throttledScroll = throttle({ interval: 200 }, handleScroll)
const throttledScroll = _.throttle({ interval: 200 }, handleScroll)
window.addEventListener('scroll', throttledScroll)

// Throttle an API call
const throttledFetch = throttle(
const throttledFetch = _.throttle(
{ interval: 5000, trailing: true },
async () => {
const response = await fetch('https://api.example.com/data')
Expand Down
2 changes: 1 addition & 1 deletion docs/function/castComparator.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The first argument of `castComparator` is called the `mapping`. This can be eith
- **Property Name**: If `mapping` is a property name, it maps the input values to a property of the input values with a comparable value.

```ts
import * as _ from 'radash'
import * as _ from 'radashi'

const users = [
{ id: 1, firstName: 'Alice', lastName: 'Smith' },
Expand Down
15 changes: 10 additions & 5 deletions docs/number/clamp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ range.
```ts
import * as _ from 'radashi'

_.clamp(5, 1, 10) // returns 5
_.clamp(0, 1, 10) // returns 1
_.clamp(15, 1, 10) // returns 10
_.clamp(5, 1, 10) // 5
_.clamp(0, 1, 10) // 1
_.clamp(15, 1, 10) // 10
```

#### Invalid ranges

// Invalid range
_.clamp(1, 10, 1) // throws
If the minimum is greater than the maximum, an error is thrown.

```ts
_.clamp(1, 10, 1) // throws Error
```
4 changes: 3 additions & 1 deletion docs/typed/isResultErr.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ since: 12.2.0
Check if a value is both a `Result` tuple and an `Err` result.

```ts
import * as _ from 'radashi'

declare const value: unknown

if (isResultErr(value)) {
if (_.isResultErr(value)) {
value // <-- now an Err<Error> type
value[0] // <-- This is the error!
}
Expand Down
4 changes: 3 additions & 1 deletion docs/typed/isResultOk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ since: 12.2.0
Check if a value is both a `Result` tuple and an `Ok` result.

```ts
import * as _ from 'radashi'

declare const value: unknown

if (isResultOk(value)) {
if (_.isResultOk(value)) {
value // <-- now an Ok<unknown> type
value[1] // <-- This is the resulting value!
}
Expand Down
Loading