A TypeScript-like JSON Schema definition library that simplifies the creation, validation, and manipulation of JSON schemas. jsondef
provides a concise and expressive syntax for defining complex data structures, making schema definitions more readable and maintainable.
- TypeScript-like Syntax: Familiar syntax for defining JSON schemas.
- Expressive Constraints: Easily define bounds and size constraints.
- Scopes and Namespaces: Use
root
,this
, and named references for complex schemas. - Extensible Types: Support for primitive, complex, and custom types.
- Validation and Parsing: Validate data against schemas and parse schema definitions.
- Type Inference: Infer TypeScript types directly from schemas.
Install jsondef
using npm (or yarn):
npm install jsondef
jsondef
provides a powerful and expressive syntax for defining JSON schemas. The syntax is inspired by TypeScript and allows for defining complex data structures with ease.
Represents any valid JSON value.
any
Represents a null
value.
null
Represents a true
or false
value.
boolean
Represents an integer
or number
value with optional bounds, defined using relational operators:
-
Operators:
>
: Greater than>=
: Greater than or equal to<
: Less than<=
: Less than or equal to
-
Examples:
integer // Unbounded Integer number // Unbounded Number integer(>0) // Integers greater than 0 number(>=-12.2, <=100e+2) // Numbers between -12.2 and 100e+2 inclusive
Represents a literal boolean, integer, number, or string.
-
Boolean Literal:
true false
-
String Literal: Enclosed in single quotes.
'active' 'with\tescapes\n'
-
Integer Literal:
42 -12
-
Number Literal
3.14 -231.2 2.3e+12
Represents a string with optional formats, regex patterns, and size constraints.
-
Formats:
string
: Basic stringdate
,time
,datetime
: Date and time formatsuuid
,email
,base64
: Specific string formats- Regex Patterns: /pattern/[flags]
-
Size Constraints:
Use bounds to specify string length:
-
Operators:
>
,>=
,<
,<=
,=
-
Examples:
string(<=100) // String with max length 100 uuid // String in UUID format email // String in email format /^(?:\+?\d{1,3})?[ -]?\d{7,14}$/ // Custom regex pattern
-
Represnts arrays of elements conforming to a schema, with optional size bounds.
-
Syntax:
<SCHEMA>[<BOUNDS>]
-
Examples:
integer[>=1, <=10] // Array of integers with length between 1 and 10 string[] // Array of strings of any length
Represents objects with dynamic keys and consistent value types, with optional size bounds
-
Syntax:
record<SCHEMA>(<BOUNDS>) record<KEY_SCHEMA, VALUE_SCHEMA>(<BOUNDS>)
-
Examples:
record<string> // Object with string values record<string, integer> // Object with string keys and integer values record<uuid, { name: string }> // Object with UUID keys and objects as values record<boolean>(=10) // Object with boolean values of exactly 10
Represents fixed-size arrays with specific types for each element.
-
Syntax:
[SCHEMA0, SCHEMA1, ...REST]
-
Examples:
[string, integer, boolean] // Tuple with a string, an integer, and a boolean [string, ...integer[]] // Tuple starting with a string followed by any number of integers
Define a type that can be one of several specified schemas.
-
Syntax:
SCHEMA0 | SCHEMA1 | ... | SCHEMAN
-
Examples:
integer | 'active' | 'inactive' // Can be an integer or one of the specified string literals boolean | null // Can be a boolean or null
Represents objects with specific properties.
-
Creates a local scope, that can be recursively referenced with a
this
schema. -
If the object is top level, also sets the root scope, whic hcan be recursively referenced with a
root
schema. -
Similar to typescript, use
?:
instead of:
to denote optional properties. -
Syntax:
{ KEY0: SCHEMA0, KEY1: SCHEMA1, }
-
Examples:
{ name: string, age: integer(>=0), email?: email // Optional property }
Similar to objects, but sets the root scope wherever it is.
-
Syntax:
model { KEY0: SCHEMA0, KEY1: SCHEMA1 }
-
Examples:
model { name: string, parent?: root // Recursive reference to the model itself }
Represents a group of schemas under a single namespace. You can select a specific schema from the group.
-
Syntax:
group { KEY0: SCHEMA0, KEY1: SCHEMA1 }
-
Select a Schema from a Group:
select <KEY> of group { KEY0: SCHEMA0, KEY1: SCHEMA1 }
-
Examples:
// Simple group, no references or selections group { User: model { id: uuid, name: string }, Admin: model { id: uuid, name: string, role: 'admin' } } // Selection from a group select User of group { User: model { id: uuid, name: string }, Admin: model { id: uuid, name: string, role: 'admin' } } // Selection and Reference select User of group { User: model { id: uuid, name: string, role: Role }, Role: 'user' | 'admin' }
-
root
: References the root scope of the current model, useful for recursive definitions that need to refer back to the root. -
this
: References the local scope of the current model, allowing for recursion within the same level. -
Example:
model { name: string(), age: integer(>=0), role: { title: string, manager: root, // rescursively references the entire model subrole?: this // recursively references the current object (role) } }
References a named schema within an ancestor group's namespace.
-
Example:
group { Node: model { value: integer, next: Node | null } }
Here,
Node
is used as an identifier to reference theNode
schema within the same group.
The d
namespace provides a set of functions to build, parse, validate, and infer schemas programmatically.
Schema Builders use a Fluid style to allow easy creation of schemas.
- All Schema Builders have
.optional()
and.required()
methods used for optional properties with models and objects.
Creates a NullSchemaBuilder
instance representing a null
value.
Usage:
const nullSchema = d.null();
Creates an AnySchemaBuilder
instance representing any value.
Usage:
const anySchema = d.any();
Creates a BooleanSchemaBuilder
instance representing a boolean value.
Usage:
const booleanSchema = d.boolean();
Creates a RootSchemaBuilder
instance referencing the root scope.
Usage:
const rootSchema = d.root();
Creates a ThisSchemaBuilder
instance referencing the local scope.
Usage:
const thisSchema = d.this();
Creates an IntegerSchemaBuilder
instance with optional bounds.
Usage:
const positiveInteger = d.integer({ min: 1 });
Creates a NumberSchemaBuilder
instance with optional bounds.
Usage:
const percentage = d.number({ min: 0, max: 100 });
Creates a StringSchemaBuilder
instance with optional size constraints.
Usage:
const shortString = d.string({ max: 50 });
Creates a StringSchemaBuilder
instance for specific formats.
Usage:
const emailSchema = d.email();
const uuidSchema = d.uuid();
Creates a StringSchemaBuilder
instance with a custom regex pattern.
- Parameters:
pattern
: ARegExp
object or regex string.size
(optional): Size constraints.
Usage:
const customString = d.regex(/^[a-z]+$/i);
Creates a LiteralSchemaBuilder
instance for a specific literal value.
Usage:
const activeStatus = d.literal('active');
Creates a UnionSchemaBuilder
instance representing an enum of literals.
Usage:
const statusEnum = d.enum(['active', 'inactive', 'pending']);
Creates an ArraySchemaBuilder
instance for arrays of a specific schema.
Usage:
const stringArray = d.array(d.string(), { min: 1 });
Creates a TupleSchemaBuilder
instance for tuples.
- Parameters:
of
: An array of schemas for the tuple elements.rest
(optional): A schema for additional elements.
Usage:
const mixedTuple = d.tuple([d.string(), d.integer()]);
Creates a RecordSchemaBuilder
instance for objects with uniform value types.
Special Methods:
// Constrains the key that the record can be indexed by
builder.by(key: StringSchema): RecordSchemaBuilder
Usage:
const numberRecord = d.record(d.number());
const uuidNumberRecord = numberRecord.by(d.uuid());
Creates an ObjectSchemaBuilder
instance for an object with specified properties.
Usage:
const userObject = d.object({
username: d.string(),
password: d.string()
});
Creates a ModelSchemaBuilder
instance, setting a new root scope.
Usage:
const userModel = d.model({
username: d.string(),
profile: d.object({
age: d.integer(),
bio: d.string().optional()
})
});
Creates a UnionSchemaBuilder
instance for a union of schemas.
Usage:
const statusUnion = d.union([d.literal('active'), d.literal('inactive')]);
Creates a RefSchemaBuilder
instance referencing another schema in ancestral namespace by name.
Usage:
const employeeSchema = d.model({
manager: d.ref('Employee')
});
Creates a GroupSchemaBuilder
instance containing multiple schemas.
Special Methods:
// Sets which subschema is selected from the group
builder.select(key: keyof Of): GroupSchemaBuilder
Usage:
const schemas = d.group({
Person: personSchema,
Employee: employeeSchema
});
const Person = schemas.select('Person')
Parses a jsondef
string into a schema object.
Usage:
const schema = d.parse(`
model {
name: string,
age: integer(>=0)
}
`);
Attempts to parse a jsondef
string, returning a Result
object.
Usage:
const result = d.tryParse('invalid schema');
if (result.success) {
// Use the schema
} else {
// Handle errors
}
Converts a schema object back into a jsondef
string.
- Parameters:
schema
: The schema object to stringify.format
(optional): Formatting options.condensed
(optional): Boolean indicating whether to use condensed format as base of optional supplied format.
Usage:
const schemaString = d.stringify(schema);
Validate a value against a schema, returning the properly types value.
Usage:
const result = d.validate({ name: 'John', age: 30 }, personSchema);
Attemptes to validate a value against a schema, returning a Result object
Usage:
const result = d.validate({ name: 'John', age: 30 }, personSchema);
if (result.success) {
// Value is valid
} else {
// Handle validation errors
}
Infers the TypeScript type from a schema.
Usage:
type Person = d.infer<typeof personSchema>;
Provides a summary of how tsdoc works, possibly useful for LLMs.
jsondef
is licensed under the MIT License. You are free to use, modify, and distribute this software in compliance with the license.