A tool to manage compiling json schemas with ajv to integrate with build tools such as rollup and vite
MIT License
A universal build tools plugin to handle json schemas compilation with ajv. This will allow you to use highly optmized standalone validation code for your json schemas without any efforts:
$schemas
. See more
npm i ajv-build-tools
/ pnpm i ajv-build-tools
This guide assumes you have familiarity with json schemas and ajv. See Resources
The plugin designed to work with vite and rollup first. This will inlcude features like hot reloading and ssr optmized builds.
import {unpluginAjvTools} from "ajv-build-tools";
export default defineConfig({
plugins: [
unpluginAjvTools.vite({
include: [
"./src/routes/*.{js,ts}",
"./src/**/schemas.{ts,js,\\.d.ts}"
]
})
]
})
Other bundlers are supported as long it's supported by unplugin, but it's well tested and designed to work with vite and rollup.
The plugin extends the schema builder interface
interface SchemaBuilderOptions {
root?: string;
baseDir?: string;
include: string | string[];
exclude?: string | string[];
ajvOptions?: {
all?: AjvOptions;
server?: AjvOptions;
client?: AjvOptions;
};
moduleLoader?: ModuleLoader;
useDirectImport?: boolean;
resolveModule?(module: Record<string, unknown>, file: string): Record<string, any>;
resolveSchema?(schema: any, file: string): any;
plugins?: Plugin[];
}
src
by default.fast-glob
and micromatch
ajvOptions: Pass diferent ajv options based on the instance. use all
to apply to all instances.
resolveModule: module -> schema map. by default all exports are treated as individual schemas, but sometimes you want a custom resolution, for example:
async function resolveModule(module, file) {
if (file.startsWith("routes/")) {
/*
Resolve from:
export GET = {queries: {}}
export POST = {body: {}}
export actions = {default: {body}}
to:
export GET_queries = {} export POST_body = {}
export actions_default_body = {}
*/
return resolveRoutesSchemas(module, file);
}
return module;
},
resolveSchema: Similarly you could resolve each schema invidually, the result should be a valid json schema. This could be used to convert another schema formats to a json schema.
Module loader: Responsible for building and loading the source files for the schema. The default loader will bundle the files with esbuild and import them using a dynamic import. It's rare case to use a custom loader as the default loader will handle most cases including transpilling typescript. An example of custom loader that used by the vite plugin:
moduleLoader(context) {
const { files, defaultModuleLoader } = context;
// if vite dev server available use it to speed up dev speed
if (vite_server) {
return Object.fromEntries(
files.map((file) => {
return [file, vite_server.ssrLoadModule(file)];
})
);
}
return defaultModuleLoader(context);
},
useDirectImport: used by the default loader to decide if to use direct dynamic import or indirectly by using new Function("p", "return import(p)")
. This to avoid transpiling dynamic imports to require by some tools.
Plugins: The builder could be extended with plugins, refer to plugins.types for the available hooks. altho this feature is very WIP and the api subjects to change.
import schemas from "$schemas/routes/api/login/schemas";
// schemas
{
GET_body: ...
}
ajv.getSchema(id_or_key)
)import validateUser from "$schemas:User"
// the default export is the compiled validate function
// it's the same function that return by ajv.compile
// use validateUser.errors to access the last validation errors
// note that's it's a global so refer to ajv docs for more information
import schemas from "$schemas?t=all";
Use ajv-build-tools/types
to declare the virtaul modules.
You could refer to the unplugin source code or the tests to see how to use the core builder.