A standalone JSON Schema library for the Adapt framework stack. Load schemas from plugin folders via glob patterns and validate JSON data with automatic defaults application via AJV.
npm install adapt-schemasimport Schemas from 'adapt-schemas'
// Create and initialize the library
const library = new Schemas()
library.init()
// Load schemas from plugin directories
library.loadSchemas('**/schema/*.schema.json', {
cwd: './plugins',
ignore: ['**/node_modules/**']
})
// Validate data against a schema (defaults are applied automatically)
const validatedData = library.validate('course', {
title: 'My Course'
})const library = new Schemas({
enableCache: true, // Enable schema build caching (default: true)
xssWhitelist: {}, // Custom XSS whitelist tags/attributes
xssWhitelistOverride: false, // Replace defaults instead of extending
formatOverrides: {} // Custom string format RegExp patterns
})Initializes the library and loads the base schema.
library.init()Loads schemas from directories matching glob patterns.
library.loadSchemas('**/schema/*.schema.json', {
cwd: './plugins', // Base directory for patterns
ignore: ['**/excluded/**'] // Patterns to exclude
})
// Multiple patterns
library.loadSchemas([
'core/**/schema/*.schema.json',
'plugins/**/schema/*.schema.json'
], { ignore: ['**/node_modules/**'] })Registers a single schema file.
library.registerSchema('/path/to/schema.json', {
replace: false // Replace existing schema with same name
})Retrieves and builds a schema by name.
const schema = library.getSchema('course', {
useCache: true, // Use cached build if available
compile: true, // Compile the schema
applyExtensions: true // Apply $patch extensions
})Returns the built schema object.
const schemaObj = library.getBuiltSchema('course')
console.log(schemaObj.properties)Validates data against a named schema.
const validated = library.validate('course', inputData, {
useDefaults: true, // Apply schema defaults (default: true)
ignoreRequired: false // Ignore required field errors
})Returns list of all registered schema names.
const names = library.getSchemaNames()
// ['base', 'course', 'content', 'component', ...]Returns information about all registered schemas.
const info = library.getSchemaInfo()
// { course: { filePath: '...', extensions: [...], isPatch: false } }Manually extends a schema with another.
library.extendSchema('course', 'my-course-extension')Adds a custom AJV keyword.
library.addKeyword({
keyword: 'isPositive',
type: 'number',
validate: (schema, data) => data > 0
})
// Override an existing keyword
library.addKeyword({
keyword: 'isPositive',
type: 'number',
validate: (schema, data) => data >= 0
}, { override: true })Removes a schema from the registry.
library.deregisterSchema('my-schema')Adds custom string format validators.
library.addStringFormats({
'phone': /^\+?[\d\s-]+$/
})The library extends EventEmitter and emits the following events:
library.on('initialized', () => { })
library.on('reset', () => { })
library.on('schemasLoaded', (schemaNames) => { })
library.on('schemaRegistered', (name, filePath) => { })
library.on('schemaDeregistered', (name) => { })
library.on('schemaExtended', (baseName, extName) => { })
library.on('warning', (message) => { })Schemas use $merge to inherit from a parent schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$anchor": "content",
"$merge": {
"source": { "$ref": "base" },
"with": {
"properties": {
"title": {
"type": "string",
"default": ""
},
"body": {
"type": "string",
"default": ""
}
},
"required": ["title"]
}
}
}Use $patch to extend an existing schema without creating a new one:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$anchor": "course-trickle-extension",
"$patch": {
"source": { "$ref": "course" },
"with": {
"properties": {
"_globals": {
"type": "object",
"properties": {
"_trickle": {
"type": "object",
"properties": {
"incompleteContent": {
"type": "string",
"default": "There is incomplete content above"
}
}
}
}
}
}
}
}
}The library includes these custom AJV keywords:
| Keyword | Description | Example |
|---|---|---|
isBytes |
Parses byte strings | "1MB" → 1048576 |
isDate |
Parses date strings | "2024-01-01" → Date |
isTimeMs |
Parses duration strings | "7d" → 604800000 |
isObjectId |
Marks ObjectId fields | No transformation |
The library throws SchemaError with the following codes:
| Code | Description |
|---|---|
INVALID_PARAMS |
Invalid method parameters |
SCHEMA_EXISTS |
Schema with same name already registered |
SCHEMA_LOAD_FAILED |
Failed to read/parse schema file |
INVALID_SCHEMA |
Schema fails JSON Schema validation |
MISSING_SCHEMA |
Requested schema not found |
VALIDATION_FAILED |
Data fails schema validation |
KEYWORD_EXISTS |
Keyword already defined |
MODIFY_PROTECTED_ATTR |
Attempt to modify internal/read-only field |
import { SchemaError } from 'adapt-schemas'
try {
library.validate('course', data)
} catch (e) {
if (e instanceof SchemaError) {
console.log(e.code) // 'VALIDATION_FAILED'
console.log(e.data) // { schemaName, errors, data }
}
}MIT