@cloudflare/cabidela 0.0.17 → 0.0.18
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 +6 -6
- package/dist/index.js +25 -57
- package/dist/index.mjs +25 -57
- package/package.json +1 -1
package/README.md
CHANGED
@@ -6,14 +6,14 @@
|
|
6
6
|
|
7
7
|
|
8
8
|
<p align="center">
|
9
|
-
<em>Small, fast, eval-less,
|
9
|
+
<em>Small, fast, eval-less, <a href="https://developers.cloudflare.com/workers/">Cloudflare Workers</a> compatible, dynamic JSON Schema validator.</em>
|
10
10
|
</p>
|
11
11
|
|
12
12
|
<hr />
|
13
13
|
|
14
|
-
|
14
|
+
## What is
|
15
15
|
|
16
|
-
Cabidela is a small, fast, eval-less,
|
16
|
+
Cabidela is a small, fast, eval-less, Cloudflare Workers compatible, dynamic JSON Schema validator. It implements a large subset of <https://json-schema.org/draft/2020-12/json-schema-validation> that should cover most use-cases. But not all. See limitations below.
|
17
17
|
|
18
18
|
## How to use
|
19
19
|
|
@@ -187,11 +187,11 @@ JSON Schema validators like Ajv tend to follow this pattern:
|
|
187
187
|
2. Compile the schema.
|
188
188
|
3. Validate one or more payloads against the (compiled) schema.
|
189
189
|
|
190
|
-
All of these steps have a cost. Compiling the schema makes sense if you are going to validate multiple payloads in the same session. But in the case of a Workers
|
190
|
+
All of these steps have a cost. Compiling the schema makes sense if you are going to validate multiple payloads in the same session. But in the case of a Workers application we typically want to validate with the HTTP request, one payload at a time, and then we discard the validator.
|
191
191
|
|
192
192
|
Cabidela skips the compilation step and validates the payload directly against the schema.
|
193
193
|
|
194
|
-
In our benchmarks, Cabidela is significantly faster than Ajv on all operations if you don't reuse the validator. Even when we skip the instantiation and compilation steps from Ajv, Cabidela still performs
|
194
|
+
In our benchmarks, Cabidela is significantly faster than Ajv on all operations if you don't reuse the validator. Even when we skip the instantiation and compilation steps from Ajv, Cabidela still performs relatively well.
|
195
195
|
|
196
196
|
Here are some results:
|
197
197
|
|
@@ -239,7 +239,7 @@ npm run benchmark
|
|
239
239
|
|
240
240
|
## Current limitations
|
241
241
|
|
242
|
-
Cabidela supports most of JSON Schema specification for
|
242
|
+
Cabidela supports most of JSON Schema specification, and should be useful for many applications, but it's not complete. **Currently** we do not support:
|
243
243
|
|
244
244
|
- Multiple (array of) types `{ "type": ["number", "string"] }`
|
245
245
|
- Regular expressions
|
package/dist/index.js
CHANGED
@@ -87,19 +87,12 @@ var Cabidela = class {
|
|
87
87
|
}
|
88
88
|
throw(message, needle) {
|
89
89
|
const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(", ")}` : ``}`;
|
90
|
-
throw new Error(
|
91
|
-
this.options.errorMessages ? needle.schema.errorMessage ?? error : error
|
92
|
-
);
|
90
|
+
throw new Error(this.options.errorMessages ? needle.schema.errorMessage ?? error : error);
|
93
91
|
}
|
94
92
|
parseAdditionalProperties(needle, contextAdditionalProperties, contextEvaluatedProperties) {
|
95
93
|
let matchCount = 0;
|
96
|
-
const { metadata, resolvedObject } = resolvePayload(
|
97
|
-
|
98
|
-
needle.payload
|
99
|
-
);
|
100
|
-
const unevaluatedProperties = metadata.properties.difference(
|
101
|
-
contextEvaluatedProperties
|
102
|
-
);
|
94
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
95
|
+
const unevaluatedProperties = metadata.properties.difference(contextEvaluatedProperties);
|
103
96
|
if (contextAdditionalProperties === false) {
|
104
97
|
if (unevaluatedProperties.size > 0) {
|
105
98
|
this.throw(
|
@@ -167,10 +160,7 @@ var Cabidela = class {
|
|
167
160
|
);
|
168
161
|
}
|
169
162
|
if (needle.schema.hasOwnProperty("unevaluatedProperties")) {
|
170
|
-
needle.evaluatedProperties = /* @__PURE__ */ new Set([
|
171
|
-
...needle.evaluatedProperties,
|
172
|
-
...localEvaluatedProperties
|
173
|
-
]);
|
163
|
+
needle.evaluatedProperties = /* @__PURE__ */ new Set([...needle.evaluatedProperties, ...localEvaluatedProperties]);
|
174
164
|
matchCount += this.parseAdditionalProperties(
|
175
165
|
needle,
|
176
166
|
needle.schema.unevaluatedProperties,
|
@@ -178,13 +168,8 @@ var Cabidela = class {
|
|
178
168
|
);
|
179
169
|
}
|
180
170
|
if (needle.schema.hasOwnProperty("required")) {
|
181
|
-
if (new Set(needle.schema.required).difference(
|
182
|
-
needle.
|
183
|
-
).size > 0) {
|
184
|
-
this.throw(
|
185
|
-
`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`,
|
186
|
-
needle
|
187
|
-
);
|
171
|
+
if (new Set(needle.schema.required).difference(needle.evaluatedProperties.union(localEvaluatedProperties)).size > 0) {
|
172
|
+
this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);
|
188
173
|
}
|
189
174
|
}
|
190
175
|
return matchCount ? true : false;
|
@@ -230,10 +215,7 @@ var Cabidela = class {
|
|
230
215
|
return 1;
|
231
216
|
}
|
232
217
|
if (needle.schema.hasOwnProperty("allOf")) {
|
233
|
-
const conditions = needle.schema.allOf.reduce(
|
234
|
-
(r, c) => Object.assign(r, c),
|
235
|
-
{}
|
236
|
-
);
|
218
|
+
const conditions = needle.schema.allOf.reduce((r, c) => Object.assign(r, c), {});
|
237
219
|
try {
|
238
220
|
this.parseSubSchema({
|
239
221
|
...needle,
|
@@ -248,10 +230,7 @@ var Cabidela = class {
|
|
248
230
|
return 0;
|
249
231
|
}
|
250
232
|
}
|
251
|
-
const { metadata, resolvedObject } = resolvePayload(
|
252
|
-
needle.path,
|
253
|
-
needle.payload
|
254
|
-
);
|
233
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
255
234
|
if (needle.schema.type === "array" && !metadata.types.has("binary") && !metadata.types.has("string")) {
|
256
235
|
let matched = 0;
|
257
236
|
for (let item in resolvedObject) {
|
@@ -265,6 +244,16 @@ var Cabidela = class {
|
|
265
244
|
} else if (needle.schema.type === "object" || needle.schema.properties) {
|
266
245
|
return this.parseObject(needle) ? 1 : 0;
|
267
246
|
} else if (resolvedObject !== void 0) {
|
247
|
+
if (needle.schema.hasOwnProperty("const")) {
|
248
|
+
if (resolvedObject !== needle.schema.const) {
|
249
|
+
this.throw(
|
250
|
+
`const ${resolvedObject} doesn't match ${needle.schema.const} at '${pathToString(needle.path)}'`,
|
251
|
+
needle
|
252
|
+
);
|
253
|
+
} else {
|
254
|
+
if (needle.schema.type == void 0) return 1;
|
255
|
+
}
|
256
|
+
}
|
268
257
|
if (needle.schema.hasOwnProperty("enum")) {
|
269
258
|
if (Array.isArray(needle.schema.enum)) {
|
270
259
|
if (!needle.schema.enum.includes(resolvedObject)) {
|
@@ -276,10 +265,7 @@ var Cabidela = class {
|
|
276
265
|
if (needle.schema.type == void 0) return 1;
|
277
266
|
}
|
278
267
|
} else {
|
279
|
-
this.throw(
|
280
|
-
`enum should be an array at '${pathToString(needle.path)}'`,
|
281
|
-
needle
|
282
|
-
);
|
268
|
+
this.throw(`enum should be an array at '${pathToString(needle.path)}'`, needle);
|
283
269
|
}
|
284
270
|
}
|
285
271
|
if (needle.schema.hasOwnProperty("type") && !metadata.types.has(needle.schema.type)) {
|
@@ -292,10 +278,7 @@ var Cabidela = class {
|
|
292
278
|
switch (needle.schema.type) {
|
293
279
|
case "string":
|
294
280
|
if (needle.schema.hasOwnProperty("maxLength") && metadata.size > needle.schema.maxLength) {
|
295
|
-
this.throw(
|
296
|
-
`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`,
|
297
|
-
needle
|
298
|
-
);
|
281
|
+
this.throw(`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`, needle);
|
299
282
|
}
|
300
283
|
if (needle.schema.hasOwnProperty("minLength") && metadata.size < needle.schema.minLength) {
|
301
284
|
this.throw(
|
@@ -307,34 +290,19 @@ var Cabidela = class {
|
|
307
290
|
case "number":
|
308
291
|
case "integer":
|
309
292
|
if (needle.schema.hasOwnProperty("minimum") && resolvedObject < needle.schema.minimum) {
|
310
|
-
this.throw(
|
311
|
-
`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`,
|
312
|
-
needle
|
313
|
-
);
|
293
|
+
this.throw(`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`, needle);
|
314
294
|
}
|
315
295
|
if (needle.schema.hasOwnProperty("exclusiveMinimum") && resolvedObject <= needle.schema.exclusiveMinimum) {
|
316
|
-
this.throw(
|
317
|
-
`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`,
|
318
|
-
needle
|
319
|
-
);
|
296
|
+
this.throw(`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`, needle);
|
320
297
|
}
|
321
298
|
if (needle.schema.hasOwnProperty("maximum") && resolvedObject > needle.schema.maximum) {
|
322
|
-
this.throw(
|
323
|
-
`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`,
|
324
|
-
needle
|
325
|
-
);
|
299
|
+
this.throw(`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`, needle);
|
326
300
|
}
|
327
301
|
if (needle.schema.hasOwnProperty("exclusiveMaximum") && resolvedObject >= needle.schema.exclusiveMaximum) {
|
328
|
-
this.throw(
|
329
|
-
`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`,
|
330
|
-
needle
|
331
|
-
);
|
302
|
+
this.throw(`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`, needle);
|
332
303
|
}
|
333
304
|
if (needle.schema.hasOwnProperty("multipleOf") && resolvedObject % needle.schema.multipleOf !== 0) {
|
334
|
-
this.throw(
|
335
|
-
`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`,
|
336
|
-
needle
|
337
|
-
);
|
305
|
+
this.throw(`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`, needle);
|
338
306
|
}
|
339
307
|
break;
|
340
308
|
}
|
package/dist/index.mjs
CHANGED
@@ -61,19 +61,12 @@ var Cabidela = class {
|
|
61
61
|
}
|
62
62
|
throw(message, needle) {
|
63
63
|
const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(", ")}` : ``}`;
|
64
|
-
throw new Error(
|
65
|
-
this.options.errorMessages ? needle.schema.errorMessage ?? error : error
|
66
|
-
);
|
64
|
+
throw new Error(this.options.errorMessages ? needle.schema.errorMessage ?? error : error);
|
67
65
|
}
|
68
66
|
parseAdditionalProperties(needle, contextAdditionalProperties, contextEvaluatedProperties) {
|
69
67
|
let matchCount = 0;
|
70
|
-
const { metadata, resolvedObject } = resolvePayload(
|
71
|
-
|
72
|
-
needle.payload
|
73
|
-
);
|
74
|
-
const unevaluatedProperties = metadata.properties.difference(
|
75
|
-
contextEvaluatedProperties
|
76
|
-
);
|
68
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
69
|
+
const unevaluatedProperties = metadata.properties.difference(contextEvaluatedProperties);
|
77
70
|
if (contextAdditionalProperties === false) {
|
78
71
|
if (unevaluatedProperties.size > 0) {
|
79
72
|
this.throw(
|
@@ -141,10 +134,7 @@ var Cabidela = class {
|
|
141
134
|
);
|
142
135
|
}
|
143
136
|
if (needle.schema.hasOwnProperty("unevaluatedProperties")) {
|
144
|
-
needle.evaluatedProperties = /* @__PURE__ */ new Set([
|
145
|
-
...needle.evaluatedProperties,
|
146
|
-
...localEvaluatedProperties
|
147
|
-
]);
|
137
|
+
needle.evaluatedProperties = /* @__PURE__ */ new Set([...needle.evaluatedProperties, ...localEvaluatedProperties]);
|
148
138
|
matchCount += this.parseAdditionalProperties(
|
149
139
|
needle,
|
150
140
|
needle.schema.unevaluatedProperties,
|
@@ -152,13 +142,8 @@ var Cabidela = class {
|
|
152
142
|
);
|
153
143
|
}
|
154
144
|
if (needle.schema.hasOwnProperty("required")) {
|
155
|
-
if (new Set(needle.schema.required).difference(
|
156
|
-
needle.
|
157
|
-
).size > 0) {
|
158
|
-
this.throw(
|
159
|
-
`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`,
|
160
|
-
needle
|
161
|
-
);
|
145
|
+
if (new Set(needle.schema.required).difference(needle.evaluatedProperties.union(localEvaluatedProperties)).size > 0) {
|
146
|
+
this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);
|
162
147
|
}
|
163
148
|
}
|
164
149
|
return matchCount ? true : false;
|
@@ -204,10 +189,7 @@ var Cabidela = class {
|
|
204
189
|
return 1;
|
205
190
|
}
|
206
191
|
if (needle.schema.hasOwnProperty("allOf")) {
|
207
|
-
const conditions = needle.schema.allOf.reduce(
|
208
|
-
(r, c) => Object.assign(r, c),
|
209
|
-
{}
|
210
|
-
);
|
192
|
+
const conditions = needle.schema.allOf.reduce((r, c) => Object.assign(r, c), {});
|
211
193
|
try {
|
212
194
|
this.parseSubSchema({
|
213
195
|
...needle,
|
@@ -222,10 +204,7 @@ var Cabidela = class {
|
|
222
204
|
return 0;
|
223
205
|
}
|
224
206
|
}
|
225
|
-
const { metadata, resolvedObject } = resolvePayload(
|
226
|
-
needle.path,
|
227
|
-
needle.payload
|
228
|
-
);
|
207
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
229
208
|
if (needle.schema.type === "array" && !metadata.types.has("binary") && !metadata.types.has("string")) {
|
230
209
|
let matched = 0;
|
231
210
|
for (let item in resolvedObject) {
|
@@ -239,6 +218,16 @@ var Cabidela = class {
|
|
239
218
|
} else if (needle.schema.type === "object" || needle.schema.properties) {
|
240
219
|
return this.parseObject(needle) ? 1 : 0;
|
241
220
|
} else if (resolvedObject !== void 0) {
|
221
|
+
if (needle.schema.hasOwnProperty("const")) {
|
222
|
+
if (resolvedObject !== needle.schema.const) {
|
223
|
+
this.throw(
|
224
|
+
`const ${resolvedObject} doesn't match ${needle.schema.const} at '${pathToString(needle.path)}'`,
|
225
|
+
needle
|
226
|
+
);
|
227
|
+
} else {
|
228
|
+
if (needle.schema.type == void 0) return 1;
|
229
|
+
}
|
230
|
+
}
|
242
231
|
if (needle.schema.hasOwnProperty("enum")) {
|
243
232
|
if (Array.isArray(needle.schema.enum)) {
|
244
233
|
if (!needle.schema.enum.includes(resolvedObject)) {
|
@@ -250,10 +239,7 @@ var Cabidela = class {
|
|
250
239
|
if (needle.schema.type == void 0) return 1;
|
251
240
|
}
|
252
241
|
} else {
|
253
|
-
this.throw(
|
254
|
-
`enum should be an array at '${pathToString(needle.path)}'`,
|
255
|
-
needle
|
256
|
-
);
|
242
|
+
this.throw(`enum should be an array at '${pathToString(needle.path)}'`, needle);
|
257
243
|
}
|
258
244
|
}
|
259
245
|
if (needle.schema.hasOwnProperty("type") && !metadata.types.has(needle.schema.type)) {
|
@@ -266,10 +252,7 @@ var Cabidela = class {
|
|
266
252
|
switch (needle.schema.type) {
|
267
253
|
case "string":
|
268
254
|
if (needle.schema.hasOwnProperty("maxLength") && metadata.size > needle.schema.maxLength) {
|
269
|
-
this.throw(
|
270
|
-
`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`,
|
271
|
-
needle
|
272
|
-
);
|
255
|
+
this.throw(`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`, needle);
|
273
256
|
}
|
274
257
|
if (needle.schema.hasOwnProperty("minLength") && metadata.size < needle.schema.minLength) {
|
275
258
|
this.throw(
|
@@ -281,34 +264,19 @@ var Cabidela = class {
|
|
281
264
|
case "number":
|
282
265
|
case "integer":
|
283
266
|
if (needle.schema.hasOwnProperty("minimum") && resolvedObject < needle.schema.minimum) {
|
284
|
-
this.throw(
|
285
|
-
`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`,
|
286
|
-
needle
|
287
|
-
);
|
267
|
+
this.throw(`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`, needle);
|
288
268
|
}
|
289
269
|
if (needle.schema.hasOwnProperty("exclusiveMinimum") && resolvedObject <= needle.schema.exclusiveMinimum) {
|
290
|
-
this.throw(
|
291
|
-
`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`,
|
292
|
-
needle
|
293
|
-
);
|
270
|
+
this.throw(`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`, needle);
|
294
271
|
}
|
295
272
|
if (needle.schema.hasOwnProperty("maximum") && resolvedObject > needle.schema.maximum) {
|
296
|
-
this.throw(
|
297
|
-
`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`,
|
298
|
-
needle
|
299
|
-
);
|
273
|
+
this.throw(`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`, needle);
|
300
274
|
}
|
301
275
|
if (needle.schema.hasOwnProperty("exclusiveMaximum") && resolvedObject >= needle.schema.exclusiveMaximum) {
|
302
|
-
this.throw(
|
303
|
-
`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`,
|
304
|
-
needle
|
305
|
-
);
|
276
|
+
this.throw(`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`, needle);
|
306
277
|
}
|
307
278
|
if (needle.schema.hasOwnProperty("multipleOf") && resolvedObject % needle.schema.multipleOf !== 0) {
|
308
|
-
this.throw(
|
309
|
-
`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`,
|
310
|
-
needle
|
311
|
-
);
|
279
|
+
this.throw(`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`, needle);
|
312
280
|
}
|
313
281
|
break;
|
314
282
|
}
|
package/package.json
CHANGED