π½οΈ API β
This section provides a detailed explanation of the Cano-TS API with examples, covering both synchronous and asynchronous pipelines.
π Creating a Pipeline β
Cano-TS offers two ways to create pipelines:
pipeSync()
β for synchronous function composition.pipe()
β for asynchronous function composition.
Each pipeline starts with an initial value, processes it through a sequence of functions, and returns the final result.
π Reference β
Methods:
.next(fn, ...args)
β Chains functions in the pipeline..log(message?)
β Logs intermediate values for debugging..result()
β Resolves and returns the final computed value.
πΉ .next(fn, ...args) β
Definition
.next<
T,
U,
Args extends unknown[]
>(fn: (value: T, ...args: Args) => U, ...args: Args): Pipe<U>
The .next()
method applies a function to the current value in the pipeline and returns a new pipeline with the transformed value.
- Works with both synchronous (
pipeSync
) and asynchronous (pipe
) pipelines. - Accepts extra arguments (
...args
) which are passed tofn
. - Preserves function history for debugging.
Example: Sync Pipeline with Extra Arguments
import { pipeSync } from "cano-ts";
const add = (x: number, y: number) => x + y;
const multiply = (x: number, factor: number) => x * factor;
const format = (x: number, prefix: string) => `${prefix} ${x}`;
const result = pipeSync(5)
.next(add, 3) // 5 + 3 = 8
.next(multiply, 2) // 8 * 2 = 16
.next(format, "Result:")
.result();
console.log(result); // "Result: 16"
Example: Async Pipeline with API Calls
import { pipe } from "cano-ts";
async function fetchUser(id: number) {
const response = await fetch(`https://api.example.com/users/${id}`);
return response.json();
}
async function updateRole(user: { id: number; name: string; role: string }, newRole: string) {
return { ...user, role: newRole };
}
async function saveToDB(user: { id: number; name: string; role: string }) {
await fetch(`https://api.example.com/users/${user.id}`, {
method: "PUT",
body: JSON.stringify(user),
});
return user;
}
const result = await pipe(1)
.next(fetchUser) // Fetch user from API
.next(updateRole, "admin") // Update user role
.next(saveToDB) // Save updated user to DB
.result();
console.log(result); // { id: 1, name: "Alice", role: "admin" }
πΉ .log(message?)
β
Definition
.log(message?: string): Pipe<T>
The .log()
method logs the current value of the pipeline to the console without modifying it.
- Helps debug intermediate values.
- Works in both sync (
pipeSync
) and async (pipe
) pipelines. - Accepts an optional message to label the log.
Example: Debugging a Sync Pipeline
pipeSync(10)
.next((x) => x * 2) // 10 * 2 = 20
.log()
.next((x) => x + 5) // 20 + 5 = 25
.log("After Addition")
.result();
π Console Output:
[PipeSync] anonymous -> 20
After Addition 25
Example: Debugging an Async Pipeline
await pipe(5)
.next(async (x) => x * 2) // 5 * 2 = 10
.log() // Logs: [PipeAsync] anonymous -> 10
.next(async (x) => x + 1) // 10 + 1 = 11
.log("After increment:")
.result();
π Console Output:
[PipeAsync] anonymous -> 10
After increment: 11```
πΉ .result()
β
Definition
.result(): Promise<T> | T
The .result()
method resolves and returns the final computed value in the pipeline.
- For
pipeSync()
, it returns a synchronous value (T
). - For
pipe()
, it returns a Promise (Promise<T>
), requiringawait
.
π§ E Module - Array Utilities β
The E
module provides a comprehensive set of functional array operations designed to work seamlessly with Cano TS pipelines. All functions are curried, meaning they can be partially applied with additional arguments.
Core Transformation Functions β
E.map(fn)
β
Transforms each element in an array using the provided function.
import { pipeSync, E } from "cano-ts";
const numbers = [1, 2, 3, 4, 5];
const doubled = pipeSync(numbers)
.next(E.map, (x: number) => x * 2)
.result();
console.log(doubled); // [2, 4, 6, 8, 10]
// With objects
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 }
];
const names = pipeSync(users)
.next(E.map, (user) => user.name)
.result();
console.log(names); // ["Alice", "Bob"]
E.filter(predicate)
β
Filters array elements based on a predicate function.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = pipeSync(numbers)
.next(E.filter, (x: number) => x % 2 === 0)
.result();
console.log(evenNumbers); // [2, 4, 6, 8, 10]
// Complex filtering
const users = [
{ name: "Alice", age: 25, active: true },
{ name: "Bob", age: 17, active: false },
{ name: "Charlie", age: 30, active: true }
];
const activeAdults = pipeSync(users)
.next(E.filter, (user) => user.active && user.age >= 18)
.result();
console.log(activeAdults); // [{ name: "Alice", age: 25, active: true }, { name: "Charlie", age: 30, active: true }]
E.reduce(reducer, initialValue)
β
Reduces an array to a single value using a reducer function.
const numbers = [1, 2, 3, 4, 5];
const sum = pipeSync(numbers)
.next(E.reduce, (acc: number, curr: number) => acc + curr, 0)
.result();
console.log(sum); // 15
// Complex reduction
const transactions = [
{ type: "credit", amount: 100 },
{ type: "debit", amount: 50 },
{ type: "credit", amount: 75 }
];
const balance = pipeSync(transactions)
.next(E.reduce, (acc, tx) => {
return tx.type === "credit" ? acc + tx.amount : acc - tx.amount;
}, 0)
.result();
console.log(balance); // 125
E.find(predicate)
β
Finds the first element that matches the predicate.
const users = [
{ id: 1, name: "Alice", role: "user" },
{ id: 2, name: "Bob", role: "admin" },
{ id: 3, name: "Charlie", role: "user" }
];
const admin = pipeSync(users)
.next(E.find, (user) => user.role === "admin")
.result();
console.log(admin); // { id: 2, name: "Bob", role: "admin" }
Array Manipulation Functions β
E.sort(compareFn?)
β
Sorts array elements using an optional compare function.
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];
// Ascending order (default)
const ascending = pipeSync(numbers)
.next(E.sort)
.result();
console.log(ascending); // [1, 1, 2, 3, 4, 5, 6, 9]
// Custom sorting
const users = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 35 }
];
const sortedByAge = pipeSync(users)
.next(E.sort, (a, b) => a.age - b.age)
.result();
console.log(sortedByAge); // Sorted by age ascending
E.reverse()
β
Reverses the order of elements in an array.
const numbers = [1, 2, 3, 4, 5];
const reversed = pipeSync(numbers)
.next(E.reverse)
.result();
console.log(reversed); // [5, 4, 3, 2, 1]
E.slice(start, end?)
β
Extracts a section of an array and returns a new array.
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const middle = pipeSync(numbers)
.next(E.slice, 2, 7)
.result();
console.log(middle); // [3, 4, 5, 6, 7]
// First 3 elements
const first3 = pipeSync(numbers)
.next(E.slice, 0, 3)
.result();
console.log(first3); // [1, 2, 3]
Array Combining Functions β
E.concat(...arrays)
β
Combines multiple arrays into one.
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
const combined = pipeSync(arr1)
.next(E.concat, arr2, arr3)
.result();
console.log(combined); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
E.flat(depth?)
β
Flattens nested arrays to the specified depth (default: 1).
const nested = [1, [2, 3], [4, [5, 6]]];
const flattened = pipeSync(nested)
.next(E.flat)
.result();
console.log(flattened); // [1, 2, 3, 4, [5, 6]]
// Flatten all levels
const deepFlattened = pipeSync(nested)
.next(E.flat, Infinity)
.result();
console.log(deepFlattened); // [1, 2, 3, 4, 5, 6]
E.join(separator?)
β
Joins array elements into a string with an optional separator.
const words = ["Hello", "world", "from", "Cano", "TS"];
const sentence = pipeSync(words)
.next(E.join, " ")
.result();
console.log(sentence); // "Hello world from Cano TS"
// CSV format
const data = ["Alice", "25", "Developer"];
const csv = pipeSync(data)
.next(E.join, ",")
.result();
console.log(csv); // "Alice,25,Developer"
Boolean Operation Functions β
E.every(predicate)
β
Tests whether all elements pass the provided predicate.
const numbers = [2, 4, 6, 8, 10];
const allEven = pipeSync(numbers)
.next(E.every, (x: number) => x % 2 === 0)
.result();
console.log(allEven); // true
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: 17 }
];
const allAdults = pipeSync(users)
.next(E.every, (user) => user.age >= 18)
.result();
console.log(allAdults); // false
E.some(predicate)
β
Tests whether at least one element passes the provided predicate.
const numbers = [1, 3, 5, 8, 9];
const hasEven = pipeSync(numbers)
.next(E.some, (x: number) => x % 2 === 0)
.result();
console.log(hasEven); // true
const users = [
{ name: "Alice", role: "user" },
{ name: "Bob", role: "admin" },
{ name: "Charlie", role: "user" }
];
const hasAdmin = pipeSync(users)
.next(E.some, (user) => user.role === "admin")
.result();
console.log(hasAdmin); // true
E.includes(searchElement)
β
Determines whether an array includes a certain value.
const fruits = ["apple", "banana", "orange"];
const hasBanana = pipeSync(fruits)
.next(E.includes, "banana")
.result();
console.log(hasBanana); // true
const numbers = [1, 2, 3, 4, 5];
const hasEight = pipeSync(numbers)
.next(E.includes, 8)
.result();
console.log(hasEight); // false
π Advanced E Module Examples β
Data Processing Pipeline β
import { pipeSync, E } from "cano-ts";
const orders = [
{ id: 1, customer: "Alice", amount: 150, status: "completed", date: "2024-01-15" },
{ id: 2, customer: "Bob", amount: 75, status: "pending", date: "2024-01-16" },
{ id: 3, customer: "Charlie", amount: 200, status: "completed", date: "2024-01-17" },
{ id: 4, customer: "Diana", amount: 90, status: "completed", date: "2024-01-18" },
{ id: 5, customer: "Eve", amount: 300, status: "cancelled", date: "2024-01-19" }
];
// Get total revenue from completed orders over $100
const highValueRevenue = pipeSync(orders)
.next(E.filter, (order) => order.status === "completed")
.next(E.filter, (order) => order.amount > 100)
.next(E.map, (order) => order.amount)
.next(E.reduce, (sum: number, amount: number) => sum + amount, 0)
.result();
console.log(highValueRevenue); // 350
// Get customer names with pending orders
const pendingCustomers = pipeSync(orders)
.next(E.filter, (order) => order.status === "pending")
.next(E.map, (order) => order.customer)
.next(E.join, ", ")
.result();
console.log(pendingCustomers); // "Bob"
Complex Data Transformation β
const salesData = [
{ region: "North", products: [{ name: "Laptop", sales: [100, 150, 200] }] },
{ region: "South", products: [{ name: "Phone", sales: [80, 90, 120] }] },
{ region: "East", products: [{ name: "Tablet", sales: [60, 70, 80] }] }
];
// Calculate total sales across all regions and products
const totalSales = pipeSync(salesData)
.next(E.map, (region) => region.products)
.next(E.flat)
.next(E.map, (product) => product.sales)
.next(E.flat)
.next(E.reduce, (sum: number, sale: number) => sum + sale, 0)
.result();
console.log(totalSales); // 950
Text Processing Pipeline β
const text = "The Quick Brown Fox Jumps Over The Lazy Dog";
const processedText = pipeSync(text)
.next((str) => str.toLowerCase())
.next((str) => str.split(" "))
.next(E.filter, (word) => word.length > 3)
.next(E.sort)
.next(E.map, (word) => word.charAt(0).toUpperCase() + word.slice(1))
.next(E.join, " β ")
.result();
console.log(processedText); // "Brown β Jumps β Lazy β Over β Quick"