Add vitepress docs

This commit is contained in:
Ticruz
2025-02-04 14:43:40 +01:00
committed by Jon Staab
parent 43255bcb74
commit 94375a56ec
84 changed files with 10821 additions and 139 deletions
+141
View File
@@ -0,0 +1,141 @@
# Deferred Promises
The Deferred module provides utilities for creating promises with exposed resolve/reject functions and typed error handling. This is particularly useful for managing asynchronous operations where you need external control over promise resolution.
## Types
### CustomPromise
```typescript
type CustomPromise<T, E> = Promise<T> & {
__errorType: E
}
```
A Promise type with strongly typed error information.
### Deferred
```typescript
type Deferred<T, E = T> = CustomPromise<T, E> & {
resolve: (arg: T) => void
reject: (arg: E) => void
}
```
A Promise with exposed resolve/reject functions and typed error handling.
## Core Functions
### makePromise
```typescript
function makePromise<T, E>(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason: E) => void
) => void
): CustomPromise<T, E>
```
Creates a Promise with strongly typed error information.
### defer
```typescript
function defer<T, E = T>(): Deferred<T, E>
```
Creates a Deferred promise with resolve/reject methods exposed.
## Usage Examples
### Basic Usage
```typescript
// Create a deferred promise
const deferred = defer<string, Error>()
// Resolve later
setTimeout(() => {
deferred.resolve('Success!')
}, 1000)
// Use like a regular promise
await deferred // => 'Success!'
```
### With Typed Errors
```typescript
interface ApiError {
code: number
message: string
}
const request = defer<Response, ApiError>()
try {
const response = await fetch('/api')
request.resolve(response)
} catch (error) {
request.reject({
code: 500,
message: error.message
})
}
```
### External Promise Control
```typescript
class AsyncOperation {
private ready = defer<boolean>()
initialize() {
// Setup async operation
this.ready.resolve(true)
}
async waitUntilReady() {
return this.ready
}
}
```
### With Timeout
```typescript
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const timeout = defer<T>()
setTimeout(() => {
timeout.reject(new Error('Timeout'))
}, ms)
return Promise.race([promise, timeout])
}
// Usage
try {
const result = await withTimeout(slowOperation(), 5000)
} catch (error) {
console.log('Operation timed out')
}
```
### Event to Promise
```typescript
function eventToPromise<T>(
emitter: EventEmitter,
successEvent: string,
errorEvent: string
): Deferred<T, Error> {
const deferred = defer<T, Error>()
emitter.once(successEvent, (data: T) => {
deferred.resolve(data)
})
emitter.once(errorEvent, (error: Error) => {
deferred.reject(error)
})
return deferred
}
```
+17
View File
@@ -0,0 +1,17 @@
# @welshman/lib
A lightweight TypeScript utility library with zero dependencies, providing essential tools for modern JavaScript development.
## What's Included
- **Deferred Promises** - Create promises with exposed resolve/reject methods
- **LRU Cache** - Efficient caching with automatic eviction policies
- **Utility Functions** - Helpers for arrays, objects, strings, and more
- **Worker Queue** - Process tasks asynchronously with batching and throttling
## Installation
```bash
npm install @welshman/lib
```
+109
View File
@@ -0,0 +1,109 @@
# LRU Cache
The LRU (Least Recently Used) Cache implementation provides efficient caching with automatic eviction of least recently used items when the cache reaches its maximum size.
## Basic Usage
```typescript
// Create cache with max size
const cache = new LRUCache<string, number>(3)
// Add items
cache.set('a', 1)
cache.set('b', 2)
cache.set('c', 3)
// Access items
cache.get('a') // => 1
// Check if key exists
cache.has('b') // => true
// Adding beyond max size evicts least recently used
cache.set('d', 4) // Evicts oldest item
```
## API Reference
### Constructor
```typescript
constructor(maxSize: number = Infinity)
```
Creates a new LRU cache with specified maximum size.
### Methods
#### set(key: T, value: U)
```typescript
set(key: T, value: U): void
```
Adds or updates an item in the cache. If cache is at maximum size, evicts least recently used item.
#### get(key: T)
```typescript
get(key: T): U | undefined
```
Retrieves item from cache. Also marks item as recently used.
#### has(key: T)
```typescript
has(key: T): boolean
```
Checks if key exists in cache without affecting usage tracking.
## Cache Decorator
The package also provides a convenient decorator function for creating memoized functions with LRU caching:
```typescript
function cached<T, V, Args extends any[]>({
maxSize,
getKey,
getValue,
}: {
maxSize: number
getKey: (args: Args) => T
getValue: (args: Args) => V
}): (...args: Args) => V
```
### Usage Example
```typescript
// Create cached function
const getUser = cached({
maxSize: 1000,
getKey: (args) => args[0], // Use first argument as cache key
getValue: async (args) => {
const [id] = args
return await fetchUser(id)
}
})
// Use cached function
const user1 = await getUser(123)
const user2 = await getUser(123) // Returns cached result
```
### Simple Cache Helper
For basic caching needs, there's also a simplified cache creator:
```typescript
function simpleCache<V, Args extends any[]>(
getValue: (args: Args) => V
) {
return cached({
maxSize: 100000,
getKey: xs => xs.join(':'),
getValue
})
}
// Usage
const cachedFn = simpleCache(async (id: string) => {
return await expensiveOperation(id)
})
```
+256
View File
@@ -0,0 +1,256 @@
# Utility Functions
The `Tools.ts` module provides a comprehensive collection of utility functions for common programming tasks. It includes functions for array manipulation, object handling, type checking, math operations, and more.
## Types
```typescript
type Nil = null | undefined
type Maybe<T> = T | undefined
type Obj<T = any> = Record<string, T>
```
## Categories
### Type Checking & Basic Operations
```typescript
// Check if value is null or undefined
isNil(x: any): boolean
// Execute function if value exists
ifLet<T>(x: T | undefined, f: (x: T) => void)
// Return value unchanged
identity<T>(x: T): T
// Create function that always returns same value
always<T>(x: T): () => T
// Logical NOT
not(x: any): boolean
// Create complement of a predicate function
complement<T extends unknown[]>(f: (...args: T) => any): (...args: T) => boolean
```
### Array Operations
```typescript
// Get first element
first<T>(xs: T[]): T | undefined
// Get first element of first array
ffirst<T>(xs: T[][]): T | undefined
// Get last element
last<T>(xs: T[]): T | undefined
// Drop first n elements
drop<T>(n: number, xs: T[]): T[]
// Take first n elements
take<T>(n: number, xs: T[]): T[]
// Remove duplicates
uniq<T>(xs: T[]): T[]
// Remove duplicates by key function
uniqBy<T>(f: (x: T) => any, xs: T[]): T[]
// Create array of n items using generator function
initArray<T>(n: number, f: () => T): T[]
// Split array into chunks
chunk<T>(chunkLength: number, xs: T[]): T[][]
// Split array into n chunks
chunks<T>(n: number, xs: T[]): T[][]
```
### Object Operations
```typescript
// Create object excluding specified keys
omit<T extends Obj>(ks: string[], x: T): T
// Create object excluding entries with specified values
omitVals<T extends Obj>(xs: any[], x: T): T
// Create object with only specified keys
pick<T extends Obj>(ks: string[], x: T): T
// Transform object keys
mapKeys<T extends Obj>(f: (v: string) => string, x: T): T
// Transform object values
mapVals<V, U>(f: (v: V) => U, x: Record<string, V>): Record<string, U>
// Merge objects (left priority)
mergeLeft<T extends Obj>(a: T, b: T): T
// Merge objects (right priority)
mergeRight<T extends Obj>(a: T, b: T): T
// Deep merge objects
deepMergeLeft(a: Obj, b: Obj): Obj
deepMergeRight(a: Obj, b: Obj): Obj
```
### Number Operations
```typescript
// Convert Maybe<number> to number
num(x: Maybe<number>): number
// Basic arithmetic with Maybe<number>
add(x: Maybe<number>, y: Maybe<number>): number
sub(x: Maybe<number>, y: Maybe<number>): number
mul(x: Maybe<number>, y: Maybe<number>): number
div(x: Maybe<number>, y: number): number
// Increment/Decrement
inc(x: Maybe<number>): number
dec(x: Maybe<number>): number
// Comparisons
lt(x: Maybe<number>, y: Maybe<number>): boolean
lte(x: Maybe<number>, y: Maybe<number>): boolean
gt(x: Maybe<number>, y: Maybe<number>): boolean
gte(x: Maybe<number>, y: Maybe<number>): boolean
// Array number operations
max(xs: Maybe<number>[]): number
min(xs: Maybe<number>[]): number
sum(xs: Maybe<number>[]): number
avg(xs: Maybe<number>[]): number
```
### String Operations
```typescript
// Truncate string with ellipsis
ellipsize(s: string, l: number, suffix = "..."): string
// URL operations
stripProtocol(url: string): string
displayUrl(url: string): string
displayDomain(url: string): string
// Bech32 encoding/decoding
hexToBech32(prefix: string, hex: string): string
bech32ToHex(b32: string): string
```
### Collection Operations
```typescript
// Create union of arrays
union<T>(a: T[], b: T[]): T[]
// Get intersection of arrays
intersection<T>(a: T[], b: T[]): T[]
// Get difference of arrays
difference<T>(a: T[], b: T[]): T[]
// Remove element from array
remove<T>(a: T, xs: T[]): T[]
// Filter array by another array
without<T>(a: T[], b: T[]): T[]
// Toggle element in array
toggle<T>(x: T, xs: T[]): T[]
// Group array by key function
groupBy<T, K>(f: (x: T) => K, xs: T[]): Map<K, T[]>
// Create map from array
indexBy<T, K>(f: (x: T) => K, xs: T[]): Map<K, T>
```
### Time Constants
```typescript
const MINUTE = 60
const HOUR = 60 * MINUTE
const DAY = 24 * HOUR
const WEEK = 7 * DAY
const MONTH = 30 * DAY
const QUARTER = 90 * DAY
const YEAR = 365 * DAY
// Get current timestamp in seconds
now(): number
// Get timestamp from ago in seconds
ago(unit: number, count = 1): number
// Convert seconds to milliseconds
ms(seconds: number): number
```
### Function Utilities
```typescript
// Create function that executes once
once(f: (...args: any) => void): (...args: any) => void
// Memoize function results
memoize<T>(f: (...args: any[]) => T): (...args: any[]) => T
// Create throttled function
throttle<F extends (...args: any[]) => any>(
ms: number,
f: F
): F
// Create batching function
batch<T>(
t: number,
f: (xs: T[]) => void
): (x: T) => void
```
### Network Utilities
```typescript
// Fetch JSON with options
fetchJson(url: string, opts?: FetchOpts): Promise<any>
// Post JSON data
postJson<T>(url: string, data: T, opts?: FetchOpts): Promise<any>
// Upload file
uploadFile(url: string, file: File): Promise<any>
```
## Usage Examples
```typescript
// Array operations
const nums = [1, 2, 2, 3, 3, 3]
uniq(nums) // => [1, 2, 3]
// Object operations
const obj = {a: 1, b: 2, c: 3}
omit(['a', 'b'], obj) // => {c: 3}
// Number operations
add(5, undefined) // => 5
inc(undefined) // => 1
// Time operations
ago(DAY, 2) // => timestamp from 2 days ago
// URL operations
displayUrl('https://www.example.com/') // => 'example.com'
// Collection operations
const users = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}]
indexBy(u => u.id, users) // => Map(1 => {id: 1, name: 'Alice'}, ...)
// Function utilities
const throttledFn = throttle(1000, () => console.log('throttled'))
```
+117
View File
@@ -0,0 +1,117 @@
# Worker
The Worker class provides a robust queue processing system with batched operations, throttling, and message routing capabilities. It's designed to handle asynchronous operations efficiently while maintaining control over processing rates and resource usage.
## Overview
```typescript
class Worker<T> {
constructor(readonly opts: WorkerOpts<T> = {})
}
```
The Worker class accepts messages of type `T` and processes them according to configured options and handlers.
## Configuration
```typescript
type WorkerOpts<T> = {
// Function to determine routing key for messages
getKey?: (x: T) => any
// Function to check if message should be deferred
shouldDefer?: (x: T) => boolean
// Maximum messages to process in one batch
chunkSize?: number // default: 50
// Milliseconds between processing batches
delay?: number // default: 50
}
```
## Basic Usage
```typescript
// Create worker for processing messages
const worker = new Worker<Message>({
chunkSize: 10,
delay: 100,
getKey: msg => msg.type
})
// Add message handlers
worker.addHandler('email', async (msg) => {
await sendEmail(msg)
})
worker.addHandler('notification', async (msg) => {
await sendNotification(msg)
})
// Add messages to queue
worker.push({
type: 'email',
content: 'Hello'
})
```
## Features
### Message Routing
Messages can be routed to specific handlers based on a key:
```typescript
const worker = new Worker<Task>({
getKey: task => task.priority
})
// Handle high priority tasks
worker.addHandler('high', async (task) => {
await processUrgent(task)
})
// Handle normal priority tasks
worker.addHandler('normal', async (task) => {
await processNormal(task)
})
```
### Global Handlers
Handle all messages regardless of routing key:
```typescript
worker.addGlobalHandler(async (message) => {
console.log('Processing:', message)
})
```
### Message Deferral
Defer processing of messages that aren't ready:
```typescript
const worker = new Worker<Task>({
shouldDefer: (task) => !task.isReady(),
delay: 1000
})
worker.push(task) // Will retry until task.isReady()
```
### Flow Control
Control message processing:
```typescript
// Pause processing
worker.pause()
// Resume processing
worker.resume()
// Clear queue
worker.clear()
```