@netfeez/schema
v0.1.0
Published
A strongly-typed schema definition, validation and type-inference library for TypeScript.
Maintainers
Readme
Schema
A strongly-typed schema definition, validation and type-inference library for TypeScript.
Schema defines data contracts once and derives their runtime and compile-time behavior from the same definition. It provides validation, default resolution, input/output inference, patch types, flat patches and JSON Schema generation without maintaining separate type and runtime representations.
Features
- Strongly-typed schema definitions
- Runtime validation and processing
- Default and derived-default resolution
InputandOutputtype inference- Object and flat patching
- Union and nullable definitions
- Additional-property policies
- JSON Schema generation
- Unique-field introspection
- Compile-time validation of schema definitions
- ESM with generated TypeScript declarations
Installation
npm install @netfeez/schemaQuick Start
import Schema from '@netfeez/schema';
const schema = new Schema({
name: {
type: 'string',
required: true
},
port: {
type: 'number',
default: 25565
},
enabled: {
type: 'boolean',
default: true
}
});
const value = schema.process({
name: 'server'
});The processed value contains materialized defaults:
{
name: 'server',
port: 25565,
enabled: true
}The same definition also determines the corresponding TypeScript types.
Definitions
Schemas are built from a small declarative definition language:
const schema = new Schema({
id: {
type: 'string',
required: true,
unique: true
},
name: {
type: 'string'
},
port: {
type: 'number',
minimum: 1,
maximum: 65535,
default: 25565
},
enabled: {
type: 'boolean',
default: true
},
tags: {
type: 'array',
items: {
type: 'string'
}
}
});Definitions support:
stringnumberbooleanobjectarrayunion
Common properties include:
requirednullabledefaultdescriptionunique
Primitive definitions can additionally constrain their values. Objects can declare nested keys and control additional properties.
const schema = new Schema({
database: {
type: 'object',
keys: {
host: {
type: 'string',
default: 'localhost'
},
port: {
type: 'number',
default: 5432
}
},
additional: false
}
});An object can also be created directly from its key map:
const schema = Schema.fromObject({
name: {
type: 'string',
required: true
}
});Type Inference
Schema derives TypeScript types directly from the definition.
type Config = Schema.Infer<typeof schema>;Schema.Infer is the output type produced after processing the schema.
The underlying inference API also exposes the two sides of the contract:
type Input = Schema.Input<typeof schema>;
type Output = Schema.Output<typeof schema>;Defaults and required properties are reflected in these types.
For example:
const schema = new Schema({
name: {
type: 'string',
required: true
},
port: {
type: 'number',
default: 25565
}
});The input requires name, while port can be omitted because the schema can provide it.
The output contains the materialized port.
This keeps the compile-time contract aligned with the runtime processing rules.
Processing
process() validates and materializes input according to the definition.
const result = schema.process(input);Unknown data can also be processed through the unknown-input overload:
const result = schema.processUnknown(value);For explicit validation without processing:
schema.validate(value);Invalid values throw SchemaError.
Defaults
Definitions can provide explicit defaults:
const schema = new Schema({
port: {
type: 'number',
default: 25565
}
});Defaults can also be derived through nested object definitions when their required children can be satisfied by defaults.
const schema = new Schema({
server: {
type: 'object',
keys: {
host: {
type: 'string',
default: 'localhost'
},
port: {
type: 'number',
default: 25565
}
}
}
});The default semantics are shared by the runtime processor and the type-level inference system.
Patching
Schema supports two patch representations.
Object patches
patch() accepts root-level keys:
const patch = schema.patch({
port: 3000
});Dot-joined paths are intentionally rejected by patch().
Flat patches
patchPaths() accepts dot-joined paths:
const patch = schema.patchPaths({
'server.host': 'localhost',
'server.port': 3000
});The corresponding type is available as:
type Patch = Schema.Patch<typeof schema>;
type FlatPatch = Schema.FlatPatch<typeof schema>;The patch types are derived from the same schema definition rather than maintained separately.
Unions
Definitions can describe multiple possible shapes:
const schema = new Schema({
value: {
type: 'union',
union: [
{
type: 'string'
},
{
type: 'number'
}
]
}
});Nullable definitions are also supported:
const schema = new Schema({
value: {
type: 'string',
nullable: true
}
});Union definitions participate in both runtime processing and static inference.
Additional Properties
Objects can explicitly control properties not declared in keys.
Reject additional properties:
const schema = new Schema({
type: 'object',
keys: {
name: {
type: 'string'
}
},
additional: false
});Accept them without further processing:
const schema = new Schema({
type: 'object',
keys: {
name: {
type: 'string'
}
},
additional: true
});Or validate them against another definition:
const schema = new Schema({
type: 'object',
keys: {
name: {
type: 'string'
}
},
additional: {
type: 'string'
}
});JSON Schema
Definitions can be exported as JSON Schema:
const jsonSchema = schema.jsonSchema;or serialized directly:
const json = schema.jsonSchemaJSON;The conversion preserves supported schema metadata, constraints, defaults, descriptions, nullable branches and additional-property policies.
Derived defaults can be included when requested through JsonSchema:
import { JsonSchema } from '@netfeez/schema';
const jsonSchema = JsonSchema.toJsonSchema(schema.definition, {
derivedDefaults: true
});Unique Fields
Definitions can mark fields as unique:
const schema = new Schema({
id: {
type: 'string',
unique: true
},
database: {
type: 'object',
keys: {
name: {
type: 'string',
unique: true
}
}
}
});Unique paths are available through:
const uniques = schema.uniques;Nested paths are represented using dot notation.
API
The public entry point exposes:
import Schema, {
Definition,
JsonSchema,
SchemaError
} from '@netfeez/schema';Schema
new Schema(definition)
new Schema(keys, additional?)
Schema.fromObject(keys, additional?)Runtime operations:
schema.process(data)
schema.processUnknown(data)
schema.validate(data)
schema.patch(data)
schema.patchPaths(data)
schema.jsonSchema
schema.jsonSchemaJSON
schema.uniquesType projections:
Schema.Infer<D>
Schema.Input<D>
Schema.Output<D>
Schema.Patch<D>
Schema.FlatPatch<D>Definition
The Definition namespace exposes the schema definition types:
Definition.String
Definition.Number
Definition.Boolean
Definition.Object
Definition.Array
Definition.Union
Definition.DefinitionJsonSchema
JsonSchema.toJsonSchema(definition, options?)SchemaError
Runtime validation and processing failures are reported through SchemaError.
Development
Build the library:
npm run buildRun the runtime test suite:
npm testRun the type-level tests:
npm run test:typesWatch the source during development:
npm run devThe project uses strict TypeScript compilation and maintains separate runtime and type-level test suites.
License
Apache-2.0
