Claude 666762a146 ✨ feat: add field-name mapping, access control and transform options
A library whose headline feature is "JSON mapping" could not map a name: there
was no way to read {"first_name": ...} into firstName, no way to keep a password
out of the response, and no way to parse a payload without validating it.

Name mapping
- @JsonProperty(name) renames a property in both directions
- @JsonAlias(...names) accepts extra names on input only, so a field can be
  renamed without breaking older clients
- naming strategies (snake_case, kebab-case, SCREAMING_SNAKE_CASE, PascalCase,
  camelCase, or your own function) for properties with no explicit name.
  Acronyms split where a reader expects: parseHTTPResponse -> parse_http_response

Access control
- @JsonIgnore()    excluded both ways
- @JsonWriteOnly() accepted from input, never echoed back (passwords)
- @JsonReadOnly()  serialized, never settable by a client (server-owned ids)

Blocked names are dropped explicitly rather than falling through to the unknown
key path, which would otherwise have copied a rejected id straight back on under
the default policy.

Transform options, per call or globally via configure()
- validate: false to map without validating, for lenient parsing
- unknownKeys: 'allow' | 'strip' | 'error'
- namingStrategy

Error ergonomics — the nested ValidationError tree was hard to turn into an HTTP
400 body. flattenErrors() yields {"items[0].qty": ["qty must be at least 1"]},
plus formatErrors() and collectErrorMessages(). Adds validateOrReject().

All defaults preserve existing behaviour; the 68 prior tests pass unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAcqrz3FcadkYr3xG32CjK
2026-08-03 23:46:18 +00:00
2026-04-11 16:20:19 +02:00

Cereale

Cereale is a lightweight TypeScript library that provides Spring-like decorators for JSON mapping and validation. Built with ZERO external dependencies, it simplifies the process of converting between plain JSON and class instances with full validation support.

Features

  • Spring-like Decorators: Familiar @JsonSerialize, @JsonDeserialize, @JsonType, and @JsonPolymorphic.
  • Custom Serializers/Deserializers: Easily handle complex types like Dates, BigInts, or custom objects.
  • Polymorphism Support: Native handling of polymorphic types via discriminators.
  • Integrated Validation: Automatically validates objects during serialization and deserialization.
  • Type Safety: Fully written in TypeScript for excellent developer experience.
  • Zero Dependencies: Extremely lightweight and fast.

Installation

npm install cereale

Make sure to enable experimentalDecorators and emitDecoratorMetadata in your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2025"
  }
}

Quick Start

1. Define your Models

Use decorators to define how your data should be transformed and validated.

import { 
  IsString, 
  IsInt, 
  Min, 
  IsDate, 
  ValidateNested,
  JsonSerialize, 
  JsonDeserialize, 
  JsonPolymorphic, 
  JsonSerializer, 
  JsonDeserializer 
} from 'cereale';

// Custom Date Serializer
class DateSerializer implements JsonSerializer<Date, string> {
  serialize(value: Date): string {
    return value.toISOString().split('T')[0];
  }
}

class DateDeserializer implements JsonDeserializer<string, Date> {
  deserialize(value: string): Date {
    return new Date(value);
  }
}

abstract class Media {
  @IsString()
  abstract type: string;

  @IsString()
  title: string;
}

class Book extends Media {
  type = 'book';
  
  @IsString()
  author: string;

  @JsonSerialize(DateSerializer)
  @JsonDeserialize(DateDeserializer)
  @IsDate()
  publishedAt: Date;
}

class Library {
  @IsString()
  name: string;

  @ValidateNested({ each: true })
  @JsonPolymorphic('type', [
    { value: Book, name: 'book' }
  ])
  items: Media[];
}

2. Map JSON with Validation

Use standalone utility functions to handle the conversion process directly.

import { fromJson, toJson, JsonValidationError } from 'cereale';

async function main() {
  const json = '{"name": "Central Library", "items": [{"type": "book", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "publishedAt": "1925-04-10"}]}';

  try {
    // Deserialize JSON to Class Instance
    const library = await fromJson(Library, json);
    console.log(library.name); // "Central Library"
    console.log(library.items[0] instanceof Book); // true

    // Serialize Class Instance back to JSON
    const outputJson = await toJson(library);
    console.log(outputJson);
  } catch (error) {
    if (error instanceof JsonValidationError) {
      console.error("Validation failed:", error.errors);
    }
  }
}

3. Modern Web Frameworks (Request Integration)

Cereale is compatible with Fetch-based frameworks like Hono, Next.js, and Remix. Use the fromRequest async helper.

import { fromRequest, toPlain } from 'cereale';

// Hono Example
app.post('/books', async (c) => {
  const book = await fromRequest(Book, c.req.raw);
  return c.json(await toPlain(book));
});

API Reference

Decorators

  • @JsonSerialize(serializer: ClassConstructor<JsonSerializer>): Specifies a custom serializer for a property.
  • @JsonDeserialize(deserializer: ClassConstructor<JsonDeserializer>): Specifies a custom deserializer for a property.
  • @JsonType(typeFunction: () => ClassConstructor<any>): Explicitly sets the type for nested transformations.
  • @JsonPolymorphic(discriminator: string, subTypes: { value: ClassConstructor<any>, name: string }[]): Configures polymorphic transformation based on a discriminator field.

Validation Decorators

Most validation decorators accept an optional ValidationOptions object:

  • each: boolean: Apply validation to each element of an array.
  • message: string | ((args: ValidationArguments) => string): Custom error message.
Decorator Description
@IsString() Checks if value is a string.
@IsNumber() Checks if value is a number (and not NaN).
@IsInt() Checks if value is an integer.
@IsBoolean() Checks if value is a boolean.
@IsObject() Checks if value is an object (not null/array).
@IsDate() Checks if value is a valid Date object.
@IsDefined() Checks if value is not null or undefined.
@IsOptional() Skips other validations if value is null/undefined.
@IsNotEmpty() Checks if value is not null/undefined/empty string.
@Min(value) Checks if number is >= value.
@Max(value) Checks if number is <= value.
@Positive() Checks if number is > 0.
@Negative() Checks if number is < 0.
@MinLength(len) Checks if string length is >= len.
@MaxLength(len) Checks if string length is <= len.
@Email() Checks if string is a valid email.
@IsUrl() Checks if string is a valid URL.
@Matches(regex) Checks if string matches a regular expression.
@IsArray() Checks if value is an array.
@ArrayNotEmpty() Checks if array is not empty.
@ArrayMinSize(n) Checks if array has at least n elements.
@ArrayMaxSize(n) Checks if array has at most n elements.
@IsIn(values) Checks if value is in the allowed list.
@IsNotIn(vals) Checks if value is NOT in the list.
@ValidateNested() Recursively validates nested objects/arrays.

Utilities

  • toJson(obj: any): Validates and serializes an instance to a JSON string (Returns Promise<string>).
  • toPlain(obj: any): Validates and transforms an instance to a plain object (Returns Promise<any>).
  • fromJson(clazz: ClassConstructor, json: string): Parses JSON and transforms it to a validated class instance (Returns Promise<T>).
  • toInstance(clazz: ClassConstructor, plain: any): Transforms a plain object to a validated class instance (Returns Promise<T>).
  • fromRequest(clazz: ClassConstructor, request: Request): Extracts JSON from a Fetch Request and transforms it to a validated instance (Returns Promise<T>).
  • validate(obj: any): Performs full validation on an object/instance (Returns Promise<ValidationError[]>).

Framework Integrations

Cereale is designed to be compatible with all trending web frameworks.

Hono / Next.js / Cloudflare Workers

Use fromRequest for seamless integration with the Fetch Request API.

NestJS

You can use Cereale inside your controllers for explicit mapping and validation without needing reflect-metadata.

import { toInstance } from 'cereale';

@Post()
async create(@Body() body: any) {
  const user = await toInstance(User, body);
  return this.userService.create(user);
}

Express / Fastify

Easily integrate with traditional Node.js frameworks.

import { toInstance, toPlain } from 'cereale';

app.post('/user', async (req, res) => {
  try {
    const user = await toInstance(User, req.body);
    res.json(await toPlain(user));
  } catch (err) {
    res.status(400).json(err);
  }
});

Contributing

Please see CONTRIBUTING.md for details on how to contribute to this project.

License

Cereale is licensed under the MIT License.

S
Description
Cereale is a lightweight TypeScript library that provides Spring-like decorators for JSON mapping and validation.
https://avalon-vanguard.github.io/cereale/
Readme MIT
1,010 KiB
Languages
TypeScript 89.6%
JavaScript 10.4%