Enzo Marioni 7fe7e8c7c3 ✨ feat: implement core Optimus library for JSON mapping and validation
- 🎨 add Spring-like decorators (@JsonSerialize, @JsonDeserialize, etc.)
- ⚙️ implement JsonMapper and metadata storage for transformations
- 🧪 add comprehensive test suite using Vitest
- 📝 add README, CONTRIBUTING, and API documentation
- 👷 setup GitHub Actions CI workflow
- 🔧 configure TypeScript and project settings
2026-04-11 16:58:12 +02:00
2026-04-11 16:20:19 +02:00

Optimus

Optimus 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 optimus

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

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

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 'optimus';

// 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 JsonMapper to handle the conversion process.

import { JsonMapper, JsonValidationError } from 'optimus';

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 JsonMapper.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 JsonMapper.toJson(library);
    console.log(outputJson);
  } catch (error) {
    if (error instanceof JsonValidationError) {
      console.error("Validation failed:", error.errors);
    }
  }
}

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

  • JsonMapper.toJson(obj: any, options?): Validates and serializes an instance to a JSON string.
  • JsonMapper.toPlain(obj: any, options?): Validates and transforms an instance to a plain object.
  • JsonMapper.fromJson(clazz: ClassConstructor, json: string, options?): Parses JSON and transforms it to a validated class instance.
  • JsonMapper.toInstance(clazz: ClassConstructor, plain: any, options?): Transforms a plain object to a validated class instance.

Contributing

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

License

Optimus is licensed under the ISC 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
971 KiB
Languages
TypeScript 89.6%
JavaScript 10.4%