Skip to content

Latest commit

 

History

History
115 lines (77 loc) · 4.34 KB

File metadata and controls

115 lines (77 loc) · 4.34 KB

SchemaFlow

A simple, robust, and composable data transformation library for TypeScript/JavaScript.

Core Philosophy

This library is built on a foundation of three core principles:

  1. Unix Philosophy: Each part of this library is a small, sharp tool that does one thing well. We compose these simple, predictable tools to build complex and reliable behavior.
  2. Parse, Don't Validate: We never trust data. We force it through a parser that returns a new, compiler-verified value. This eliminates an entire class of bugs at the source.
  3. Simplicity over Ease: We prioritize correctness and predictability. Logic is treated as data (JSON Schema, JSONLogic rules), which makes the system transparent and configurable.

Features

  • Type-Safe Transformations: Ensure your data transformations are type-safe from end to end.
  • Bi-Directional: Decode and encode data between two different shapes.
  • Composable: Build complex pipelines from simple, reusable functions.
  • Declarative: Define your transformation logic as data using JSON Schema and JSON Logic.
  • Self-Testing: Verify your data contracts with the built-in verification function.

Installation

npm install

Usage

Here's a simple example of how to use the library to decode and encode data.

import { processPacket, verifyPacket } from "./src/packet-processor";
import { readFileSync } from "fs";

// 1. Load a data contract packet
const packet = JSON.parse(readFileSync("./sample-packet.json", "utf-8"));

// 2. Create a transformer from the packet
const transformer = processPacket(packet);

// 3. Verify the packet (optional)
const isValid = verifyPacket(packet);
console.log(`Packet is ${isValid ? "valid" : "invalid"}`);

// 4. Decode data
const decoded = transformer.decode({ firstName: "John", lastName: "Smith" });
console.log(decoded); // { fullName: 'John Smith' }

// 5. Encode data
const encoded = transformer.encode({ fullName: "Jane Smith" });
console.log(encoded); // { firstName: 'Jane', lastName: 'Smith' }

Data Contract Packets

A Data Contract Packet is a JSON object that contains everything needed to perform a bi-directional transformation:

  • inputSchema: The JSON Schema for the input data.
  • outputSchema: The JSON Schema for the output data.
  • decoderRules: The JSON Logic rules for decoding the data (input -> output).
  • encoderRules: The JSON Logic rules for encoding the data (output -> input).
  • data: An array of sample data that can be used to verify the packet.

This packet is a self-contained unit that can be easily shared and tested.

Demo

To see the library in action, run the demo script:

bun run demo.ts

This will process three different data packets: a simple one, a complex one, and an invalid one.

Command-line interface (CLI)

A CLI is available via the schemaflow entrypoint. It supports both Bun and Node (with a built JS bundle). New flags were added:

  • --help, -h — show help
  • --version — show package version
  • --verbose — show detailed error output / stack traces
  • -o, --output <file> — write transformed output to a file
  • -c, --config <file> — load JSON configuration file (defaults to .ajv-decoderrc in project root)

Basic usage:

  • Verify a packet file:

    • bun: bun run src/cli.ts /path/to/packet.json
    • node (after build): node dist/cli.js /path/to/packet.json
  • Decode a JSON payload (positional):

    • bun run src/cli.ts /path/to/packet.json '{"foo":"bar"}'
  • Decode from stdin:

    • cat data.json | bun run src/cli.ts /path/to/packet.json
  • Write output to a file:

    • bun run src/cli.ts -o out.json /path/to/packet.json '{"foo":"bar"}'

Configuration:

  • Place a JSON file named .ajv-decoderrc in the project root or pass --config <file> to load options used by the CLI.

Testing:

  • The CLI exposes an exported runCli(argv?, transformFn?) function used by tests. Tests inject a small transformFn to avoid loading the full packet processing pipeline and to make CLI behavior deterministic.

npx / node usage:

  • To run via npx, produce a Node-compatible build first (see docs/cli.md) and ensure bin points to the built JS file.

API Reference

For a detailed API reference, please see the API.md file.

Contributing

For guidelines on how to contribute to this project, please see the GEMINI.md file.