@cloudflare/cabidela 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +13 -0
- package/README.md +241 -0
- package/dist/helpers.d.ts +13 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +303 -0
- package/dist/index.js.map +7 -0
- package/package.json +35 -0
package/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2023 Cloudflare, Inc.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
# Cabidela
|
2
|
+
|
3
|
+
Cabidela is a small, fast, eval-less, [Cloudflare Workers](https://developers.cloudflare.com/workers/) compatible, dynamic JSON Schema validator.
|
4
|
+
|
5
|
+
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.
|
6
|
+
|
7
|
+
## How to use
|
8
|
+
|
9
|
+
Install the package:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
npm install @cloudflare/cabidela --save
|
13
|
+
```
|
14
|
+
|
15
|
+
Import it:
|
16
|
+
|
17
|
+
```ts
|
18
|
+
import { Cabidela } from "@cloudflare/cabidela";
|
19
|
+
```
|
20
|
+
|
21
|
+
Use it:
|
22
|
+
|
23
|
+
```ts
|
24
|
+
let schema: any = {
|
25
|
+
type: "object",
|
26
|
+
properties: {
|
27
|
+
prompt: {
|
28
|
+
type: "string",
|
29
|
+
minLength: 1,
|
30
|
+
maxLength: 131072,
|
31
|
+
description: "The input text prompt for the model to generate a response.",
|
32
|
+
},
|
33
|
+
num_steps: {
|
34
|
+
type: "number",
|
35
|
+
minimum: 0,
|
36
|
+
maximum: 20,
|
37
|
+
description: "Increases the likelihood of the model introducing new topics.",
|
38
|
+
},
|
39
|
+
},
|
40
|
+
required: ["prompt"],
|
41
|
+
};
|
42
|
+
|
43
|
+
const cabidela = new Cabidela(schema);
|
44
|
+
|
45
|
+
cabidela.validate({
|
46
|
+
prompt: "Tell me a joke",
|
47
|
+
num_steps: 5,
|
48
|
+
});
|
49
|
+
```
|
50
|
+
|
51
|
+
Cabidela implements a [Exception-Driven Validation](https://json-schema.org/implementers/interfaces#exception-driven-validation) approach. If any condition in the schema is not met, we throw an error.
|
52
|
+
|
53
|
+
## API
|
54
|
+
|
55
|
+
### New instance
|
56
|
+
|
57
|
+
`const cabidela = new Cabidela(schema: any, options?: CabidelaOptions)`
|
58
|
+
|
59
|
+
Cabidela takes a JSON-Schema and optional configuration flags:
|
60
|
+
|
61
|
+
- `applyDefaults`: boolean - If true, the validator will apply default values to the input object. Default is false.
|
62
|
+
- `errorMessages`: boolean - If true, the validator will use custom `errorMessage` messages from the schema. Default is false.
|
63
|
+
- `fullErrors`: boolean - If true, the validator will be more verbose when throwing errors for complex schemas (example: anyOf, oneOf's), set to false for shorter exceptions. Default is true.
|
64
|
+
|
65
|
+
Returns a validation object.
|
66
|
+
|
67
|
+
You can change the schema at any time by calling `cabidela.setSchema(schema: any)`.
|
68
|
+
|
69
|
+
You can change the options at any time by calling `cabidela.setOptions(options: CabidelaOptions)`.
|
70
|
+
|
71
|
+
### Validate payload
|
72
|
+
|
73
|
+
Call `cabidela.validate(payload: any)` to validate your payload.
|
74
|
+
|
75
|
+
Returns truth if the payload is valid, throws an error otherwise.
|
76
|
+
|
77
|
+
```js
|
78
|
+
const payload = {
|
79
|
+
messages: [
|
80
|
+
{ role: "system", content: "You're a helpful assistant" },
|
81
|
+
{ role: "user", content: "What is Cloudflare?" },
|
82
|
+
],
|
83
|
+
};
|
84
|
+
|
85
|
+
try {
|
86
|
+
cabidela.validate(payload);
|
87
|
+
console.log("Payload is valid");
|
88
|
+
} catch (e) {
|
89
|
+
console.error(e);
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
## Modifying the payload
|
94
|
+
|
95
|
+
Some options, like `applyDefaults`, will modify the input object.
|
96
|
+
|
97
|
+
```js
|
98
|
+
const schema = {
|
99
|
+
type: "object",
|
100
|
+
properties: {
|
101
|
+
prompt: {
|
102
|
+
type: "string",
|
103
|
+
},
|
104
|
+
num_steps: {
|
105
|
+
type: "number",
|
106
|
+
default: 10,
|
107
|
+
},
|
108
|
+
},
|
109
|
+
};
|
110
|
+
|
111
|
+
const cabidela = new Cabidela(schema, { applyDefaults: true });
|
112
|
+
|
113
|
+
const payload = {
|
114
|
+
prompt: "Tell me a joke",
|
115
|
+
});
|
116
|
+
|
117
|
+
cabidela.validate(payload);
|
118
|
+
|
119
|
+
console.log(payload);
|
120
|
+
|
121
|
+
// {
|
122
|
+
// prompt: 'Tell me a joke',
|
123
|
+
// num_steps: 10
|
124
|
+
// }
|
125
|
+
|
126
|
+
```
|
127
|
+
|
128
|
+
## Custom errors
|
129
|
+
|
130
|
+
If the new instance options has the `errorMessages` flag set to true, you can use the property `errorMessage` in the schema to define custom error messages.
|
131
|
+
|
132
|
+
```js
|
133
|
+
const schema = {
|
134
|
+
type: "object",
|
135
|
+
properties: {
|
136
|
+
prompt: {
|
137
|
+
type: "string",
|
138
|
+
},
|
139
|
+
},
|
140
|
+
required: ["prompt"],
|
141
|
+
errorMessage: "prompt required",
|
142
|
+
};
|
143
|
+
|
144
|
+
const cabidela = new Cabidela(schema, { errorMessages: true });
|
145
|
+
|
146
|
+
const payload = {
|
147
|
+
missing: "prompt",
|
148
|
+
});
|
149
|
+
|
150
|
+
cabidela.validate(payload);
|
151
|
+
// throws "Error: prompt required"
|
152
|
+
```
|
153
|
+
|
154
|
+
## Tests
|
155
|
+
|
156
|
+
The tests can be found [here](./tests/).
|
157
|
+
|
158
|
+
Cabidela uses [vitest](https://vitest.dev/) to test internal methods and compliance with the [JSON Schema specification](https://json-schema.org/). To run the tests type:
|
159
|
+
|
160
|
+
```bash
|
161
|
+
npm run test
|
162
|
+
```
|
163
|
+
|
164
|
+
You can also run the tests with [Ajv](https://ajv.js.org/), or both. This allows us to compare the results and double-check how we interpret the specification.
|
165
|
+
|
166
|
+
```bash
|
167
|
+
npm run test-ajv
|
168
|
+
npm run test-all
|
169
|
+
```
|
170
|
+
|
171
|
+
## Performance
|
172
|
+
|
173
|
+
JSON Schema validators like Ajv tend to follow this pattern:
|
174
|
+
|
175
|
+
1. Instantiate a validator.
|
176
|
+
2. Compile the schema.
|
177
|
+
3. Validate one or more payloads against the (compiled) schema.
|
178
|
+
|
179
|
+
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 applications we typically want to validate with the HTTP request, one payload at a time, and then we discard the validator.
|
180
|
+
|
181
|
+
Cabidela skips the compilation step and validates the payload directly against the schema.
|
182
|
+
|
183
|
+
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 on par or better than Ajv.
|
184
|
+
|
185
|
+
Here are some results:
|
186
|
+
|
187
|
+
```bash
|
188
|
+
Cabidela - benchmarks/00-basic.bench.js > allOf, two properties
|
189
|
+
1929.61x faster than Ajv
|
190
|
+
|
191
|
+
Cabidela - benchmarks/00-basic.bench.js > allOf, two objects
|
192
|
+
1351.41x faster than Ajv
|
193
|
+
|
194
|
+
Cabidela - benchmarks/00-basic.bench.js > anyOf, two conditions
|
195
|
+
227.48x faster than Ajv
|
196
|
+
|
197
|
+
Cabidela - benchmarks/00-basic.bench.js > oneOf, two conditions
|
198
|
+
224.49x faster than Ajv
|
199
|
+
|
200
|
+
Cabidela - benchmarks/80-big-ops.bench.js > Big array payload
|
201
|
+
386.44x faster than Ajv
|
202
|
+
|
203
|
+
Cabidela - benchmarks/80-big-ops.bench.js > Big object payload
|
204
|
+
6.08x faster than Ajv
|
205
|
+
|
206
|
+
Cabidela - benchmarks/80-big-ops.bench.js > Deep schema, deep payload
|
207
|
+
59.75x faster than Ajv
|
208
|
+
|
209
|
+
Cabidela - benchmarks/80-big-ops.bench.js > allOf, two properties
|
210
|
+
1701.95x faster than Ajv
|
211
|
+
|
212
|
+
Cabidela - benchmarks/80-big-ops.bench.js > allOf, two objects
|
213
|
+
1307.04x faster than Ajv
|
214
|
+
|
215
|
+
Cabidela - benchmarks/80-big-ops.bench.js > anyOf, two conditions
|
216
|
+
207.73x faster than Ajv
|
217
|
+
|
218
|
+
Cabidela - benchmarks/80-big-ops.bench.js > oneOf, two conditions
|
219
|
+
211.72x faster than Ajv
|
220
|
+
```
|
221
|
+
|
222
|
+
We use Vitest's [bench](https://vitest.dev/api/#bench) feature to run the benchmarks. You can find the benchmarks in the [benchmarks](./benchmarks/) folder and you can run them with:
|
223
|
+
|
224
|
+
```bash
|
225
|
+
npm run benchmark
|
226
|
+
```
|
227
|
+
|
228
|
+
|
229
|
+
## Current limitations
|
230
|
+
|
231
|
+
Cabidela supports most of JSON Schema specification for most use-cases, we think. However it's not complete. **Currently** we do not support:
|
232
|
+
|
233
|
+
- Multiple (array of) types `{ "type": ["number", "string"] }`
|
234
|
+
- Regular expressions
|
235
|
+
- Pattern properties
|
236
|
+
- `not`
|
237
|
+
- `dependentRequired`, `dependentSchemas`, `If-Then-Else`
|
238
|
+
- `$ref`, `$defs` and `$id`
|
239
|
+
|
240
|
+
yet.
|
241
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export type metaData = {
|
2
|
+
types: Set<string>;
|
3
|
+
size: number;
|
4
|
+
properties: Set<string>;
|
5
|
+
};
|
6
|
+
export type resolvedResponse = {
|
7
|
+
metadata: metaData;
|
8
|
+
resolvedObject: any;
|
9
|
+
};
|
10
|
+
export declare const includesAll: (arr: Array<any>, values: Array<any>) => boolean;
|
11
|
+
export declare const resolvePayload: (path: Array<string | number>, obj: any) => resolvedResponse;
|
12
|
+
export declare const pathToString: (path: Array<string | number>) => string;
|
13
|
+
export declare const getMetaData: (value: any) => metaData;
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
export type CabidelaOptions = {
|
2
|
+
applyDefaults?: boolean;
|
3
|
+
errorMessages?: boolean;
|
4
|
+
fullErrors?: boolean;
|
5
|
+
};
|
6
|
+
export type SchemaNavigation = {
|
7
|
+
path: Array<string>;
|
8
|
+
schema: any;
|
9
|
+
payload: any;
|
10
|
+
evaluatedProperties?: Set<string>;
|
11
|
+
carryProperties?: boolean;
|
12
|
+
absorvErrors?: boolean;
|
13
|
+
errors?: Set<string>;
|
14
|
+
};
|
15
|
+
export declare class Cabidela {
|
16
|
+
schema: any;
|
17
|
+
options: CabidelaOptions;
|
18
|
+
constructor(schema: any, options?: CabidelaOptions);
|
19
|
+
setSchema(schema: any): void;
|
20
|
+
setOptions(options: CabidelaOptions): void;
|
21
|
+
throw(message: string, needle: SchemaNavigation): void;
|
22
|
+
parseAdditionalProperties(needle: SchemaNavigation, contextAdditionalProperties: any, contextEvaluatedProperties: Set<string>): number;
|
23
|
+
parseObject(needle: SchemaNavigation): boolean;
|
24
|
+
parseList(list: any, needle: SchemaNavigation, breakCondition?: Function): number;
|
25
|
+
parseSubSchema(needle: SchemaNavigation): number;
|
26
|
+
validate(payload: any): boolean;
|
27
|
+
}
|
package/dist/index.js
ADDED
@@ -0,0 +1,303 @@
|
|
1
|
+
// src/helpers.ts
|
2
|
+
var resolvePayload = (path, obj) => {
|
3
|
+
let resolvedObject = path.reduce(function(prev, curr) {
|
4
|
+
return prev ? prev[curr] : void 0;
|
5
|
+
}, obj);
|
6
|
+
return { metadata: getMetaData(resolvedObject), resolvedObject };
|
7
|
+
};
|
8
|
+
var pathToString = (path) => {
|
9
|
+
return path.length == 0 ? `.` : path.map((item) => typeof item === "number" ? `[${item}]` : `.${item}`).join("");
|
10
|
+
};
|
11
|
+
var getMetaData = (value) => {
|
12
|
+
let size = 0;
|
13
|
+
let types = /* @__PURE__ */ new Set([]);
|
14
|
+
let properties = /* @__PURE__ */ new Set([]);
|
15
|
+
if (value === null) {
|
16
|
+
types.add("null");
|
17
|
+
} else if (typeof value == "string") {
|
18
|
+
types.add("string");
|
19
|
+
size = value.length;
|
20
|
+
} else if (typeof value == "number") {
|
21
|
+
size = 1;
|
22
|
+
types.add("number");
|
23
|
+
if (Number.isInteger(value)) {
|
24
|
+
types.add("integer");
|
25
|
+
}
|
26
|
+
} else if (typeof value == "boolean") {
|
27
|
+
types.add("boolean");
|
28
|
+
size = 1;
|
29
|
+
} else if (Array.isArray(value)) {
|
30
|
+
size = value.length;
|
31
|
+
types.add("array");
|
32
|
+
if (value.find((item) => typeof item !== "number" && typeof item !== "string") == void 0) {
|
33
|
+
types.add("binary");
|
34
|
+
}
|
35
|
+
} else if (typeof value == "object") {
|
36
|
+
types.add("object");
|
37
|
+
size = Object.keys(value).length;
|
38
|
+
properties = new Set(Object.keys(value));
|
39
|
+
}
|
40
|
+
return { types, size, properties };
|
41
|
+
};
|
42
|
+
|
43
|
+
// src/index.ts
|
44
|
+
var Cabidela = class {
|
45
|
+
schema;
|
46
|
+
options;
|
47
|
+
constructor(schema, options) {
|
48
|
+
this.schema = schema;
|
49
|
+
this.options = { fullErrors: true, applyDefaults: false, errorMessages: false, ...options || {} };
|
50
|
+
}
|
51
|
+
setSchema(schema) {
|
52
|
+
this.schema = schema;
|
53
|
+
}
|
54
|
+
setOptions(options) {
|
55
|
+
this.options = options;
|
56
|
+
}
|
57
|
+
throw(message, needle) {
|
58
|
+
const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(", ")}` : ``}`;
|
59
|
+
throw new Error(this.options.errorMessages ? needle.schema.errorMessage ?? error : error);
|
60
|
+
}
|
61
|
+
parseAdditionalProperties(needle, contextAdditionalProperties, contextEvaluatedProperties) {
|
62
|
+
let matchCount = 0;
|
63
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
64
|
+
const unevaluatedProperties = metadata.properties.difference(contextEvaluatedProperties);
|
65
|
+
if (contextAdditionalProperties === false) {
|
66
|
+
if (unevaluatedProperties.size > 0) {
|
67
|
+
this.throw(
|
68
|
+
`Additional or unevaluated properties '${Array.from(unevaluatedProperties).join(", ")}' at '${pathToString(needle.path)}' not allowed`,
|
69
|
+
{
|
70
|
+
...needle,
|
71
|
+
schema: contextAdditionalProperties,
|
72
|
+
payload: resolvedObject
|
73
|
+
}
|
74
|
+
);
|
75
|
+
}
|
76
|
+
} else {
|
77
|
+
for (let property of unevaluatedProperties) {
|
78
|
+
if (this.parseSubSchema({
|
79
|
+
path: [property],
|
80
|
+
schema: contextAdditionalProperties,
|
81
|
+
payload: resolvedObject,
|
82
|
+
evaluatedProperties: /* @__PURE__ */ new Set(),
|
83
|
+
errors: /* @__PURE__ */ new Set()
|
84
|
+
})) {
|
85
|
+
matchCount++;
|
86
|
+
needle.evaluatedProperties.add(property);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
return matchCount;
|
91
|
+
}
|
92
|
+
// Iterates through the properties of an "object" schema
|
93
|
+
parseObject(needle) {
|
94
|
+
if (needle.schema.hasOwnProperty("minProperties")) {
|
95
|
+
if (Object.keys(needle.payload).length < needle.schema.minProperties) {
|
96
|
+
this.throw(
|
97
|
+
`minProperties at '${pathToString(needle.path)}' is ${needle.schema.minProperties}, got ${Object.keys(needle.payload).length}`,
|
98
|
+
needle
|
99
|
+
);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
if (needle.schema.hasOwnProperty("maxProperties")) {
|
103
|
+
if (Object.keys(needle.payload).length > needle.schema.maxProperties) {
|
104
|
+
this.throw(
|
105
|
+
`maxProperties at '${pathToString(needle.path)}' is ${needle.schema.minProperties}, got ${Object.keys(needle.payload).length}`,
|
106
|
+
needle
|
107
|
+
);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
const localEvaluatedProperties = /* @__PURE__ */ new Set([]);
|
111
|
+
let matchCount = 0;
|
112
|
+
if (needle.schema.hasOwnProperty("properties")) {
|
113
|
+
for (let property in needle.schema.properties) {
|
114
|
+
if (this.parseSubSchema({
|
115
|
+
...needle,
|
116
|
+
path: [...needle.path, property],
|
117
|
+
schema: needle.schema.properties[property]
|
118
|
+
})) {
|
119
|
+
localEvaluatedProperties.add(property);
|
120
|
+
matchCount++;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
if (needle.schema.hasOwnProperty("additionalProperties")) {
|
125
|
+
matchCount += this.parseAdditionalProperties(
|
126
|
+
needle,
|
127
|
+
needle.schema.additionalProperties,
|
128
|
+
localEvaluatedProperties
|
129
|
+
);
|
130
|
+
}
|
131
|
+
if (needle.schema.hasOwnProperty("unevaluatedProperties")) {
|
132
|
+
needle.evaluatedProperties = /* @__PURE__ */ new Set([...needle.evaluatedProperties, ...localEvaluatedProperties]);
|
133
|
+
matchCount += this.parseAdditionalProperties(
|
134
|
+
needle,
|
135
|
+
needle.schema.unevaluatedProperties,
|
136
|
+
needle.evaluatedProperties
|
137
|
+
);
|
138
|
+
}
|
139
|
+
if (needle.schema.hasOwnProperty("required")) {
|
140
|
+
if (new Set(needle.schema.required).difference(needle.evaluatedProperties.union(localEvaluatedProperties)).size > 0) {
|
141
|
+
this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
return matchCount ? true : false;
|
145
|
+
}
|
146
|
+
parseList(list, needle, breakCondition) {
|
147
|
+
let rounds = 0;
|
148
|
+
for (let option in list) {
|
149
|
+
try {
|
150
|
+
rounds += this.parseSubSchema({
|
151
|
+
...needle,
|
152
|
+
schema: { type: needle.schema.type, ...list[option] },
|
153
|
+
carryProperties: true,
|
154
|
+
absorvErrors: true
|
155
|
+
});
|
156
|
+
if (breakCondition && breakCondition(rounds)) break;
|
157
|
+
} catch (e) {
|
158
|
+
needle.errors.add(e.message);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
return rounds;
|
162
|
+
}
|
163
|
+
// Parses a JSON Schema sub-schema object - reentrant
|
164
|
+
parseSubSchema(needle) {
|
165
|
+
if (needle.schema == void 0) {
|
166
|
+
this.throw(`No schema for path '${pathToString(needle.path)}'`, needle);
|
167
|
+
}
|
168
|
+
if (needle.schema.hasOwnProperty("oneOf")) {
|
169
|
+
if (this.parseList(needle.schema.oneOf, needle) !== 1) {
|
170
|
+
if (needle.path.length == 0) {
|
171
|
+
this.throw(`oneOf at '${pathToString(needle.path)}' not met`, needle);
|
172
|
+
}
|
173
|
+
return 0;
|
174
|
+
}
|
175
|
+
return 1;
|
176
|
+
}
|
177
|
+
if (needle.schema.hasOwnProperty("anyOf")) {
|
178
|
+
if (this.parseList(needle.schema.anyOf, needle, (r) => r !== 0) === 0) {
|
179
|
+
if (needle.path.length == 0) {
|
180
|
+
this.throw(`anyOf at '${pathToString(needle.path)}' not met`, needle);
|
181
|
+
}
|
182
|
+
return 0;
|
183
|
+
}
|
184
|
+
return 1;
|
185
|
+
}
|
186
|
+
if (needle.schema.hasOwnProperty("allOf")) {
|
187
|
+
const conditions = needle.schema.allOf.reduce((r, c) => Object.assign(r, c), {});
|
188
|
+
try {
|
189
|
+
this.parseSubSchema({
|
190
|
+
...needle,
|
191
|
+
schema: { type: needle.schema.type, ...conditions },
|
192
|
+
carryProperties: true
|
193
|
+
});
|
194
|
+
} catch (e) {
|
195
|
+
if (needle.path.length == 0) {
|
196
|
+
throw e;
|
197
|
+
}
|
198
|
+
needle.errors.add(e.message);
|
199
|
+
return 0;
|
200
|
+
}
|
201
|
+
}
|
202
|
+
const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);
|
203
|
+
if (needle.schema.type === "array" && !metadata.types.has("binary") && !metadata.types.has("string")) {
|
204
|
+
let matched = 0;
|
205
|
+
for (let item in resolvedObject) {
|
206
|
+
matched += this.parseSubSchema({
|
207
|
+
...needle,
|
208
|
+
path: [...needle.path, item],
|
209
|
+
schema: needle.schema.items
|
210
|
+
});
|
211
|
+
}
|
212
|
+
return matched;
|
213
|
+
} else if (needle.schema.type === "object" || needle.schema.properties) {
|
214
|
+
return this.parseObject(needle) ? 1 : 0;
|
215
|
+
} else if (resolvedObject !== void 0) {
|
216
|
+
if (needle.schema.hasOwnProperty("enum")) {
|
217
|
+
if (Array.isArray(needle.schema.enum)) {
|
218
|
+
if (!needle.schema.enum.includes(resolvedObject)) {
|
219
|
+
this.throw(
|
220
|
+
`enum ${resolvedObject} not in ${needle.schema.enum.join(",")} at '${pathToString(needle.path)}'`,
|
221
|
+
needle
|
222
|
+
);
|
223
|
+
} else {
|
224
|
+
if (needle.schema.type == void 0) return 1;
|
225
|
+
}
|
226
|
+
} else {
|
227
|
+
this.throw(`enum should be an array at '${pathToString(needle.path)}'`, needle);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
if (needle.schema.hasOwnProperty("type") && !metadata.types.has(needle.schema.type)) {
|
231
|
+
this.throw(
|
232
|
+
`Type mismatch of '${pathToString(needle.path)}', '${needle.schema.type}' not in ${JSON.stringify(Array.from(metadata.types))}`,
|
233
|
+
needle
|
234
|
+
);
|
235
|
+
}
|
236
|
+
if (needle.schema !== true) {
|
237
|
+
switch (needle.schema.type) {
|
238
|
+
case "string":
|
239
|
+
if (needle.schema.hasOwnProperty("maxLength") && metadata.size > needle.schema.maxLength) {
|
240
|
+
this.throw(`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`, needle);
|
241
|
+
}
|
242
|
+
if (needle.schema.hasOwnProperty("minLength") && metadata.size < needle.schema.minLength) {
|
243
|
+
this.throw(
|
244
|
+
`Length of '${pathToString(needle.path)}' must be >= ${needle.schema.minLength} not met`,
|
245
|
+
needle
|
246
|
+
);
|
247
|
+
}
|
248
|
+
break;
|
249
|
+
case "number":
|
250
|
+
case "integer":
|
251
|
+
if (needle.schema.hasOwnProperty("minimum") && resolvedObject < needle.schema.minimum) {
|
252
|
+
this.throw(`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`, needle);
|
253
|
+
}
|
254
|
+
if (needle.schema.hasOwnProperty("exclusiveMinimum") && resolvedObject <= needle.schema.exclusiveMinimum) {
|
255
|
+
this.throw(`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`, needle);
|
256
|
+
}
|
257
|
+
if (needle.schema.hasOwnProperty("maximum") && resolvedObject > needle.schema.maximum) {
|
258
|
+
this.throw(`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`, needle);
|
259
|
+
}
|
260
|
+
if (needle.schema.hasOwnProperty("exclusiveMaximum") && resolvedObject >= needle.schema.exclusiveMaximum) {
|
261
|
+
this.throw(`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`, needle);
|
262
|
+
}
|
263
|
+
if (needle.schema.hasOwnProperty("multipleOf") && resolvedObject % needle.schema.multipleOf !== 0) {
|
264
|
+
this.throw(`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`, needle);
|
265
|
+
}
|
266
|
+
break;
|
267
|
+
}
|
268
|
+
}
|
269
|
+
if (needle.carryProperties) {
|
270
|
+
needle.evaluatedProperties.add(needle.path[needle.path.length - 1]);
|
271
|
+
}
|
272
|
+
return 1;
|
273
|
+
}
|
274
|
+
if (this.options.applyDefaults === true && needle.schema.hasOwnProperty("default")) {
|
275
|
+
needle.path.reduce(function(prev, curr, index) {
|
276
|
+
if (prev[curr] === void 0) {
|
277
|
+
prev[curr] = {};
|
278
|
+
}
|
279
|
+
if (index == needle.path.length - 1) {
|
280
|
+
prev[curr] = needle.schema.default;
|
281
|
+
needle.evaluatedProperties.add(needle.path[needle.path.length - 1]);
|
282
|
+
}
|
283
|
+
return prev ? prev[curr] : void 0;
|
284
|
+
}, needle.payload);
|
285
|
+
}
|
286
|
+
return 0;
|
287
|
+
}
|
288
|
+
validate(payload) {
|
289
|
+
const needle = {
|
290
|
+
errors: /* @__PURE__ */ new Set(),
|
291
|
+
evaluatedProperties: /* @__PURE__ */ new Set(),
|
292
|
+
path: [],
|
293
|
+
schema: this.schema,
|
294
|
+
payload
|
295
|
+
};
|
296
|
+
this.parseSubSchema(needle);
|
297
|
+
return true;
|
298
|
+
}
|
299
|
+
};
|
300
|
+
export {
|
301
|
+
Cabidela
|
302
|
+
};
|
303
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../src/helpers.ts", "../src/index.ts"],
|
4
|
+
"sourcesContent": ["export type metaData = {\n types: Set<string>;\n size: number;\n properties: Set<string>;\n};\n\nexport type resolvedResponse = {\n metadata: metaData;\n resolvedObject: any;\n};\n\nexport const includesAll = (arr: Array<any>, values: Array<any>) => {\n return values.every((v) => arr.includes(v));\n};\n\n/* Resolves a path in an object\n\n obj = {\n prompt: \"hello\",\n messages: [\n { role: \"system\", content: \"you are a helpful assistant\" },\n { role: \"user\", content: \"tell me a joke\" },\n ]\n }\n\n path = [\"messages\"]\n returns [\n { role: \"system\", content: \"you are a helpful assistant\" },\n { role: \"user\", content: \"tell me a joke\" },\n ]\n\n path = [\"messages\", 1, \"role\"]\n returns \"system\"\n\n path = [\"prompt\"]\n returns \"hello\"\n\n path = [\"invalid\", \"path\"]\n returns undefined\n\n */\n\nexport const resolvePayload = (path: Array<string | number>, obj: any): resolvedResponse => {\n let resolvedObject = path.reduce(function (prev, curr) {\n return prev ? prev[curr] : undefined;\n }, obj);\n\n return { metadata: getMetaData(resolvedObject), resolvedObject };\n};\n\nexport const pathToString = (path: Array<string | number>) => {\n return path.length == 0 ? `.` : path.map((item) => (typeof item === \"number\" ? `[${item}]` : `.${item}`)).join(\"\");\n};\n\n// https://json-schema.org/understanding-json-schema/reference/type\n\nexport const getMetaData = (value: any): metaData => {\n let size = 0;\n let types = new Set([]);\n let properties = new Set([]);\n if (value === null) {\n types.add(\"null\");\n } else if (typeof value == \"string\") {\n types.add(\"string\");\n size = value.length;\n } else if (typeof value == \"number\") {\n size = 1;\n types.add(\"number\");\n if (Number.isInteger(value)) {\n types.add(\"integer\");\n }\n } else if (typeof value == \"boolean\") {\n types.add(\"boolean\");\n size = 1;\n } else if (Array.isArray(value)) {\n size = value.length;\n types.add(\"array\");\n if (value.find((item) => typeof item !== \"number\" && typeof item !== \"string\") == undefined) {\n types.add(\"binary\");\n }\n } else if (typeof value == \"object\") {\n types.add(\"object\");\n size = Object.keys(value).length;\n properties = new Set(Object.keys(value));\n }\n return { types, size, properties };\n};\n", "import { resolvePayload, pathToString } from \"./helpers\";\n\nexport type CabidelaOptions = {\n applyDefaults?: boolean;\n errorMessages?: boolean;\n fullErrors?: boolean;\n};\n\nexport type SchemaNavigation = {\n path: Array<string>;\n schema: any;\n payload: any;\n evaluatedProperties?: Set<string>;\n carryProperties?: boolean;\n absorvErrors?: boolean;\n errors?: Set<string>;\n};\n\nexport class Cabidela {\n public schema: any;\n public options: CabidelaOptions;\n\n constructor(schema: any, options?: CabidelaOptions) {\n this.schema = schema;\n this.options = { fullErrors: true, applyDefaults: false, errorMessages: false, ...(options || {}) };\n }\n\n setSchema(schema: any) {\n this.schema = schema;\n }\n\n setOptions(options: CabidelaOptions) {\n this.options = options;\n }\n\n throw(message: string, needle: SchemaNavigation) {\n const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(\", \")}` : ``}`;\n throw new Error(this.options.errorMessages ? (needle.schema.errorMessage ?? error) : error);\n }\n\n parseAdditionalProperties(\n needle: SchemaNavigation,\n contextAdditionalProperties: any,\n contextEvaluatedProperties: Set<string>,\n ): number {\n let matchCount = 0;\n const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);\n\n const unevaluatedProperties = metadata.properties.difference(contextEvaluatedProperties);\n\n // Setting the additionalProperties schema to false means no additional properties will be allowed.\n if (contextAdditionalProperties === false) {\n if (unevaluatedProperties.size > 0) {\n this.throw(\n `Additional or unevaluated properties '${Array.from(unevaluatedProperties).join(\", \")}' at '${pathToString(needle.path)}' not allowed`,\n {\n ...needle,\n schema: contextAdditionalProperties,\n payload: resolvedObject,\n },\n );\n }\n } else {\n for (let property of unevaluatedProperties) {\n if (\n this.parseSubSchema({\n path: [property],\n schema: contextAdditionalProperties,\n payload: resolvedObject,\n evaluatedProperties: new Set(),\n errors: new Set(),\n })\n ) {\n matchCount++;\n needle.evaluatedProperties.add(property);\n }\n }\n }\n return matchCount;\n }\n\n // Iterates through the properties of an \"object\" schema\n parseObject(needle: SchemaNavigation): boolean {\n if (needle.schema.hasOwnProperty(\"minProperties\")) {\n if (Object.keys(needle.payload).length < needle.schema.minProperties) {\n this.throw(\n `minProperties at '${pathToString(needle.path)}' is ${needle.schema.minProperties}, got ${Object.keys(needle.payload).length}`,\n needle,\n );\n }\n }\n\n if (needle.schema.hasOwnProperty(\"maxProperties\")) {\n if (Object.keys(needle.payload).length > needle.schema.maxProperties) {\n this.throw(\n `maxProperties at '${pathToString(needle.path)}' is ${needle.schema.minProperties}, got ${Object.keys(needle.payload).length}`,\n needle,\n );\n }\n }\n\n const localEvaluatedProperties = new Set([]);\n let matchCount: number = 0;\n\n if (needle.schema.hasOwnProperty(\"properties\")) {\n for (let property in needle.schema.properties) {\n if (\n this.parseSubSchema({\n ...needle,\n path: [...needle.path, property],\n schema: needle.schema.properties[property],\n })\n ) {\n localEvaluatedProperties.add(property);\n matchCount++;\n }\n }\n }\n\n // additionalProperties only recognizes properties declared in the same subschema as itself.\n if (needle.schema.hasOwnProperty(\"additionalProperties\")) {\n matchCount += this.parseAdditionalProperties(\n needle,\n needle.schema.additionalProperties,\n localEvaluatedProperties,\n );\n }\n\n // unevaluatedProperties keyword is similar to additionalProperties except that it can recognize properties declared in subschemas.\n if (needle.schema.hasOwnProperty(\"unevaluatedProperties\")) {\n needle.evaluatedProperties = new Set([...needle.evaluatedProperties, ...localEvaluatedProperties]);\n matchCount += this.parseAdditionalProperties(\n needle,\n needle.schema.unevaluatedProperties,\n needle.evaluatedProperties,\n );\n }\n\n // this has to be last\n if (needle.schema.hasOwnProperty(\"required\")) {\n if (\n new Set(needle.schema.required).difference(needle.evaluatedProperties.union(localEvaluatedProperties)).size > 0\n ) {\n this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);\n }\n }\n return matchCount ? true : false;\n }\n\n parseList(list: any, needle: SchemaNavigation, breakCondition?: Function) {\n let rounds = 0;\n for (let option in list) {\n try {\n rounds += this.parseSubSchema({\n ...needle,\n schema: { type: needle.schema.type, ...list[option] },\n carryProperties: true,\n absorvErrors: true,\n });\n if (breakCondition && breakCondition(rounds)) break;\n } catch (e) {\n needle.errors.add(e.message);\n }\n }\n return rounds;\n }\n\n // Parses a JSON Schema sub-schema object - reentrant\n parseSubSchema(needle: SchemaNavigation) {\n if (needle.schema == undefined) {\n this.throw(`No schema for path '${pathToString(needle.path)}'`, needle);\n }\n\n // To validate against oneOf, the given data must be valid against exactly one of the given subschemas.\n if (needle.schema.hasOwnProperty(\"oneOf\")) {\n if (this.parseList(needle.schema.oneOf, needle) !== 1) {\n if (needle.path.length == 0) {\n this.throw(`oneOf at '${pathToString(needle.path)}' not met`, needle);\n }\n return 0;\n }\n return 1;\n }\n\n // To validate against anyOf, the given data must be valid against any (one or more) of the given subschemas.\n if (needle.schema.hasOwnProperty(\"anyOf\")) {\n if (this.parseList(needle.schema.anyOf, needle, (r: number) => r !== 0) === 0) {\n if (needle.path.length == 0) {\n this.throw(`anyOf at '${pathToString(needle.path)}' not met`, needle);\n }\n return 0;\n }\n return 1;\n }\n\n // To validate against allOf, the given data must be valid against all of the given subschemas.\n if (needle.schema.hasOwnProperty(\"allOf\")) {\n const conditions = needle.schema.allOf.reduce((r: any, c: any) => Object.assign(r, c), {});\n try {\n this.parseSubSchema({\n ...needle,\n schema: { type: needle.schema.type, ...conditions },\n carryProperties: true,\n });\n } catch (e) {\n if (needle.path.length == 0) {\n throw e;\n }\n needle.errors.add(e.message);\n return 0;\n }\n }\n\n const { metadata, resolvedObject } = resolvePayload(needle.path, needle.payload);\n\n // array, but object is not binary\n if (needle.schema.type === \"array\" && !metadata.types.has(\"binary\") && !metadata.types.has(\"string\")) {\n let matched = 0;\n for (let item in resolvedObject) {\n matched += this.parseSubSchema({\n ...needle,\n path: [...needle.path, item],\n schema: needle.schema.items,\n });\n }\n return matched;\n } else if (needle.schema.type === \"object\" || needle.schema.properties) {\n return this.parseObject(needle) ? 1 : 0;\n } else if (resolvedObject !== undefined) {\n // This has to be before type checking\n if (needle.schema.hasOwnProperty(\"enum\")) {\n if (Array.isArray(needle.schema.enum)) {\n if (!needle.schema.enum.includes(resolvedObject)) {\n this.throw(\n `enum ${resolvedObject} not in ${needle.schema.enum.join(\",\")} at '${pathToString(needle.path)}'`,\n needle,\n );\n } else {\n // You can use enum even without a type, to accept values of different types.\n // If that's the case, then skip type checking below\n if (needle.schema.type == undefined) return 1;\n }\n } else {\n this.throw(`enum should be an array at '${pathToString(needle.path)}'`, needle);\n }\n }\n // This has to be after handling enum\n if (needle.schema.hasOwnProperty(\"type\") && !metadata.types.has(needle.schema.type)) {\n this.throw(\n `Type mismatch of '${pathToString(needle.path)}', '${needle.schema.type}' not in ${JSON.stringify(Array.from(metadata.types))}`,\n needle,\n );\n }\n /* If property === true, then it's declared validated no matter what the value is */\n if (needle.schema !== true) {\n /* Otherwise check schema type */\n switch (needle.schema.type) {\n case \"string\":\n if (needle.schema.hasOwnProperty(\"maxLength\") && metadata.size > needle.schema.maxLength) {\n this.throw(`Length of '${pathToString(needle.path)}' must be <= ${needle.schema.maxLength}`, needle);\n }\n if (needle.schema.hasOwnProperty(\"minLength\") && metadata.size < needle.schema.minLength) {\n this.throw(\n `Length of '${pathToString(needle.path)}' must be >= ${needle.schema.minLength} not met`,\n needle,\n );\n }\n break;\n case \"number\":\n case \"integer\":\n if (needle.schema.hasOwnProperty(\"minimum\") && resolvedObject < needle.schema.minimum) {\n this.throw(`'${pathToString(needle.path)}' must be >= ${needle.schema.minimum}`, needle);\n }\n if (needle.schema.hasOwnProperty(\"exclusiveMinimum\") && resolvedObject <= needle.schema.exclusiveMinimum) {\n this.throw(`'${pathToString(needle.path)}' must be > ${needle.schema.exclusiveMinimum}`, needle);\n }\n if (needle.schema.hasOwnProperty(\"maximum\") && resolvedObject > needle.schema.maximum) {\n this.throw(`'${pathToString(needle.path)}' must be <= ${needle.schema.maximum}`, needle);\n }\n if (needle.schema.hasOwnProperty(\"exclusiveMaximum\") && resolvedObject >= needle.schema.exclusiveMaximum) {\n this.throw(`'${pathToString(needle.path)}' must be < ${needle.schema.exclusiveMaximum}`, needle);\n }\n if (needle.schema.hasOwnProperty(\"multipleOf\") && resolvedObject % needle.schema.multipleOf !== 0) {\n this.throw(`'${pathToString(needle.path)}' must be multiple of ${needle.schema.multipleOf}`, needle);\n }\n break;\n }\n }\n if (needle.carryProperties) {\n needle.evaluatedProperties.add(needle.path[needle.path.length - 1]);\n }\n return 1;\n }\n // Apply defaults\n if (this.options.applyDefaults === true && needle.schema.hasOwnProperty(\"default\")) {\n needle.path.reduce(function (prev, curr, index) {\n // create objects as needed along the path, if they don't exist, so we can apply defaults at the end\n if (prev[curr] === undefined) {\n prev[curr] = {};\n }\n if (index == needle.path.length - 1) {\n prev[curr] = needle.schema.default;\n // defaults add to evaluatedProperties and can meet \"required\" constraints\n needle.evaluatedProperties.add(needle.path[needle.path.length - 1]);\n }\n return prev ? prev[curr] : undefined;\n }, needle.payload);\n }\n return 0;\n }\n\n validate(payload: any) {\n const needle: SchemaNavigation = {\n errors: new Set(),\n evaluatedProperties: new Set(),\n path: [],\n schema: this.schema,\n payload,\n };\n this.parseSubSchema(needle);\n return true;\n }\n}\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": []
|
7
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
{
|
2
|
+
"name": "@cloudflare/cabidela",
|
3
|
+
"version": "0.0.15",
|
4
|
+
"type": "module",
|
5
|
+
"description": "Cabidela is a small, fast, eval-less, Cloudflare Workers compatible, dynamic JSON Schema validator",
|
6
|
+
"main": "dist/index.js",
|
7
|
+
"types": "dist/index.d.ts",
|
8
|
+
"author": "Celso Martinho <celso@cloudflare.com>",
|
9
|
+
"license": "Apache 2.0",
|
10
|
+
"scripts": {
|
11
|
+
"test": "npm run test-cabidela",
|
12
|
+
"test-all": "npm run test-cabidela && npm run test-ajv",
|
13
|
+
"test-cabidela": "vitest run --dir tests --reporter=verbose",
|
14
|
+
"test-ajv": "AJV=true vitest run --dir tests --reporter=verbose",
|
15
|
+
"benchmark": "vitest bench --dir benchmarks --reporter=verbose --watch false",
|
16
|
+
"build": "npm run build-tsc && npm run build-esbuild",
|
17
|
+
"build-esbuild": "esbuild src/index.ts --bundle --outfile=dist/index.js --sourcemap --format=esm",
|
18
|
+
"build-tsc": "tsc --declaration --emitDeclarationOnly --outDir ./dist --target esnext src/index.ts",
|
19
|
+
"dry-publish": "npm pack --dry-run"
|
20
|
+
},
|
21
|
+
"keywords": [
|
22
|
+
"json-schema"
|
23
|
+
],
|
24
|
+
"files": [
|
25
|
+
"dist/*"
|
26
|
+
],
|
27
|
+
"devDependencies": {
|
28
|
+
"@vitest/ui": "^3.0.3",
|
29
|
+
"ajv": "^8.17.1",
|
30
|
+
"ajv-errors": "^3.0.0",
|
31
|
+
"esbuild": "^0.24.2",
|
32
|
+
"typescript": "^5.7.3",
|
33
|
+
"vitest": "^3.0.3"
|
34
|
+
}
|
35
|
+
}
|