### Implement Sequential Async Operations with pipeAsync (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Builds a pipeline to read a file, process its content asynchronously, and save it to a cache. This example showcases `pipeAsync` for managing sequential asynchronous file operations. ```typescript const readFile = async (path: string) => { return `content of ${path}`; }; const processContent = async (content: string) => { await new Promise(r => setTimeout(r, 5)); return content.toUpperCase(); }; const saveToCache = (content: string) => { console.log('Cached:', content); return content; }; const fileProcessor = pipeAsync( readFile, processContent, saveToCache ); await fileProcessor('/data/file.txt'); // "Cached: CONTENT OF /data/file.txt" ``` -------------------------------- ### Build Real-world API Pipeline with pipeAsync (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Constructs a pipeline to fetch user data, enrich it with posts, and add metadata. This example highlights how `pipeAsync` can orchestrate complex asynchronous API calls and data transformations. ```typescript interface User { id: number; name: string; } interface UserProfile { user: User; posts: any[]; metadata: any; } const fetchUser = async (userId: number): Promise => { const response = await fetch(`/api/users/${userId}`); return response.json(); }; const enrichWithPosts = async (user: User) => { const posts = await fetch(`/api/users/${user.id}/posts`).then(r => r.json()); return { ...user, posts }; }; const addMetadata = (data: any) => ({ ...data, metadata: { fetchedAt: new Date().toISOString() } }); const getUserProfile = pipeAsync( fetchUser, enrichWithPosts, addMetadata ); const profile: UserProfile = await getUserProfile(123); ``` -------------------------------- ### Async Generator Handlers in matchblade Source: https://github.com/mendrik/matchblade/blob/main/README.md Demonstrates using async generator functions as handlers within `match` and `caseOf`. This allows pattern matching cases to yield multiple values asynchronously, enabling complex streaming or iterative asynchronous operations. The example shows a case yielding a single string. ```typescript import { match, caseOf } from 'matchblade'; const asyncGenMatcher = match<[number], AsyncGenerator>( caseOf([1], async function* (n) { yield `Number ${n}`; }) ); for await (const val of asyncGenMatcher(1)) { console.log(val); // "Number 1" } ``` -------------------------------- ### Recursive Data Transformation with matchblade traverse (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Demonstrates using the `traverse` function from `matchblade` to recursively transform values in nested data structures. This function takes a callback that is applied to each primitive value, allowing for operations like doubling numbers, uppercasing strings, sanitizing sensitive information, and serializing dates. The examples show direct usage and curried function application. ```typescript import { traverse } from 'matchblade'; // Double all numbers in nested structure const data = { a: 1, b: { c: 2, d: [3, 4, 5] }, e: 'hello', f: { g: { h: 10 } } }; const doubleNumbers = traverse((val: any) => typeof val === 'number' ? val * 2 : val ); const doubled = doubleNumbers(data); console.log(doubled); // Transform all strings to uppercase const config = { app: { name: 'myapp', version: '1.0.0', features: { auth: { provider: 'oauth', type: 'bearer' }, database: { host: 'localhost', name: 'mydb' } } }, count: 42 }; const uppercaseStrings = traverse((val: any) => typeof val === 'string' ? val.toUpperCase() : val ); const uppercased = uppercaseStrings(config); console.log(uppercased.app.name); console.log(uppercased.app.features.auth.provider); // Sanitize sensitive data const user = { id: 1, name: 'Alice', credentials: { password: 'secret123', apiKey: 'sk-1234567890', tokens: ['token1', 'token2'] }, profile: { email: 'alice@example.com', age: 30 } }; const sanitize = traverse((val: any, key?: string) => { const sensitiveKeys = ['password', 'apiKey', 'token']; if (typeof val === 'string' && key && sensitiveKeys.some(k => key.includes(k))) { return '***REDACTED***'; } return val; }); const sanitized = sanitize(user); console.log(sanitized.credentials.password); console.log(sanitized.credentials.apiKey); console.log(sanitized.profile.email); // Convert all dates to ISO strings const events = { created: new Date('2024-01-01'), updated: new Date('2024-02-15'), metadata: { lastAccess: new Date('2024-03-20'), count: 42 } }; const serializeDates = traverse((val: any) => val instanceof Date ? val.toISOString() : val ); const serialized = serializeDates(events); console.log(serialized.created); // Curried usage const multiplyBy = (factor: number) => traverse((val: any) => typeof val === 'number' ? val * factor : val); const triple = multiplyBy(3); const quadruple = multiplyBy(4); console.log(triple({ x: 10, y: 20 })); console.log(quadruple({ x: 10, y: 20 })); ``` -------------------------------- ### Create Basic Async Pipeline with pipeAsync (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Builds a simple asynchronous pipeline to perform a series of operations: adding one, doubling asynchronously, and converting to a string. It demonstrates the sequential execution of synchronous and asynchronous functions. ```typescript import { pipeAsync } from 'matchblade'; // Basic async pipeline const addOne = (n: number) => n + 1; const doubleAsync = async (n: number) => { await new Promise(r => setTimeout(r, 10)); return n * 2; }; const toString = (n: number) => `Result: ${n}`; const calculation = pipeAsync( addOne, // 5 -> 6 doubleAsync, // 6 -> 12 (async) toString // 12 -> "Result: 12" ); const result = await calculation(5); console.log(result); // "Result: 12" ``` -------------------------------- ### Basic Accumulation with pipeTap in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt Demonstrates the basic accumulation pattern using pipeTap. Each step modifies the result based on the initial input and the previous step's output. The function takes an initial value and applies a series of transformations. ```typescript import { pipeTap } from 'matchblade'; // Basic accumulation pattern const calculation = pipeTap( (initial: number) => initial + 1, // 10 -> 11 (initial, prev) => prev + 10, // 11 + 10 = 21 (initial, prev) => prev * 2, // 21 * 2 = 42 (initial, prev) => prev + initial // 42 + 10 = 52 ); console.log(calculation(10)); // 52 ``` -------------------------------- ### TypeScript Pattern Matching with match and caseOf Source: https://context7.com/mendrik/matchblade/llms.txt Demonstrates type-safe pattern matching in TypeScript using `match` and `caseOf`. Supports primitive, type guard, class instance, multi-argument, and object structure matching, with automatic type narrowing and exhaustive checks. ```typescript import { match, caseOf, _ } from 'matchblade'; // Basic primitive matching const greet = match<[string], string>( caseOf(['hello'], () => 'You said hello!'), caseOf(['bye'], () => 'See you later!'), caseOf([_], (msg) => `Unknown message: ${msg}`) ); console.log(greet('hello')); // "You said hello!" console.log(greet('unknown')); // "Unknown message: unknown" // Type guard matching with automatic narrowing const isString = (x: any): x is string => typeof x === 'string'; const isNumber = (x: any): x is number => typeof x === 'number'; const processValue = match<[any], string>( caseOf([isString], (str) => `String: ${str.toUpperCase()}`), caseOf([isNumber, 10], (num) => `Number is 10`), caseOf([isNumber], (num) => `Other number: ${num}`), caseOf([_], () => 'Unknown type') ); console.log(processValue('test')); // "String: TEST" console.log(processValue(10)); // "Number is 10" console.log(processValue(42)); // "Other number: 42" // Class instance matching with type narrowing class Cat { meow() { return 'meow'; } } class Dog { bark() { return 'woof'; } } const animalSound = match<[Cat | Dog], string>( caseOf([(x): x is Cat => x instanceof Cat], (cat) => cat.meow()), caseOf([(x): x is Dog => x instanceof Dog], (dog) => dog.bark()), caseOf([_], () => 'silence') ); console.log(animalSound(new Cat())); // "meow" console.log(animalSound(new Dog())); // "woof" // Multi-argument matching const calculator = match<[string, number, number], number>( caseOf(['add', _, _], (op, a, b) => a + b), caseOf(['multiply', _, _], (op, a, b) => a * b), caseOf(['subtract', _, _], (op, a, b) => a - b), caseOf([_, _, _], () => 0) ); console.log(calculator('add', 5, 3)); // 8 console.log(calculator('multiply', 4, 2)); // 8 // Object structure matching const objMatcher = match<[any], string>( caseOf([{ status: 'success' }], (obj) => `Success: ${obj.data}`), caseOf([{ status: 'error' }], (obj) => `Error: ${obj.message}`), caseOf([_], () => 'Unknown status') ); console.log(objMatcher({ status: 'success', data: 'Complete' })); // "Success: Complete" console.log(objMatcher({ status: 'error', message: 'Failed' })); // "Error: Failed" ``` -------------------------------- ### Progressive Validation with Context using pipeTap in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt Illustrates progressive validation of user input using pipeTap. Each step validates a specific field and accumulates validation results or throws an error if validation fails. The pipeline passes the original input and the accumulated context to each function. ```typescript interface UserInput { username: string; email: string; password: string; } const validateUser = pipeTap( (input: UserInput) => { if (input.username.length < 3) throw new Error('Username too short'); return { usernameValid: true }; }, (input, prev) => { if (!input.email.includes('@')) throw new Error('Invalid email'); return { ...prev, emailValid: true }; }, (input, prev) => { if (input.password.length < 8) throw new Error('Password too short'); return { ...prev, passwordValid: true }; }, (input, prev) => ({ ...prev, user: input, validatedAt: new Date() }) ); try { const result = validateUser({ username: 'alice', email: 'alice@example.com', password: 'securepass123' }); console.log(result); // { // usernameValid: true, // emailValid: true, // passwordValid: true, // user: { username: 'alice', ... }, // validatedAt: Date // } } catch (error) { console.error(error.message); } ``` -------------------------------- ### Statistical Accumulation with pipeTap in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt Demonstrates statistical analysis using pipeTap. The pipeline calculates the sum, average, and maximum deviation of a list of numbers. Each step utilizes the results from the previous step and the original input array. ```typescript const analyzeNumbers = pipeTap( (nums: number[]) => nums.reduce((a, b) => a + b, 0), // sum (nums, sum) => sum / nums.length, // average (nums, avg) => Math.max(...nums) - avg, // max deviation (nums, deviation) => ({ count: nums.length, sum: nums.reduce((a, b) => a + b, 0), average: nums.reduce((a, b) => a + b, 0) / nums.length, maxDeviation: deviation }) ); console.log(analyzeNumbers([10, 20, 30, 40, 50])); // { count: 5, sum: 150, average: 30, maxDeviation: 20 } ``` -------------------------------- ### Create a Pipeline with Original Arguments using pipeTap Source: https://github.com/mendrik/matchblade/blob/main/README.md The pipeTap utility constructs a pipeline where each function receives both the original initial argument and the result of the previous function. This is useful for managing accumulated state or performing side effects within a pipeline. ```typescript import { pipeTap } from 'matchblade'; const calculation = pipeTap( (initial: number) => initial + 1, (initial, prev) => prev + 10, (initial, prev) => prev * 2 ); console.log(calculation(10)); // 42 ``` -------------------------------- ### Pattern Matching with Predicates and Primitives in matchblade Source: https://github.com/mendrik/matchblade/blob/main/README.md Illustrates how to use `match` and `caseOf` with predicate functions (like `isString`, `isNumber`) and primitive values for more flexible matching. This allows for type checking and value-based matching within the same pattern matching structure. It handles different types and specific values, falling back to a general case. ```typescript import { match, caseOf, _ } from 'matchblade'; import { isString, isNumber } from 'ramda-adjunct'; // or your own guards const processValue = match<[any], string>( caseOf([isString], (str) => `String: ${str.toUpperCase()}`), caseOf([isNumber, 10], (num) => `Is Number 10`), caseOf([isNumber], (num) => `Other Number: ${num}`), caseOf([_], () => 'Result: unknown') ); console.log(processValue('test')); // "String: TEST" console.log(processValue(10)); // "Is Number 10" console.log(processValue(42)); // "Other Number: 42" ``` -------------------------------- ### Create Data Transformation Pipeline with pipeAsync (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Designs a pipeline for processing API responses, including JSON parsing, data validation, and transformation. It demonstrates error handling for invalid data within the pipeline. ```typescript const parseJson = (text: string) => JSON.parse(text); const validateData = async (data: any) => { if (!data.id) throw new Error('Invalid data'); return data; }; const transformData = (data: any) => ({ id: data.id, name: data.name.toUpperCase(), timestamp: Date.now() }); const processApiResponse = pipeAsync( parseJson, validateData, transformData ); try { const processed = await processApiResponse('{"id": 1, "name": "test"}'); console.log(processed); // { id: 1, name: 'TEST', timestamp: ... } } catch (error) { console.error('Pipeline failed:', error); } ``` -------------------------------- ### Basic Pattern Matching with matchblade Source: https://github.com/mendrik/matchblade/blob/main/README.md Demonstrates basic pattern matching using `match` and `caseOf` with string literals and a wildcard. This is the fundamental way to define conditional logic based on input values with type safety. It takes a tuple of arguments and returns a function that accepts the matched value and returns a result. ```typescript import { match, caseOf, _ } from 'matchblade'; const getMessage = match<[string], string>( caseOf(['hello'], () => 'You said hello!'), caseOf(['bye'], () => 'See you later!'), caseOf([_], (msg) => `Unknown message: ${msg}`) // Wildcard catch-all ); console.log(getMessage('hello')); // "You said hello!" console.log(getMessage('unknown')); // "Unknown message: unknown" ``` -------------------------------- ### Create a failOn Guard Utility Source: https://github.com/mendrik/matchblade/blob/main/README.md The failOn utility creates a function that throws an error if a given value matches a specific predicate. It's useful for implementing runtime assertions and ensuring data integrity. ```typescript import { failOn } from 'matchblade'; const isError = (val: any): val is Error => val instanceof Error; const ensureSuccess = failOn(isError, 'Operation failed'); const result = ensureSuccess('Success'); // Returns 'Success' // ensureSuccess(new Error('fail')); // Throws Error: 'Operation failed' ``` -------------------------------- ### Resolving Promises in Objects with awaitObj Source: https://github.com/mendrik/matchblade/blob/main/README.md Introduces the `awaitObj` utility from `matchblade`, which recursively resolves all `Promise` values within an object. This is useful for flattening objects that contain promises, making the data directly accessible without manual `await` calls for each promise. It handles nested promises as well. ```typescript import { awaitObj } from 'matchblade'; const data = { user: Promise.resolve({ id: 1, name: 'Alice' }), posts: ['Post 1', 'Post 2'] }; const resolved = await awaitObj(data); // Output: // { // user: { id: 1, name: 'Alice' }, // posts: ['Post 1', 'Post 2'] // } ``` -------------------------------- ### TypeScript Promise Resolution with awaitObj Source: https://context7.com/mendrik/matchblade/llms.txt Provides the `awaitObj` utility function in TypeScript to asynchronously resolve all Promise values nested within an object structure. It handles mixed data types, including Promises and plain values, and supports error handling for rejected Promises. ```typescript import { awaitObj } from 'matchblade'; // Basic usage with mixed promises and values const fetchUserData = async () => { const data = { user: Promise.resolve({ id: 1, name: 'Alice' }), posts: Promise.resolve(['Post 1', 'Post 2']), settings: { theme: 'dark', notifications: true }, version: 2 }; const resolved = await awaitObj(data); console.log(resolved); // { // user: { id: 1, name: 'Alice' }, // posts: ['Post 1', 'Post 2'], // settings: { theme: 'dark', notifications: true }, // version: 2 // } }; // Real-world API aggregation example const aggregateData = async (userId: number) => { const apiData = { profile: fetch(`/api/users/${userId}`).then(r => r.json()), orders: fetch(`/api/users/${userId}/orders`).then(r => r.json()), reviews: fetch(`/api/users/${userId}/reviews`).then(r => r.json()), metadata: { timestamp: Date.now() } }; try { const allData = await awaitObj(apiData); return allData; } catch (error) { console.error('Failed to fetch user data:', error); throw error; } }; // Handle rejection scenarios const handleFailures = async () => { const failing = { success: Promise.resolve('OK'), failure: Promise.reject(new Error('Network error')) }; try { await awaitObj(failing); } catch (error) { console.error(error.message); // "Network error" } }; ``` -------------------------------- ### Type Narrowing in matchblade Pattern Matching Source: https://github.com/mendrik/matchblade/blob/main/README.md Shows how `match` and `caseOf` provide intelligent type narrowing within handler functions. By using type guards (e.g., `instanceof`), the types of variables within specific `caseOf` blocks are automatically narrowed, improving type safety and developer experience. This is crucial for working with union types. ```typescript import { match, caseOf, _ } from 'matchblade'; class Cat { meow() { return 'meow'; } } class Dog { bark() { return 'woof'; } } const animalSound = match<[Cat | Dog], string>( caseOf([(x): x is Cat => x instanceof Cat], (cat) => cat.meow()), caseOf([(x): x is Dog => x instanceof Dog], (dog) => dog.bark()), caseOf([_], () => 'silence') ); console.log(animalSound(new Cat())); // "meow" ``` -------------------------------- ### Structured Pattern Matching (Objects and Arrays) in matchblade Source: https://github.com/mendrik/matchblade/blob/main/README.md Explains how `match` and `caseOf` can destructure and match against the shape of objects and arrays. This allows for powerful pattern matching directly on data structures, simplifying access to nested properties and array elements. It supports matching specific keys/values in objects and patterns in arrays. ```typescript import { match, caseOf, _ } from 'matchblade'; // Match object structure const objMatcher = match<[any], string>( caseOf([{ a: 1 }], (obj) => `Object with a=1`), caseOf([{ b: 2 }], (obj) => `Object with b=2`), caseOf([_], () => 'Other object') ); console.log(objMatcher({ a: 1, c: 3 })); // "Object with a=1" // Match array structure const arrayMatcher = match<[number[]], string>( caseOf([[1, 2]], () => 'Array [1, 2]') , caseOf([[_, 2]], () => 'Array ending with 2') , caseOf([_], () => 'Other array') ); console.log(arrayMatcher([1, 2])); // "Array [1, 2]" console.log(arrayMatcher([5, 2])); // "Array ending with 2" ``` -------------------------------- ### Recursive Object Transformation with evolve Source: https://github.com/mendrik/matchblade/blob/main/README.md Presents the `evolve` utility for creating a new object by applying transformations to a source object recursively. It takes a 'spec' object defining the transformations and applies them to the corresponding properties of the source object. This is powerful for immutable updates and data shaping. ```typescript import { evolve } from 'matchblade'; const user = { name: 'Alice', stats: { visits: 10 } }; const transformations = { name: (name: string) => name.toUpperCase(), stats: { visits: (n: number) => n + 1 } }; const updated = evolve(transformations, user); // Output: // { // name: 'ALICE', // stats: { visits: 11 } // } ``` -------------------------------- ### Type Hinting for Curried Matchblade Functions Source: https://github.com/mendrik/matchblade/blob/main/README.md When using Matchblade functions in a curried manner (e.g., providing only the first argument), explicit type annotations can improve TypeScript's inference of return types, ensuring better type safety and autocompletion. ```typescript // Explicitly typing mapBy for better inference const mapById = mapBy((u: { id: number }) => u.id); // mapById is now inferred as (list: { id: number }[]) => Map ``` -------------------------------- ### Multi-Argument Pattern Matching with matchblade Source: https://github.com/mendrik/matchblade/blob/main/README.md Demonstrates `match` and `caseOf` capabilities for matching against multiple arguments simultaneously. The `match` function is variadic and can be configured to handle tuples of arguments, allowing for complex conditional logic based on several inputs. A wildcard `_` can be used for any argument. ```typescript import { match, caseOf, _ } from 'matchblade'; const mixedMatch = match<[string, number], string>( caseOf(['a', 1], () => 'Matched A and 1'), caseOf(['b', 2], () => 'Matched B and 2'), caseOf([_, _], (a, b) => `Catch all: ${a}, ${b}`) ); console.log(mixedMatch('a', 1)); // "Matched A and 1" console.log(mixedMatch('b', 2)); // "Matched B and 2" console.log(mixedMatch('c', 3)); // "Catch all: c, 3" ``` -------------------------------- ### Async Operations Pipeline with pipeTap in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt Shows how to handle asynchronous operations within a pipeTap pipeline. Each asynchronous function in the pipeline awaits the result of the previous one, accumulating data from multiple API calls. The final step aggregates the data into a summary object. ```typescript const processOrder = pipeTap( async (orderId: number) => { const order = await fetch(`/api/orders/${orderId}`).then(r => r.json()); return order; }, async (orderId, order) => { const customer = await fetch(`/api/customers/${order.customerId}`).then(r => r.json()); return { ...order, customer }; }, async (orderId, enrichedOrder) => { const shipping = await fetch(`/api/shipping/${orderId}`).then(r => r.json()); return { ...enrichedOrder, shipping }; }, (orderId, fullOrder) => ({ ...fullOrder, summary: { orderId, total: fullOrder.total, customerName: fullOrder.customer.name, status: fullOrder.shipping.status } }) ); const orderDetails = await processOrder(12345); ``` -------------------------------- ### Chain Asynchronous Functions with pipeAsync Source: https://github.com/mendrik/matchblade/blob/main/README.md The pipeAsync utility allows you to chain multiple functions, including asynchronous ones, into a single pipeline. Each function in the pipeline receives the output of the preceding function as its input. ```typescript import { pipeAsync } from 'matchblade'; const addOne = (n: number) => n + 1; const doubleAsync = async (n: number) => { await new Promise(r => setTimeout(r, 10)); return n * 2; }; const pipeline = pipeAsync( addOne, doubleAsync, (n) => `Result: ${n}` ); const result = await pipeline(5); console.log(result); // "Result: 12" ``` -------------------------------- ### Create a Map from a List by Key Source: https://github.com/mendrik/matchblade/blob/main/README.md The mapBy utility function generates a JavaScript Map object from an array. It uses a provided key-generating function to determine the keys for each element in the Map. ```typescript import { mapBy } from 'matchblade'; const users = [ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' } ]; const usersById = mapBy((u) => u.id, users); console.log(usersById.get(1)); // { id: 1, name: 'Alice' } ``` -------------------------------- ### Type Narrowing with Match and Type Guards Source: https://github.com/mendrik/matchblade/blob/main/README.md The 'match' function in Matchblade leverages TypeScript's control flow analysis for type narrowing within handler functions. By using type guards, you can avoid manual type casting and ensure correct type inference for variables within different cases. ```typescript const isString = (x: any): x is string => typeof x === 'string'; match<[any], string>( caseOf([isString], (str) => { // 'str' is correctly inferred as 'string' here return str.toUpperCase(); }) ); ``` -------------------------------- ### Create Maps with mapBy (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Creates a JavaScript Map object from an array, using a provided function to extract keys from each element. This is useful for efficient lookups and managing unique identifiers. The function handles duplicate keys by defaulting to the last occurrence. ```typescript import { mapBy } from 'matchblade'; // Basic usage const users = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' }, { id: 3, name: 'Charlie', email: 'charlie@example.com' } ]; const usersById = mapBy((u) => u.id, users); console.log(usersById.get(2)); // { id: 2, name: 'Bob', email: 'bob@example.com' } const usersByEmail = mapBy((u) => u.email, users); console.log(usersByEmail.get('alice@example.com')); // { id: 1, name: 'Alice', ... } // Quick lookup for complex operations interface Product { sku: string; name: string; price: number; category: string; } const products: Product[] = [ { sku: 'LAPTOP-001', name: 'Dell XPS 13', price: 999, category: 'electronics' }, { sku: 'MOUSE-001', name: 'Logitech MX', price: 79, category: 'accessories' }, { sku: 'KEYBOARD-001', name: 'Keychron K2', price: 89, category: 'accessories' } ]; const productsBySku = mapBy((p) => p.sku, products); const updatePrice = (sku: string, newPrice: number) => { const product = productsBySku.get(sku); if (product) { product.price = newPrice; return product; } return null; }; console.log(updatePrice('LAPTOP-001', 899)); // { sku: 'LAPTOP-001', price: 899, ... } // Curried usage for reusable mappers const mapById = mapBy((item: { id: number }) => item.id); const orders = [ { id: 101, total: 250, status: 'shipped' }, { id: 102, total: 180, status: 'pending' } ]; const ordersById = mapById(orders); console.log(ordersById.get(101)); // { id: 101, total: 250, status: 'shipped' } // Handle duplicate keys (last wins) const items = [ { key: 'a', value: 1 }, { key: 'b', value: 2 }, { key: 'a', value: 3 } ]; const itemsByKey = mapBy((item) => item.key, items); console.log(itemsByKey.get('a')); // { key: 'a', value: 3 } console.log(itemsByKey.size); // 2 ``` -------------------------------- ### Convert List to Tree Structure Source: https://github.com/mendrik/matchblade/blob/main/README.md The listToTree utility transforms a flat list of objects, each with an 'id' and 'parentId', into a nested tree structure. It allows customization of the key names for IDs, parent IDs, and the children array. ```typescript import { listToTree } from 'matchblade'; const list = [ { id: '1', parentId: null, name: 'Root' }, { id: '2', parentId: '1', name: 'Child A' }, { id: '3', parentId: '1', name: 'Child B' } ]; // Configure the converter const toTree = listToTree('id', 'parentId', 'children'); const tree = toTree(list); ``` -------------------------------- ### Object Transformation with evolve in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt The 'evolve' function from 'matchblade' allows for recursive, immutable transformation of object structures. It takes a set of transformation rules and an object, returning a new object with applied changes. It supports basic property updates, nested object transformations, array transformations, adding computed properties, and curried usage for reusable transformation logic. ```typescript import { evolve } from 'matchblade'; // Basic transformations const user = { name: 'alice', age: 25, stats: { visits: 10, score: 100 } }; const transformations = { name: (name: string) => name.toUpperCase(), age: (age: number) => age + 1, stats: { visits: (n: number) => n + 1, score: (n: number) => n * 2 } }; const updated = evolve(transformations, user); console.log(updated); // { // name: 'ALICE', // age: 26, // stats: { visits: 11, score: 200 } // } // Transform arrays of objects const data = { users: [ { id: 1, score: 10 }, { id: 2, score: 20 } ], metadata: { version: 1 } }; const arrayTransform = { users: { score: (s: number) => s * 10 }, metadata: { version: (v: number) => v + 1 } }; const transformed = evolve(arrayTransform, data); console.log(transformed); // { // users: [ // { id: 1, score: 100 }, // { id: 2, score: 200 } // ], // metadata: { version: 2 } // } // Add computed properties const source = { firstName: 'John', lastName: 'Doe', age: 30 }; const addFullName = { fullName: (obj: typeof source) => `${obj.firstName} ${obj.lastName}`, age: (age: number) => age }; const withFullName = evolve(addFullName, source); console.log(withFullName); // { // firstName: 'John', // lastName: 'Doe', // age: 30, // fullName: 'John Doe' // } // Curried usage const incrementVersion = evolve({ version: (v: number) => v + 1 }); const config1 = incrementVersion({ version: 1, name: 'app' }); const config2 = incrementVersion({ version: 5, name: 'api' }); console.log(config1); // { version: 2, name: 'app' } console.log(config2); // { version: 6, name: 'api' } ``` -------------------------------- ### Build Tree Structures with listToTree (TypeScript) Source: https://context7.com/mendrik/matchblade/llms.txt Converts a flat array of objects with parent-child relationships into a nested tree structure. It requires specifying the unique identifier field, the parent identifier field, and the name of the children array property. Useful for representing hierarchies like file systems or organizational charts. ```typescript import { listToTree } from 'matchblade'; // Basic tree conversion const flatList = [ { id: 1, name: 'Root', parentId: null }, { id: 2, name: 'Child A', parentId: 1 }, { id: 3, name: 'Child B', parentId: 1 }, { id: 4, name: 'Grandchild A.1', parentId: 2 } ]; const toTree = listToTree('id', 'parentId', 'children'); const tree = toTree(flatList); console.log(tree); // { // id: 1, // name: 'Root', // parentId: null, // children: [ // { // id: 2, // name: 'Child A', // parentId: 1, // children: [ // { id: 4, name: 'Grandchild A.1', parentId: 2, children: [] } // ] // }, // { id: 3, name: 'Child B', parentId: 1, children: [] } // ] // } // File system structure interface FileNode { path: string; parentPath: string | null; type: 'file' | 'folder'; size?: number; } const files: FileNode[] = [ { path: '/', parentPath: null, type: 'folder' }, { path: '/src', parentPath: '/', type: 'folder' }, { path: '/src/index.ts', parentPath: '/src', type: 'file', size: 1024 }, { path: '/src/utils.ts', parentPath: '/src', type: 'file', size: 512 }, { path: '/tests', parentPath: '/', type: 'folder' }, { path: '/tests/unit.test.ts', parentPath: '/tests', type: 'file', size: 2048 } ]; const buildFileTree = listToTree('path', 'parentPath', 'contents'); const fileTree = buildFileTree(files); // Organization hierarchy const employees = [ { empId: 'CEO1', name: 'Alice', managerId: null }, { empId: 'VP1', name: 'Bob', managerId: 'CEO1' }, { empId: 'VP2', name: 'Carol', managerId: 'CEO1' }, { empId: 'MGR1', name: 'Dave', managerId: 'VP1' }, { empId: 'EMP1', name: 'Eve', managerId: 'MGR1' } ]; const buildOrgChart = listToTree('empId', 'managerId', 'directReports'); const orgChart = buildOrgChart(employees); console.log(orgChart.directReports.length); // 2 (VP1 and VP2) ``` -------------------------------- ### Recursively Traverse and Transform Data with traverse Source: https://github.com/mendrik/matchblade/blob/main/README.md The traverse utility enables recursive traversal of nested objects or arrays. It applies a given transformation function to every primitive value encountered within the data structure. ```typescript import { traverse } from 'matchblade'; const data = { a: 1, b: { c: 2, d: [3, 4] } }; const doubleNumbers = traverse((val) => { return typeof val === 'number' ? val * 2 : val; }); const result = doubleNumbers(data); ``` -------------------------------- ### Type Guards with failOn in TypeScript Source: https://context7.com/mendrik/matchblade/llms.txt The 'failOn' function from 'matchblade' provides runtime type validation that throws errors and narrows types. It accepts a type guard function and an error message, returning a function that, when applied to a value, either returns the value if it satisfies the guard or throws an error. This is useful for validating function arguments, API responses, and ensuring type safety in complex data flows. ```typescript import { failOn } from 'matchblade'; // Basic error handling with type narrowing type Result = { status: 'success'; data: string } | { status: 'error'; message: string }; const isError = (r: Result): r is { status: 'error'; message: string } => r.status === 'error'; const processResult = (result: Result) => { const success = failOn(isError, 'Operation failed')(result); // `success` is now typed as { status: 'success'; data: string } return success.data.toUpperCase(); }; try { const good = processResult({ status: 'success', data: 'hello' }); console.log(good); // "HELLO" const bad = processResult({ status: 'error', message: 'Network error' }); // Throws: Error: Operation failed } catch (error) { console.error(error); } // Validate API responses interface ApiResponse { statusCode: number; body: any; } const isServerError = (r: ApiResponse): r is ApiResponse & { statusCode: 500 } => r.statusCode >= 500; const isClientError = (r: ApiResponse): r is ApiResponse & { statusCode: 400 } => r.statusCode >= 400 && r.statusCode < 500; const handleResponse = (response: ApiResponse) => { const noServerError = failOn(isServerError, 'Server error occurred')(response); const noClientError = failOn(isClientError, 'Client error occurred')(noServerError); return noClientError.body; }; // Chain multiple validations const validateUser = (user: any) => { const isInvalid = (u: any): u is { id?: never } => !u.id; const isBanned = (u: any): u is { banned: true } => u.banned === true; const checkInvalid = failOn(isInvalid, 'User ID is required'); const checkBanned = failOn(isBanned, 'User is banned'); const validUser = checkInvalid(user); const activeUser = checkBanned(validUser); return activeUser; }; try { validateUser({ id: 1, name: 'Alice', banned: false }); // OK validateUser({ id: 2, name: 'Bob', banned: true }); // Throws: "User is banned" validateUser({ name: 'Charlie' }); // Throws: "User ID is required" } catch (error) { console.error(error.message); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.