Overview
The @apisr/transform package provides a powerful system for defining data collections with typed transformations. It uses a registry-based approach with tags to describe data structures and enable safe transformations between different data formats.
Installation
npm install @apisr/transform
Exports
The package exports the following core utilities:
registry() - Create a typed registry of tags
collection() - Define data collections with transformations
BaseTag - Base class for creating tags
StringTag - Specialized tag for string data
Type utilities: Registry, Collection, PromiseOr
Core Concepts
Tags are typed descriptors for data fields. They define the shape and validation rules for data:
import { BaseTag , StringTag } from '@apisr/transform' ;
import { z } from '@apisr/zod' ;
// Create a base tag
const userIdTag = new BaseTag ({
schema: z . string (),
required: true ,
});
// Create a string tag with constraints
const usernameTag = new BaseTag ()
. string ()
. min ( 3 )
. max ( 20 )
. required ();
// Create a number tag
const ageTag = new BaseTag (). number ();
Registry
Registries organize collections of tags with type safety:
import { registry } from '@apisr/transform' ;
const userRegistry = registry (( tag ) => ({
id: tag . string (). required (),
username: tag . string (). min ( 3 ). max ( 20 ). required (),
email: tag . string (). required (),
age: tag . number (),
bio: tag . string (). max ( 500 ),
}));
// Access tags from the registry
const idTag = userRegistry ( 'id' );
const usernameTag = userRegistry ( 'username' );
Collections
Collections define versioned data structures with transformation capabilities:
import { collection } from '@apisr/transform' ;
const userCollection = collection ({
// Version 1
'user.v1' : {
id: z . string (),
name: z . string (),
},
// Version 2 with additional fields
'user.v2' : {
id: z . string (),
name: z . string (),
email: z . string (),
createdAt: z . date (),
},
});
Usage
Creating Tagged Schemas
Define reusable, validated data structures:
import { registry } from '@apisr/transform' ;
import { z } from '@apisr/zod' ;
const productRegistry = registry (( tag ) => ({
id: tag . string (). required (),
name: tag . string (). min ( 1 ). max ( 100 ). required (),
description: tag . string (). max ( 1000 ),
price: tag . number (). required (),
inStock: tag . schema ( z . boolean ()),
category: tag . string (). required (),
}));
// Use the registry
const nameTag = productRegistry ( 'name' );
const priceTag = productRegistry ( 'price' );
Tag Methods
Tags provide a fluent API for defining constraints:
const tag = new BaseTag ()
. string () // Create string tag
. min ( 5 ) // Minimum length
. max ( 50 ) // Maximum length
. required (); // Mark as required
const tag = new BaseTag ()
. number () // Create number tag
. required (); // Mark as required
import { z } from '@apisr/zod' ;
const tag = new BaseTag ()
. schema ( z . object ({
lat: z . number (),
lng: z . number (),
}))
. required ();
Transform data between different collection versions:
import { collection } from '@apisr/transform' ;
import { z } from '@apisr/zod' ;
const userCollection = collection ({
'user.v1' : {
id: z . string (),
name: z . string (),
},
'user.v2' : {
id: z . string (),
firstName: z . string (),
lastName: z . string (),
},
});
const result = userCollection . transform (
{ id: '123' , name: 'John Doe' },
{
from: 'user.v1' ,
to: 'user.v2' ,
mode: 'strict' , // or 'warn' or 'loose'
explain: true ,
}
);
// result: { value, errors, explain }
Source collection key (e.g., "user.v1")
Target collection key (e.g., "user.v2")
mode
'strict' | 'warn' | 'loose'
default: "strict"
Transformation strictness level:
strict: Fail on any validation error
warn: Log warnings but continue
loose: Ignore validation errors
Include detailed explanation of the transformation
Collection Key Naming
Collections support three naming patterns:
// Simple naming
'user' : { ... }
// Namespace naming
'api.user' : { ... }
// Versioned naming
'api.user@v1' : { ... }
'api.user@v2' : { ... }
Versioned naming is recommended for APIs that need to support multiple versions simultaneously.
Advanced Features
Registry Derivation
Create derived tags based on other tags (planned feature):
const registry = registry (( tag ) => ({
firstName: tag . string (),
lastName: tag . string (),
}))
. derive ( 'fullName' , ( tags ) => {
return ` ${ tags . firstName } ${ tags . lastName } ` ;
}, { when: 'always' });
The derive() method is currently under development and will throw an error if called.
Array Collections
Transform arrays of data:
const userCollection = collection ({
'user.v1' : {
id: z . string (),
name: z . string (),
},
});
// Transform array of users
const arrayTransform = userCollection . arrayOf ();
Type Utilities
PromiseOr<T>
Accepts either a value or a promise of that value:
import type { PromiseOr } from '@apisr/transform' ;
function processData ( data : PromiseOr < string >) : Promise < string > {
return Promise . resolve ( data );
}
// Both work
await processData ( 'hello' );
await processData ( Promise . resolve ( 'hello' ));
UnwrapFunctionObject<T>
Unwraps the return type of a function:
import type { UnwrapFunctionObject } from '@apisr/transform' ;
type Result = UnwrapFunctionObject <() => { name : string }>;
// Result = { name: string }
Error Handling
Thrown when accessing a non-existent tag from a registry: const registry = registry (( tag ) => ({
name: tag . string (),
}));
registry ( 'name' ); // OK
registry ( 'email' ); // Error: Tag with name 'email' is not found.
Derive not developed error
The derive() method is currently under development: registry . derive ( 'fullName' , ... ); // Error: Derive is still not developed.
@apisr/zod Extended Zod for schema validation
@apisr/schema Core schema types and utilities