Skip to content
module@warp-drive/schema-dsl

A TypeScript decorator DSL for authoring WarpDrive resource, object, and trait schemas using familiar class syntax, compiled to plain JSON schemas at build time.

Authoring schemas as JSON keeps them flexible, composable, and easy to interoperate with (see In Defense of Machine Formats for more on why), but hand-writing JSON gives up type-safety, autocomplete, and refactoring support. This package lets you author with the ergonomics of TypeScript classes and decorators while still producing standard schema JSON for the store to consume.

Basic Usage

Decorate a class with @Resource and its fields with decorators like @field:

ts
import { Resource, field } from '@warp-drive/schema-dsl';

@Resource
export class User {
  @field declare firstName: string;
  @field declare lastName: string;
}
json
{
  "type": "user",
  "identity": { "kind": "@id", "name": "id" },
  "fields": [
    { "kind": "derived", "name": "$type", "type": "@identity", "options": { "key": "type" } },
    { "kind": "field", "name": "firstName" },
    { "kind": "field", "name": "lastName" },
    { "kind": "derived", "name": "constructor", "type": "@constructor" }
  ]
}

The decorators are no-ops at runtime: nothing in this package should ever run in your production bundle. Compilation happens entirely at build time, so schema files should only ever be imported by the build tooling below, never by application code.

Build Setup

Register the compiler as a Vite plugin, pointing it at a glob of your schema files:

vite.config.ts
ts
import { defineConfig } from 'vite';
import { schemaDSL } from '@warp-drive/schema-dsl/vite';

export default defineConfig({
  plugins: [
    schemaDSL({ schemas: 'app/schemas/**/*.ts' }),
    // ...other plugins
  ],
});

The plugin exposes the compiled output as the virtual module virtual:warp-drive-schemas:

app/setup-schemas.ts
ts
import schemas, { objects, traits } from 'virtual:warp-drive-schemas';

export function registerSchemas(store: Store): void {
  store.schema.registerResources([...schemas, ...objects]);
  traits.forEach((trait) => store.schema.registerTrait?.(trait));
}

What's in a Schema File

A schema file exports one class per resource, object, or trait, each with exactly one class decorator:

  • @Resource — a primary resource with its own identity
  • @ObjectSchema — an embedded object with no independent identity
  • @Trait — a reusable collection of fields composed onto other schemas via @trait

Properties on the class are decorated to describe how each field should be compiled, for instance @field for a plain value, @local for local-only state, or @derived for a computed value. See each decorator's own documentation below for its exact compiled output.

Class Decorators

Field Decorators

Types

Released under the MIT License.