Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@ata-project/unplugin

Compiles JSON Schema files into self-contained ata-validator modules at build time, with TypeScript declarations, in Vite, Webpack, Rollup, Rolldown, esbuild and Rspack. One plugin, built on unplugin.

The generated module imports nothing. A typical schema compiles to about 1 KB gzipped, exports validate, isValid and the inferred type, and runs anywhere plain JavaScript runs.

Schemas can be authored as .json, .js or .ts.

Install

npm install --save-dev @ata-project/unplugin ata-validator

ata-validator is a peer dependency and is only used at build time.

Setup

Vite:

// vite.config.ts
import ata from '@ata-project/unplugin/vite'

export default {
  plugins: [ata({ schemas: 'src/**/*.schema.json' })],
}

Webpack:

// webpack.config.js
const ata = require('@ata-project/unplugin/webpack')

module.exports = {
  plugins: [ata({ schemas: 'src/**/*.schema.json' })],
}

Rollup:

// rollup.config.js
import ata from '@ata-project/unplugin/rollup'

export default {
  // Rollup has no project root; tell the plugin where the globs start.
  plugins: [ata({ schemas: 'src/**/*.schema.json', root: process.cwd() })],
}

esbuild:

import { build } from 'esbuild'
import ata from '@ata-project/unplugin/esbuild'

await build({
  entryPoints: ['src/main.ts'],
  bundle: true,
  plugins: [ata({ schemas: 'src/**/*.schema.json' })],
})

Rspack:

// rspack.config.js
const ata = require('@ata-project/unplugin/rspack')

module.exports = {
  plugins: [ata({ schemas: 'src/**/*.schema.json' })],
}

Rolldown:

// rolldown.config.js
import ata from '@ata-project/unplugin/rolldown'

export default {
  plugins: [ata({ schemas: 'src/**/*.schema.json', root: process.cwd() })],
}

Next.js uses Webpack, so the Webpack entry goes into next.config.js:

const ata = require('@ata-project/unplugin/webpack')

module.exports = {
  webpack(config) {
    config.plugins.push(ata({ schemas: 'schemas/**/*.schema.json' }))
    return config
  },
}

Turbopack has no plugin interface this could attach to. Run the compile as a step before the build instead: ata build 'schemas/**/*.schema.json' from ata-validator's CLI, or the compile() function below in a script.

The .schema.json convention

Name a schema user.schema.json and import a typed validator by its name:

import validate, { type User, isValid } from './user.schema'

const r = validate(input)
if (r.valid) {
  // input matched the schema
}
if (isValid(input)) {
  input.id // narrowed to User
}

The plugin writes user.schema.js and user.schema.d.ts next to the schema. The default export is the validate function; validate, isValid and the inferred type are also named exports. The type name comes from the schema's title, then its $id, then the file name.

Add the generated files to .gitignore:

*.schema.js
*.schema.d.ts

Other sources (.json without the .schema suffix, .js, .ts) produce <name>.validator.mjs and <name>.validator.d.mts.

Options

Option Default Description
schemas **/*.schema.json Glob or globs, relative to the root. node_modules is skipped.
outDir next to each schema Directory for generated files, mirroring the source layout.
format 'esm' 'esm' or 'cjs'.
abortEarly false Emit the smaller validator that stops at the first failure.
types true Emit a .d.ts next to each validator.
nameFromFile file name in PascalCase Type name for schemas without title or $id.
root from the bundler Where the globs resolve from. Vite's root, Webpack's and Rspack's context and esbuild's absWorkingDir are read; Rollup and Rolldown need it passed.
alias Vite's resolve.alias Import aliases inside .ts schema files. tsconfig paths work without configuration.

How it works

Output goes to disk, not to virtual modules. That is what makes the plugin identical across bundlers and what lets TypeScript see the generated declarations without any bundler-specific type plumbing.

Schemas compile on build start. On a schema change, Vite recompiles through its HMR hook and Webpack, Rspack, Rollup and Rolldown through watchChange. esbuild has no watch hook, so under esbuild --watch a schema edit alone does not trigger a rebuild; the next build start compiles it.

.ts schemas load through jiti. A schema module exports the schema as default or as a named schema.

A schema the standalone compiler cannot represent is reported with a warning and skipped; the ata-validator runtime API still validates it.

Programmatic use

import { compile } from '@ata-project/unplugin'

const { files, results } = await compile({ schemas: 'schemas/**/*.json', root: process.cwd() })

Tests

npm test compiles the same entry with Vite, Webpack, Rollup, Rolldown, esbuild and Rspack, imports each bundle and runs the validator it contains.

Package name

The package is @ata-project/unplugin; the plugin registers itself in the bundler as unplugin-ata, which is the name in log lines and in plugin.name. The unscoped name is not available on npm.

Relation to ata-vite

ata-vite is this plugin's Vite entry with the old name. It keeps working; new projects can use either.

License

MIT

About

Build-time JSON Schema compilation to standalone ata-validator modules for Vite, Webpack, Rollup, Rolldown, esbuild and Rspack

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages