@cloudflare/cabidela 0.0.19 → 0.2.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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.1.2] - 2025-03-07
6
+
7
+ ### Added
8
+
9
+ - $merge support - see README for more information
10
+
11
+ ## [0.1.1] - 2025-02-26
12
+
13
+ ### Added
14
+
15
+ - Added support for $id, $ref and $defs - https://json-schema.org/understanding-json-schema/structuring
16
+ - Added support for not - https://json-schema.org/understanding-json-schema/reference/combining#not
17
+
5
18
  ## [0.0.19] - 2025-02-26
6
19
 
7
20
  ### Added
package/README.md CHANGED
@@ -71,6 +71,8 @@ Cabidela takes a JSON-Schema and optional configuration flags:
71
71
  - `applyDefaults`: boolean - If true, the validator will apply default values to the input object. Default is false.
72
72
  - `errorMessages`: boolean - If true, the validator will use custom `errorMessage` messages from the schema. Default is false.
73
73
  - `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.
74
+ - `useMerge`: boolean - Set to true if you want to use the `$merge` keyword. Default is false. See below for more information.
75
+ - `subSchema`: any[] - An optional array of sub-schemas that can be used with `$id` and `$ref`. See below for more information.
74
76
 
75
77
  Returns a validation object.
76
78
 
@@ -180,9 +182,121 @@ example, using this schema:
180
182
  - The payload `{ moon: 10}` will be modified to `{ sun: 9000, moon: 10 }`.
181
183
  - The payload `{ saturn: 10}` will throw an error because no condition is met.
182
184
 
185
+ ### $id, $ref, $defs
186
+
187
+ The keywords [$id](https://json-schema.org/understanding-json-schema/structuring#id), [$ref](https://json-schema.org/understanding-json-schema/structuring#dollarref) and [$defs](https://json-schema.org/understanding-json-schema/structuring#defs) can be used to build and maintain complex schemas where the reusable parts are defined in separate schemas.
188
+
189
+ The following is the main schema and a `customer` sub-schema that defines the `contacts` and `address` properties.
190
+
191
+ ```js
192
+ import { Cabidela } from "@cloudflare/cabidela";
193
+
194
+ const schema = {
195
+ $id: "http://example.com/schemas/main",
196
+ type: "object",
197
+ properties: {
198
+ name: { type: "string" },
199
+ contacts: { $ref: "customer#/contacts" },
200
+ address: { $ref: "customer#/address" },
201
+ balance: { $ref: "$defs#/balance" },
202
+ },
203
+ required: ["name", "contacts", "address"],
204
+ "$defs": {
205
+ "balance": {
206
+ type: "object",
207
+ prope properties: {
208
+ currency: { type: "string" },
209
+ amount: { type: "number" },
210
+ },
211
+ }
212
+ }
213
+ };
214
+
215
+ const contactSchema = {
216
+ $id: "http://example.com/schemas/customer",
217
+ contacts: {
218
+ type: "object",
219
+ properties: {
220
+ email: { type: "string" },
221
+ phone: { type: "string" },
222
+ },
223
+ required: ["email", "phone"],
224
+ },
225
+ address: {
226
+ type: "object",
227
+ properties: {
228
+ street: { type: "string" },
229
+ city: { type: "string" },
230
+ zip: { type: "string" },
231
+ country: { type: "string" },
232
+ },
233
+ required: ["street", "city", "zip", "country"],
234
+ },
235
+ };
236
+
237
+ const cabidela = new Cabidela(schema, { subSchemas: [contactSchema] });
238
+
239
+ cabidela.validate({
240
+ name: "John",
241
+ contacts: {
242
+ email: "john@example.com",
243
+ phone: "+123456789",
244
+ },
245
+ address: {
246
+ street: "123 Main St",
247
+ city: "San Francisco",
248
+ zip: "94105",
249
+ country: "USA",
250
+ },
251
+ });
252
+ ```
253
+
254
+ ## Combined schemas and $merge
255
+
256
+ The standard way of combining and extending schemas is by using the [`allOf`](https://json-schema.org/understanding-json-schema/reference/combining#allOf) (AND), [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) (OR), [`oneOf`](https://json-schema.org/understanding-json-schema/reference/combining#oneOf) (XOR) and [`not`](https://json-schema.org/understanding-json-schema/reference/combining#not) keywords, all supported by this library.
257
+
258
+ Cabidela supports an additional keyword `$merge` (inspired by [Ajv](https://ajv.js.org/guide/combining-schemas.html#merge-and-patch-keywords)) that allows you to merge two objects. This is useful when you want to extend a schema with additional properties and `allOf`` is not enough.
259
+
260
+ Here's how it works:
261
+
262
+ ```json
263
+ {
264
+ "$merge": {
265
+ "source": {
266
+ "type": "object",
267
+ "properties": { "p": { "type": "string" } },
268
+ "additionalProperties": false
269
+ },
270
+ "with": {
271
+ "properties": { "q": { "type": "number" } }
272
+ }
273
+ }
274
+ }
275
+ ```
276
+
277
+ Resolves to:
278
+
279
+ ```json
280
+ {
281
+ "type": "object",
282
+ "properties": {
283
+ "q": {
284
+ "type": "number"
285
+ }
286
+ },
287
+ "additionalProperties": false
288
+ }
289
+ ```
290
+
291
+ To use `$merge` set the `useMerge` flag to true when creating the instance.
292
+
293
+ ```js
294
+ new Cabidela(schema, { useMerge: true });
295
+ ```
296
+
183
297
  ## Custom errors
184
298
 
185
- 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.
299
+ 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.
186
300
 
187
301
  ```js
188
302
  const schema = {
@@ -204,7 +318,7 @@ const payload = {
204
318
 
205
319
  cabidela.validate(payload);
206
320
  // throws "Error: prompt required"
207
- ````
321
+ ```
208
322
 
209
323
  ## Tests
210
324
 
@@ -262,7 +376,7 @@ Here are some results:
262
376
  59.75x faster than Ajv
263
377
 
264
378
  Cabidela - benchmarks/80-big-ops.bench.js > allOf, two properties
265
- 1701.95x faster than Ajv
379
+ 1701.95x faster than Ajv
266
380
 
267
381
  Cabidela - benchmarks/80-big-ops.bench.js > allOf, two objects
268
382
  1307.04x faster than Ajv
@@ -285,10 +399,7 @@ npm run benchmark
285
399
  Cabidela supports most of JSON Schema specification, and should be useful for many applications, but it's not complete. **Currently** we do not support:
286
400
 
287
401
  - Multiple (array of) types `{ "type": ["number", "string"] }`
288
- - Regular expressions
289
402
  - Pattern properties
290
- - `not`
291
403
  - `dependentRequired`, `dependentSchemas`, `If-Then-Else`
292
- - `$ref`, `$defs` and `$id`
293
404
 
294
405
  yet.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,9 @@
1
1
  type CabidelaOptions = {
2
2
  applyDefaults?: boolean;
3
+ useMerge?: boolean;
3
4
  errorMessages?: boolean;
4
5
  fullErrors?: boolean;
6
+ subSchemas?: Array<any>;
5
7
  };
6
8
  type SchemaNavigation = {
7
9
  path: Array<string>;
@@ -15,10 +17,13 @@ type SchemaNavigation = {
15
17
  defaultsCallbacks: Array<any>;
16
18
  };
17
19
  declare class Cabidela {
18
- schema: any;
19
- options: CabidelaOptions;
20
+ private schema;
21
+ private options;
22
+ private definitions;
20
23
  constructor(schema: any, options?: CabidelaOptions);
21
24
  setSchema(schema: any): void;
25
+ addSchema(subSchema: any, combine?: boolean): void;
26
+ getSchema(): any;
22
27
  setOptions(options: CabidelaOptions): void;
23
28
  throw(message: string, needle: SchemaNavigation): void;
24
29
  parseAdditionalProperties(needle: SchemaNavigation, contextAdditionalProperties: any, contextEvaluatedProperties: Set<string>): number;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  type CabidelaOptions = {
2
2
  applyDefaults?: boolean;
3
+ useMerge?: boolean;
3
4
  errorMessages?: boolean;
4
5
  fullErrors?: boolean;
6
+ subSchemas?: Array<any>;
5
7
  };
6
8
  type SchemaNavigation = {
7
9
  path: Array<string>;
@@ -15,10 +17,13 @@ type SchemaNavigation = {
15
17
  defaultsCallbacks: Array<any>;
16
18
  };
17
19
  declare class Cabidela {
18
- schema: any;
19
- options: CabidelaOptions;
20
+ private schema;
21
+ private options;
22
+ private definitions;
20
23
  constructor(schema: any, options?: CabidelaOptions);
21
24
  setSchema(schema: any): void;
25
+ addSchema(subSchema: any, combine?: boolean): void;
26
+ getSchema(): any;
22
27
  setOptions(options: CabidelaOptions): void;
23
28
  throw(message: string, needle: SchemaNavigation): void;
24
29
  parseAdditionalProperties(needle: SchemaNavigation, contextAdditionalProperties: any, contextEvaluatedProperties: Set<string>): number;
package/dist/index.js CHANGED
@@ -25,6 +25,52 @@ __export(index_exports, {
25
25
  module.exports = __toCommonJS(index_exports);
26
26
 
27
27
  // src/helpers.ts
28
+ var parse$ref = (ref) => {
29
+ const parts = ref.split("#");
30
+ const $id = parts[0];
31
+ const $path = parts[1].split("/").filter((part) => part !== "");
32
+ return { $id, $path };
33
+ };
34
+ function deepMerge(target, source) {
35
+ const result = Array.isArray(target) && Array.isArray(source) ? target.concat(source) : { ...target, ...source };
36
+ for (const key of Object.keys(result)) {
37
+ result[key] = typeof target[key] == "object" && typeof source[key] == "object" ? deepMerge(target[key], source[key]) : structuredClone(result[key]);
38
+ }
39
+ return result;
40
+ }
41
+ var traverseSchema = (options, definitions, obj, cb) => {
42
+ let hits;
43
+ do {
44
+ hits = 0;
45
+ Object.keys(obj).forEach((key) => {
46
+ if (obj[key] !== null && typeof obj[key] === "object") {
47
+ traverseSchema(options, definitions, obj[key], (value) => {
48
+ hits++;
49
+ obj[key] = value;
50
+ });
51
+ if (options.useMerge && key === "$merge") {
52
+ const merge = deepMerge(obj[key].source, obj[key].with);
53
+ if (cb) {
54
+ cb(merge);
55
+ } else {
56
+ Object.assign(obj, merge);
57
+ delete obj[key];
58
+ }
59
+ }
60
+ } else {
61
+ if (key === "$ref") {
62
+ const { $id, $path } = parse$ref(obj[key]);
63
+ const { resolvedObject } = resolvePayload($path, definitions[$id]);
64
+ if (resolvedObject) {
65
+ cb(resolvedObject);
66
+ } else {
67
+ throw new Error(`Could not resolve '${obj[key]}' $ref`);
68
+ }
69
+ }
70
+ }
71
+ });
72
+ } while (hits > 0);
73
+ };
28
74
  var resolvePayload = (path, obj) => {
29
75
  let resolvedObject = path.reduce(function(prev, curr) {
30
76
  return prev ? prev[curr] : void 0;
@@ -32,7 +78,7 @@ var resolvePayload = (path, obj) => {
32
78
  return { metadata: getMetaData(resolvedObject), resolvedObject };
33
79
  };
34
80
  var pathToString = (path) => {
35
- return path.length == 0 ? `.` : path.map((item) => typeof item === "number" ? `[${item}]` : `.${item}`).join("");
81
+ return path.length == 0 ? `/` : path.map((item) => `/${item}`).join("");
36
82
  };
37
83
  var getMetaData = (value) => {
38
84
  let size = 0;
@@ -70,20 +116,52 @@ var getMetaData = (value) => {
70
116
  var Cabidela = class {
71
117
  schema;
72
118
  options;
119
+ definitions = {};
73
120
  constructor(schema, options) {
74
121
  this.schema = schema;
75
122
  this.options = {
76
123
  fullErrors: true,
124
+ subSchemas: [],
77
125
  applyDefaults: false,
78
126
  errorMessages: false,
79
127
  ...options || {}
80
128
  };
129
+ if (this.schema.hasOwnProperty("$defs")) {
130
+ this.definitions["$defs"] = this.schema["$defs"];
131
+ delete this.schema["$defs"];
132
+ }
133
+ if (this.options.subSchemas.length > 0) {
134
+ for (const subSchema of this.options.subSchemas) {
135
+ this.addSchema(subSchema, false);
136
+ }
137
+ }
138
+ if (this.options.useMerge || this.options.subSchemas.length > 0) {
139
+ traverseSchema(this.options, this.definitions, this.schema);
140
+ }
81
141
  }
82
142
  setSchema(schema) {
83
143
  this.schema = schema;
84
144
  }
145
+ addSchema(subSchema, combine = true) {
146
+ if (subSchema.hasOwnProperty("$id")) {
147
+ const url = URL.parse(subSchema["$id"]);
148
+ if (url) {
149
+ this.definitions[url.pathname.split("/").slice(-1)[0]] = subSchema;
150
+ } else {
151
+ throw new Error(
152
+ "subSchemas need a valid retrieval URI $id https://json-schema.org/understanding-json-schema/structuring#retrieval-uri"
153
+ );
154
+ }
155
+ } else {
156
+ throw new Error("subSchemas need $id https://json-schema.org/understanding-json-schema/structuring#id");
157
+ }
158
+ if (combine == true) traverseSchema(this.options, this.definitions, this.schema);
159
+ }
160
+ getSchema() {
161
+ return this.schema;
162
+ }
85
163
  setOptions(options) {
86
- this.options = options;
164
+ this.options = { ...this.options, ...options };
87
165
  }
88
166
  throw(message, needle) {
89
167
  const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(", ")}` : ``}`;
@@ -109,7 +187,7 @@ var Cabidela = class {
109
187
  } else {
110
188
  for (let property of unevaluatedProperties) {
111
189
  if (this.parseSubSchema({
112
- path: [property.split(".").slice(-1)[0]],
190
+ path: [property.split("/").slice(-1)[0]],
113
191
  schema: contextAdditionalProperties,
114
192
  payload: resolvedObject,
115
193
  evaluatedProperties: /* @__PURE__ */ new Set(),
@@ -175,7 +253,7 @@ var Cabidela = class {
175
253
  if (new Set(needle.schema.required.map((r) => pathToString([...needle.path, r]))).difference(
176
254
  needle.evaluatedProperties.union(localEvaluatedProperties)
177
255
  ).size > 0) {
178
- this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);
256
+ this.throw(`required properties at '${pathToString(needle.path)}' are '${needle.schema.required}'`, needle);
179
257
  }
180
258
  }
181
259
  return matchCount ? true : false;
@@ -210,6 +288,20 @@ var Cabidela = class {
210
288
  if (needle.schema == void 0) {
211
289
  this.throw(`No schema for path '${pathToString(needle.path)}'`, needle);
212
290
  }
291
+ if (needle.schema.hasOwnProperty("not")) {
292
+ let pass = false;
293
+ try {
294
+ this.parseSubSchema({
295
+ ...needle,
296
+ schema: needle.schema.not
297
+ });
298
+ } catch (e) {
299
+ pass = true;
300
+ }
301
+ if (pass == false) {
302
+ this.throw(`not at '${pathToString(needle.path)}' not met`, needle);
303
+ }
304
+ }
213
305
  if (needle.schema.hasOwnProperty("oneOf")) {
214
306
  const rounds = this.parseList(needle.schema.oneOf, needle, (r) => r !== 1);
215
307
  if (rounds !== 1) {
@@ -322,6 +414,14 @@ var Cabidela = class {
322
414
  break;
323
415
  }
324
416
  }
417
+ if (needle.schema.hasOwnProperty("pattern")) {
418
+ let passes = false;
419
+ try {
420
+ if (new RegExp(needle.schema.pattern).test(resolvedObject)) passes = true;
421
+ } catch (e) {
422
+ }
423
+ if (!passes) this.throw(`'${pathToString(needle.path)}' failed test ${needle.schema.pattern} patttern`, needle);
424
+ }
325
425
  if (needle.carryProperties) {
326
426
  needle.evaluatedProperties.add(pathToString(needle.path));
327
427
  }
package/dist/index.mjs CHANGED
@@ -1,4 +1,50 @@
1
1
  // src/helpers.ts
2
+ var parse$ref = (ref) => {
3
+ const parts = ref.split("#");
4
+ const $id = parts[0];
5
+ const $path = parts[1].split("/").filter((part) => part !== "");
6
+ return { $id, $path };
7
+ };
8
+ function deepMerge(target, source) {
9
+ const result = Array.isArray(target) && Array.isArray(source) ? target.concat(source) : { ...target, ...source };
10
+ for (const key of Object.keys(result)) {
11
+ result[key] = typeof target[key] == "object" && typeof source[key] == "object" ? deepMerge(target[key], source[key]) : structuredClone(result[key]);
12
+ }
13
+ return result;
14
+ }
15
+ var traverseSchema = (options, definitions, obj, cb) => {
16
+ let hits;
17
+ do {
18
+ hits = 0;
19
+ Object.keys(obj).forEach((key) => {
20
+ if (obj[key] !== null && typeof obj[key] === "object") {
21
+ traverseSchema(options, definitions, obj[key], (value) => {
22
+ hits++;
23
+ obj[key] = value;
24
+ });
25
+ if (options.useMerge && key === "$merge") {
26
+ const merge = deepMerge(obj[key].source, obj[key].with);
27
+ if (cb) {
28
+ cb(merge);
29
+ } else {
30
+ Object.assign(obj, merge);
31
+ delete obj[key];
32
+ }
33
+ }
34
+ } else {
35
+ if (key === "$ref") {
36
+ const { $id, $path } = parse$ref(obj[key]);
37
+ const { resolvedObject } = resolvePayload($path, definitions[$id]);
38
+ if (resolvedObject) {
39
+ cb(resolvedObject);
40
+ } else {
41
+ throw new Error(`Could not resolve '${obj[key]}' $ref`);
42
+ }
43
+ }
44
+ }
45
+ });
46
+ } while (hits > 0);
47
+ };
2
48
  var resolvePayload = (path, obj) => {
3
49
  let resolvedObject = path.reduce(function(prev, curr) {
4
50
  return prev ? prev[curr] : void 0;
@@ -6,7 +52,7 @@ var resolvePayload = (path, obj) => {
6
52
  return { metadata: getMetaData(resolvedObject), resolvedObject };
7
53
  };
8
54
  var pathToString = (path) => {
9
- return path.length == 0 ? `.` : path.map((item) => typeof item === "number" ? `[${item}]` : `.${item}`).join("");
55
+ return path.length == 0 ? `/` : path.map((item) => `/${item}`).join("");
10
56
  };
11
57
  var getMetaData = (value) => {
12
58
  let size = 0;
@@ -44,20 +90,52 @@ var getMetaData = (value) => {
44
90
  var Cabidela = class {
45
91
  schema;
46
92
  options;
93
+ definitions = {};
47
94
  constructor(schema, options) {
48
95
  this.schema = schema;
49
96
  this.options = {
50
97
  fullErrors: true,
98
+ subSchemas: [],
51
99
  applyDefaults: false,
52
100
  errorMessages: false,
53
101
  ...options || {}
54
102
  };
103
+ if (this.schema.hasOwnProperty("$defs")) {
104
+ this.definitions["$defs"] = this.schema["$defs"];
105
+ delete this.schema["$defs"];
106
+ }
107
+ if (this.options.subSchemas.length > 0) {
108
+ for (const subSchema of this.options.subSchemas) {
109
+ this.addSchema(subSchema, false);
110
+ }
111
+ }
112
+ if (this.options.useMerge || this.options.subSchemas.length > 0) {
113
+ traverseSchema(this.options, this.definitions, this.schema);
114
+ }
55
115
  }
56
116
  setSchema(schema) {
57
117
  this.schema = schema;
58
118
  }
119
+ addSchema(subSchema, combine = true) {
120
+ if (subSchema.hasOwnProperty("$id")) {
121
+ const url = URL.parse(subSchema["$id"]);
122
+ if (url) {
123
+ this.definitions[url.pathname.split("/").slice(-1)[0]] = subSchema;
124
+ } else {
125
+ throw new Error(
126
+ "subSchemas need a valid retrieval URI $id https://json-schema.org/understanding-json-schema/structuring#retrieval-uri"
127
+ );
128
+ }
129
+ } else {
130
+ throw new Error("subSchemas need $id https://json-schema.org/understanding-json-schema/structuring#id");
131
+ }
132
+ if (combine == true) traverseSchema(this.options, this.definitions, this.schema);
133
+ }
134
+ getSchema() {
135
+ return this.schema;
136
+ }
59
137
  setOptions(options) {
60
- this.options = options;
138
+ this.options = { ...this.options, ...options };
61
139
  }
62
140
  throw(message, needle) {
63
141
  const error = `${message}${this.options.fullErrors && needle.absorvErrors !== true && needle.errors.size > 0 ? `: ${Array.from(needle.errors).join(", ")}` : ``}`;
@@ -83,7 +161,7 @@ var Cabidela = class {
83
161
  } else {
84
162
  for (let property of unevaluatedProperties) {
85
163
  if (this.parseSubSchema({
86
- path: [property.split(".").slice(-1)[0]],
164
+ path: [property.split("/").slice(-1)[0]],
87
165
  schema: contextAdditionalProperties,
88
166
  payload: resolvedObject,
89
167
  evaluatedProperties: /* @__PURE__ */ new Set(),
@@ -149,7 +227,7 @@ var Cabidela = class {
149
227
  if (new Set(needle.schema.required.map((r) => pathToString([...needle.path, r]))).difference(
150
228
  needle.evaluatedProperties.union(localEvaluatedProperties)
151
229
  ).size > 0) {
152
- this.throw(`required properties at '${pathToString(needle.path)}' is '${needle.schema.required}'`, needle);
230
+ this.throw(`required properties at '${pathToString(needle.path)}' are '${needle.schema.required}'`, needle);
153
231
  }
154
232
  }
155
233
  return matchCount ? true : false;
@@ -184,6 +262,20 @@ var Cabidela = class {
184
262
  if (needle.schema == void 0) {
185
263
  this.throw(`No schema for path '${pathToString(needle.path)}'`, needle);
186
264
  }
265
+ if (needle.schema.hasOwnProperty("not")) {
266
+ let pass = false;
267
+ try {
268
+ this.parseSubSchema({
269
+ ...needle,
270
+ schema: needle.schema.not
271
+ });
272
+ } catch (e) {
273
+ pass = true;
274
+ }
275
+ if (pass == false) {
276
+ this.throw(`not at '${pathToString(needle.path)}' not met`, needle);
277
+ }
278
+ }
187
279
  if (needle.schema.hasOwnProperty("oneOf")) {
188
280
  const rounds = this.parseList(needle.schema.oneOf, needle, (r) => r !== 1);
189
281
  if (rounds !== 1) {
@@ -296,6 +388,14 @@ var Cabidela = class {
296
388
  break;
297
389
  }
298
390
  }
391
+ if (needle.schema.hasOwnProperty("pattern")) {
392
+ let passes = false;
393
+ try {
394
+ if (new RegExp(needle.schema.pattern).test(resolvedObject)) passes = true;
395
+ } catch (e) {
396
+ }
397
+ if (!passes) this.throw(`'${pathToString(needle.path)}' failed test ${needle.schema.pattern} patttern`, needle);
398
+ }
299
399
  if (needle.carryProperties) {
300
400
  needle.evaluatedProperties.add(pathToString(needle.path));
301
401
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudflare/cabidela",
3
- "version": "0.0.19",
3
+ "version": "0.2.0",
4
4
  "description": "Cabidela is a small, fast, eval-less, Cloudflare Workers compatible, dynamic JSON Schema validator",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -27,6 +27,9 @@
27
27
  "README.md",
28
28
  "CHANGELOG.md"
29
29
  ],
30
+ "prettier": {
31
+ "embeddedLanguageFormatting": "auto"
32
+ },
30
33
  "repository": {
31
34
  "type": "git",
32
35
  "url": "https://github.com/cloudflare/cabidela.git"
@@ -39,6 +42,7 @@
39
42
  "@vitest/ui": "^3.0.3",
40
43
  "ajv": "^8.17.1",
41
44
  "ajv-errors": "^3.0.0",
45
+ "ajv-merge-patch": "^5.0.1",
42
46
  "tsup": "^8.3.6",
43
47
  "typescript": "^5.7.3",
44
48
  "vitest": "^3.0.3"