@shridey/transformer
v1.1.0
Published
A strictly typed, lazy-evaluated data pipeline for Chart.js, Nivo, and Recharts.
Maintainers
Readme
⚡ @shridey/transformer
The "God Mode" Data Pipeline for TypeScript.
A strictly typed, lazy-evaluated transformation library designed to bridge the gap between messy API responses and clean application state. Whether you are munging data for business logic or preparing complex datasets for Chart.js, Nivo, or Recharts, this is your all-in-one toolkit.
🚀 Why this? The Impact.
Most developers write the same fragile map / filter / reduce chains over and over again. When data gets complex (nested arrays, conditional summing, dynamic grouping), code becomes unreadable and slow.
@shridey/transformer changes the game:
- ⚡ Lazy Evaluation: We use Generators. If you have 10,000 items but only need the top 5, we only process 5. No massive intermediate arrays.
- 🔒 Strict Typing: If you typo a key, your build fails. If you change a schema, you know exactly what breaks.
- 🧠 The "Accessor" System: Every method accepts either a String Key (
'price') OR a Function (item => item.price * 1.2). - 📊 Visualization Ready: Stop fighting with Chart.js config structures. We have pre-built "Collectors" that output exactly what charting libraries need.
📦 Installation
npm install @shridey/transformer
🛠️ Usage: The "All-Rounder"
This library isn't just for charts. It's for any time you touch an array.
Scenario 1: Day-to-Day Data Munging
Cleaning API responses, calculating totals, and reshaping objects.
import { LazyPipeline, Aggregate, Sort } from "@shridey/transformer";
const rawUsers = [
{ id: 1, name: "Alice", role: "admin", meta: { loginCount: 50 } },
{ id: 2, name: "Bob", role: "user", meta: { loginCount: 12 } },
{ id: 3, name: "Charlie", role: "user", meta: { loginCount: 0 } },
];
const report = LazyPipeline.from(rawUsers)
// 1. Filter: Clean logic
.filter((u) => u.role === "user")
// 2. Sort: Use helper or function
.sort(Sort.desc((u) => u.meta.loginCount))
// 3. Reshape: Pick exactly what you need
.reshape({
username: (u) => u.name,
activityScore: (u) => u.meta.loginCount * 10,
status: (u) => (u.meta.loginCount > 0 ? "Active" : "Inactive"),
})
.execute();
// Result:
// [
// { username: 'Bob', activityScore: 120, status: 'Active' },
// { username: 'Charlie', activityScore: 0, status: 'Inactive' }
// ]Scenario 2: The Visualization Hero
Turning nested data (Users -> Orders -> Products) into a Chart.js Bar Chart.
import { LazyPipeline, Aggregate } from "@shridey/transformer";
import { ToChartJsBar } from "@shridey/transformer/collectors";
// Complex nested source
const pipeline = LazyPipeline.from(users)
.flatMap((user) => user.orders) // Unwind orders
.filter((order) => order.isPaid) // Keep paid only
.flatMap((order) => order.products) // Unwind products
.groupBy("category") // Group by Category
.reshape({
category: (g) => g.key,
revenue: (g) => Aggregate.sum("price", g.items),
avgPrice: (g) => Aggregate.avg("price", g.items),
});
// Zero-Config Chart Output
const chartConfig = pipeline.collect(
ToChartJsBar({
labelKey: "category",
datasets: [
{
label: "Total Revenue",
dataKey: "revenue",
backgroundColor: "blue",
},
{
label: "Avg Item Price",
dataKey: "avgPrice",
// Dynamic color based on data!
backgroundColor: (item) => (item.avgPrice > 50 ? "red" : "green"),
},
],
})
);📚 Core API
LazyPipeline<T>
The engine of the library. It wraps your array and prepares it for transformation.
| Method | Description | Example |
| ---------------------------- | ----------------------------------------------------------------------------------- | --------------------------------- |
| .filter(predicate) | Keeps items matching the condition. | .filter(x => x.active) |
| .flatMap(selector) | Unwinds nested arrays into a flat stream. | .flatMap(u => u.orders) |
| .groupBy(accessor) | Groups items. Returns { key, items[] }. | .groupBy('status') |
| .reshape(schema) | The Powerhouse. Transforms objects into a new shape defined by a key-value map. | .reshape({ name: u => u.id }) |
| .sort(comparator) | Sorts the stream (buffers data). | .sort(Sort.asc('date')) |
| .take(n) | Lazy. Stops processing after n items found. | .take(5) |
| .reduce(reducer, init) | Terminal. Reduces stream to a single value. | .reduce((acc, x) => acc + x, 0) |
| .collect(collector) | Terminal. Ends the pipeline and runs a formatter. | .collect(ToChartJsBar(...)) |
| .execute() | Terminal. Returns the final array T[]. | .execute() |
Helpers
Utility functions to save you time. Import them from the root.
Aggregate
sum(accessor, items)avg(accessor, items)count(items)max(accessor, items)/min(accessor, items)(Safe for large arrays)sumIf(accessor, items, predicate)
Sort
asc(accessor)desc(accessor)
Filter
eq(accessor, value)gt(accessor, value)/ltincludes(accessor, value)
📊 Chart Collectors (Visualizations)
Stop writing spaghetti code to format data for libraries. Import collectors from @shridey/transformer/collectors.
1. Chart.js
Supported: ToChartJsBar, ToChartJsLine, ToChartJsPie, ToChartJsScatter.
pipeline.collect(
ToChartJsBar({
labelKey: "month",
datasets: [
{
label: "Sales",
dataKey: "amount",
// Supports static string, array, or function
backgroundColor: (d) => (d.amount > 100 ? "#4caf50" : "#f44336"),
},
],
})
);2. Nivo
Supported: ToNivoBar, ToNivoLine, ToNivoPie, ToNivoScatter.
Handles Nivo's specific needs (nested data arrays for lines, flat objects for bars).
pipeline.collect(
ToNivoLine({
xKey: "date",
lines: [
{ id: "Revenue", dataKey: "revenue" },
{ id: "Costs", dataKey: "costs" },
],
})
);3. Recharts
Supported: ToRechartsLine, ToRechartsBar, ToRechartsPie, ToRechartsScatter.
Automatically remaps keys to Recharts-friendly structures while preserving your original data in payload for custom tooltips.
pipeline.collect(
ToRechartsLine({
xAxisKey: "timestamp",
lines: [
{ dataKey: "seriesA", accessor: "valueA" },
{ dataKey: "seriesB", accessor: (item) => item.valueB * 100 },
],
})
);⚡ Performance Note
If you have an array of 1,000,000 items:
// STANDARD JS (Slow)
// Loops 1M times to map, then 1M times to filter, then creates a huge new array
data.map(expensiveFn).filter(condition).slice(0, 5);
// TRANSFORMER (Fast)
// Processes item 1 -> map -> filter -> keep
// ... repeats until 5 items are found
// Stops instantly.
LazyPipeline.from(data).map(expensiveFn).filter(condition).take(5).execute();📄 License
MIT © Shridhar Pandey
