@ata-project/unplugin 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -9
- package/package.json +3 -3
- package/src/compile-away.js +24 -2
- package/src/core.js +4 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +7 -2
package/README.md
CHANGED
|
@@ -6,6 +6,11 @@ The generated module imports nothing. A small schema compiles to about 1.3 KB gz
|
|
|
6
6
|
|
|
7
7
|
Schemas can be authored as `.json`, `.js` or `.ts`.
|
|
8
8
|
|
|
9
|
+
It also compiles away `new Validator(schema)` in your own code wherever the schema
|
|
10
|
+
is known at build time and the result is the same, so the runtime compiler stays
|
|
11
|
+
out of the bundle: for the test entry, 122.5 KB gzipped becomes 16.7 KB. See
|
|
12
|
+
[compileAway](#compileaway-keep-new-validator-drop-the-compiler).
|
|
13
|
+
|
|
9
14
|
## Install
|
|
10
15
|
|
|
11
16
|
```bash
|
|
@@ -145,12 +150,12 @@ Other sources (`.json` without the `.schema` suffix, `.js`, `.ts`) produce
|
|
|
145
150
|
| `nameFromFile` | file name in PascalCase | Type name for schemas without `title` or `$id`. |
|
|
146
151
|
| `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. |
|
|
147
152
|
| `alias` | Vite's `resolve.alias` | Import aliases inside `.ts` schema files. tsconfig `paths` work without configuration. |
|
|
148
|
-
| `compileAway` | `
|
|
153
|
+
| `compileAway` | `true` | Replace `new Validator(schema)` in your code with a validator compiled at build time, where that gives the same results. See below. Needs ata-validator 1.36.0; with an older version the runtime stays, and a warning is printed only if you set the option yourself. |
|
|
149
154
|
|
|
150
155
|
## compileAway: keep `new Validator`, drop the compiler
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
Code written against the runtime API is compiled at build time without being
|
|
158
|
+
changed. This is on by default; `compileAway: false` turns it off.
|
|
154
159
|
|
|
155
160
|
```js
|
|
156
161
|
import { Validator } from 'ata-validator'
|
|
@@ -168,8 +173,8 @@ The plugin puts a compiled validator in place of the `new Validator(...)` call,
|
|
|
168
173
|
and once nothing else in the file uses the `ata-validator` import, the import
|
|
169
174
|
goes with it, so the runtime compiler is not in the bundle. For the three-schema
|
|
170
175
|
entry in `test/fixtures/compile-away`, one of them with defaults, a minified Vite
|
|
171
|
-
library build is
|
|
172
|
-
ata-validator 1.
|
|
176
|
+
library build is 122.5 KB gzipped without it and 16.7 KB with it (gzip level 9), on
|
|
177
|
+
ata-validator 1.39.2. Across the 977 schemas of SchemaStore, 725 can be compiled
|
|
173
178
|
away this way.
|
|
174
179
|
|
|
175
180
|
The replacement answers `validate()`, `isValidObject()`, `validateJSON()` and
|
|
@@ -183,9 +188,13 @@ A call is replaced only when all of this is true, and left to the runtime
|
|
|
183
188
|
otherwise:
|
|
184
189
|
|
|
185
190
|
- `Validator` is a named import from `ata-validator`;
|
|
186
|
-
- the
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
- the schema argument is an object literal, a top-level `const` bound to one,
|
|
192
|
+
the default import of a relative `.json` file, or `defineSchema(...)` around
|
|
193
|
+
one of those;
|
|
194
|
+
- there is no second argument, or it is `{ useDefaults: false }` (or
|
|
195
|
+
`{ useDefaults: true }`), written as a literal or a top-level `const`; that
|
|
196
|
+
one option needs ata-validator 1.37.0, and older versions keep such calls on
|
|
197
|
+
the runtime;
|
|
189
198
|
- the result goes into a `const` that is not exported and is only used as
|
|
190
199
|
`name.validate(...)`, `name.isValidObject(...)`, `name.validateJSON(...)` or
|
|
191
200
|
`name.isValidJSON(...)`;
|
|
@@ -193,7 +202,7 @@ otherwise:
|
|
|
193
202
|
`errorMessage`s and shapes its code generator cannot express, which the
|
|
194
203
|
runtime answers with its interpreted engine.
|
|
195
204
|
|
|
196
|
-
|
|
205
|
+
Any other option (`new Validator(schema, { coerceTypes: true })`), a schema
|
|
197
206
|
built at run time, or an instance passed around stays as written.
|
|
198
207
|
|
|
199
208
|
## How it works
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ata-project/unplugin",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Build-time JSON Schema for Vite, Webpack, Rollup, Rolldown, esbuild and Rspack. compileAway takes the runtime compiler out of the bundle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@rspack/core": "^1.7.0",
|
|
81
|
-
"ata-validator": "^1.
|
|
81
|
+
"ata-validator": "^1.39.2",
|
|
82
82
|
"esbuild": "^0.28.0",
|
|
83
83
|
"rolldown": "^1.2.8",
|
|
84
84
|
"rollup": "^4.60.0",
|
package/src/compile-away.js
CHANGED
|
@@ -185,8 +185,24 @@ function inlineModule(src, index) {
|
|
|
185
185
|
return `const __ataCompiled${index} = (() => {\n${body}\nreturn { validate, isValid };\n})();\n`
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// The options of `new Validator(schema, options)` as a third argument for
|
|
189
|
+
// fromCompiled(), or NOT_STATIC when the call has to stay on the runtime: options
|
|
190
|
+
// that are not a literal the build can read, or that name anything this
|
|
191
|
+
// ata-validator's wrapper does not reproduce. `useDefaults: true` is the default
|
|
192
|
+
// and needs no argument.
|
|
193
|
+
function compiledOptionsArg(node, ctx, supported) {
|
|
194
|
+
const opts = staticValue(node, ctx)
|
|
195
|
+
if (opts === NOT_STATIC || opts === null || typeof opts !== 'object' || Array.isArray(opts)) return NOT_STATIC
|
|
196
|
+
for (const [key, value] of Object.entries(opts)) {
|
|
197
|
+
if (!supported.includes(key)) return NOT_STATIC
|
|
198
|
+
if (key === 'useDefaults' && typeof value !== 'boolean') return NOT_STATIC
|
|
199
|
+
}
|
|
200
|
+
return opts.useDefaults === false ? '{"useDefaults":false}' : ''
|
|
201
|
+
}
|
|
202
|
+
|
|
188
203
|
export function compileAway(code, id, ata) {
|
|
189
204
|
const { compiledModuleFor, compiledSchemaFor } = ata
|
|
205
|
+
const supportedOptions = Array.isArray(ata.compiledOptions) ? ata.compiledOptions : []
|
|
190
206
|
if (!code.includes('ata-validator')) return null
|
|
191
207
|
let ast
|
|
192
208
|
try {
|
|
@@ -221,7 +237,13 @@ export function compileAway(code, id, ata) {
|
|
|
221
237
|
for (const r of refs) {
|
|
222
238
|
if (r.node.name !== validatorName) continue
|
|
223
239
|
const expr = r.parent
|
|
224
|
-
if (!expr || expr.type !== 'NewExpression' || r.key !== 'callee'
|
|
240
|
+
if (!expr || expr.type !== 'NewExpression' || r.key !== 'callee') continue
|
|
241
|
+
if (expr.arguments.length !== 1 && expr.arguments.length !== 2) continue
|
|
242
|
+
let optionsArg = ''
|
|
243
|
+
if (expr.arguments.length === 2) {
|
|
244
|
+
optionsArg = compiledOptionsArg(expr.arguments[1], ctx, supportedOptions)
|
|
245
|
+
if (optionsArg === NOT_STATIC) continue
|
|
246
|
+
}
|
|
225
247
|
if (!replaceableBinding(expr, ctx)) continue
|
|
226
248
|
const schema = staticValue(expr.arguments[0], ctx)
|
|
227
249
|
if (schema === NOT_STATIC || schema === null || typeof schema !== 'object' || Array.isArray(schema)) continue
|
|
@@ -230,7 +252,7 @@ export function compileAway(code, id, ata) {
|
|
|
230
252
|
if (!src) continue
|
|
231
253
|
const index = modules.length
|
|
232
254
|
modules.push(inlineModule(src, index))
|
|
233
|
-
s.overwrite(expr.start, expr.end, `__ataFromCompiled(__ataCompiled${index}, ${JSON.stringify(compiledSchemaFor(schema))})`)
|
|
255
|
+
s.overwrite(expr.start, expr.end, `__ataFromCompiled(__ataCompiled${index}, ${JSON.stringify(compiledSchemaFor(schema))}${optionsArg ? ', ' + optionsArg : ''})`)
|
|
234
256
|
done.add(expr)
|
|
235
257
|
}
|
|
236
258
|
if (done.size === 0) return null
|
package/src/core.js
CHANGED
|
@@ -41,7 +41,7 @@ const DEFAULT_OPTIONS = {
|
|
|
41
41
|
format: 'esm',
|
|
42
42
|
abortEarly: false,
|
|
43
43
|
types: true,
|
|
44
|
-
compileAway:
|
|
44
|
+
compileAway: true,
|
|
45
45
|
nameFromFile: (file) => {
|
|
46
46
|
const base = path.basename(file, path.extname(file)).replace(/\.schema$/i, '')
|
|
47
47
|
return pascal(base)
|
|
@@ -69,6 +69,9 @@ async function loadAta() {
|
|
|
69
69
|
toStandaloneModule: build.toStandaloneModule,
|
|
70
70
|
compiledModuleFor: canCompileAway ? build.compiledModuleFor : null,
|
|
71
71
|
compiledSchemaFor: canCompileAway ? build.compiledSchemaFor : null,
|
|
72
|
+
// The Validator options fromCompiled() reproduces, from ata-validator
|
|
73
|
+
// 1.37.0; before it, only calls without options are replaced.
|
|
74
|
+
compiledOptions: canCompileAway && Array.isArray(build.compiledOptions) ? build.compiledOptions : [],
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
|
package/src/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface Options {
|
|
|
27
27
|
* only used through validate(), isValidObject(), validateJSON() and
|
|
28
28
|
* isValidJSON(), so the runtime compiler stays out of the bundle. Results are
|
|
29
29
|
* the ones the runtime gives. Needs ata-validator 1.35.0 or later.
|
|
30
|
-
* Default: `false
|
|
30
|
+
* Default: `true`; `false` turns it off.
|
|
31
31
|
*/
|
|
32
32
|
compileAway?: boolean
|
|
33
33
|
}
|
package/src/index.js
CHANGED
|
@@ -34,8 +34,11 @@ export const unpluginFactory = (userOptions = {}) => {
|
|
|
34
34
|
// compileAway: `new Validator(schema)` with a schema the build can read
|
|
35
35
|
// becomes a validator compiled here, and the runtime compiler leaves the
|
|
36
36
|
// bundle. See src/compile-away.js for what is replaced and what is not.
|
|
37
|
+
// On unless the caller turned it off. It replaces a call only where the
|
|
38
|
+
// compiled validator answers exactly as the runtime would, so being on by
|
|
39
|
+
// default can cost a saving but not change a result.
|
|
37
40
|
transformInclude(id) {
|
|
38
|
-
if (
|
|
41
|
+
if (userOptions.compileAway === false) return false
|
|
39
42
|
const file = id.split('?')[0]
|
|
40
43
|
return SOURCE.test(file) && !file.split(/[\\/]/).includes('node_modules')
|
|
41
44
|
},
|
|
@@ -44,7 +47,9 @@ export const unpluginFactory = (userOptions = {}) => {
|
|
|
44
47
|
if (!code.includes('ata-validator')) return null
|
|
45
48
|
const api = await session.api()
|
|
46
49
|
if (!api.compiledModuleFor) {
|
|
47
|
-
|
|
50
|
+
// Only a caller who asked for it hears that it could not happen; on
|
|
51
|
+
// by default, an older ata-validator just keeps the runtime.
|
|
52
|
+
if (userOptions.compileAway === true && !session.warnedCompileAway) {
|
|
48
53
|
session.warnedCompileAway = true
|
|
49
54
|
session.logger?.warn?.('[unplugin-ata] compileAway needs ata-validator 1.36.0 or later; nothing was replaced')
|
|
50
55
|
}
|