schema-shield 0.0.6 → 1.0.1

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.
Files changed (39) hide show
  1. package/README.md +219 -65
  2. package/dist/formats.d.ts.map +1 -1
  3. package/dist/index.d.ts +25 -6
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1837 -484
  6. package/dist/index.min.js +1 -1
  7. package/dist/index.min.js.map +1 -1
  8. package/dist/index.mjs +1837 -484
  9. package/dist/keywords/array-keywords.d.ts.map +1 -1
  10. package/dist/keywords/object-keywords.d.ts.map +1 -1
  11. package/dist/keywords/other-keywords.d.ts.map +1 -1
  12. package/dist/keywords/string-keywords.d.ts.map +1 -1
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/utils/deep-freeze.d.ts +5 -0
  15. package/dist/utils/deep-freeze.d.ts.map +1 -0
  16. package/dist/utils/has-changed.d.ts +2 -0
  17. package/dist/utils/has-changed.d.ts.map +1 -0
  18. package/dist/utils/index.d.ts +5 -0
  19. package/dist/utils/index.d.ts.map +1 -0
  20. package/dist/{utils.d.ts → utils/main-utils.d.ts} +7 -9
  21. package/dist/utils/main-utils.d.ts.map +1 -0
  22. package/dist/utils/pattern-matcher.d.ts +3 -0
  23. package/dist/utils/pattern-matcher.d.ts.map +1 -0
  24. package/lib/formats.ts +468 -155
  25. package/lib/index.ts +702 -107
  26. package/lib/keywords/array-keywords.ts +260 -52
  27. package/lib/keywords/number-keywords.ts +1 -1
  28. package/lib/keywords/object-keywords.ts +295 -88
  29. package/lib/keywords/other-keywords.ts +263 -70
  30. package/lib/keywords/string-keywords.ts +123 -7
  31. package/lib/types.ts +5 -18
  32. package/lib/utils/deep-freeze.ts +208 -0
  33. package/lib/utils/has-changed.ts +51 -0
  34. package/lib/utils/index.ts +4 -0
  35. package/lib/{utils.ts → utils/main-utils.ts} +63 -77
  36. package/lib/utils/pattern-matcher.ts +66 -0
  37. package/package.json +2 -2
  38. package/tsconfig.json +4 -4
  39. package/dist/utils.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,16 +1,47 @@
1
- # SchemaShield
1
+ # SchemaShield 🛡️
2
2
 
3
- SchemaShield is a versatile and powerful JSON Schema validator designed to simplify the process of validating complex data structures.
3
+ **Validation for Modern Architectures: Secure, Stack-Safe, and Domain-Aware.**
4
4
 
5
- Unlike many other libraries, SchemaShield does not rely on code generation, making it safer to pass real references to objects, classes, or variables and opening new possibilities for custom validation that are not possible with other libraries.
5
+ SchemaShield is a secure interpreter for JSON Schema engineered for strict environments and complex domain logic. It prioritizes **architectural stability** and **developer experience** over raw synthetic throughput.
6
6
 
7
- Despite its feature-rich and easy extendable nature, SchemaShield is designed to be fast and efficient, matching the performance of other libraries that use code generation.
7
+ > 🏆 **Fastest JSON Schema Validator on Bun** 2.5x faster than ajv, 4x faster than schemasafe
8
+ >
9
+ > 📊 **#3 fastest on Node.js** — 70% ajv speed, 50x faster than jsonschema
10
+
11
+ ## Quick Start
12
+
13
+ ```javascript
14
+ import { SchemaShield } from "schema-shield";
15
+
16
+ const validator = new SchemaShield().compile({
17
+ type: "object",
18
+ properties: {
19
+ name: { type: "string" },
20
+ age: { type: "number" }
21
+ }
22
+ });
23
+
24
+ validator({ name: "John", age: 30 });
25
+ // { valid: true, data: { name: "John", age: 30 } }
26
+
27
+ validator({ name: "John", age: "30" });
28
+ // { valid: false, error: ValidationError }
29
+ ```
8
30
 
9
31
  ## Table of Contents
10
32
 
11
- - [Table of Contents](#table-of-contents)
12
- - [Features](#features)
33
+ - [Quick Start](#quick-start)
34
+ - [Why SchemaShield?](#why-schemashield)
35
+ - [Comparison with Other Approaches](#comparison-with-other-approaches)
13
36
  - [Usage](#usage)
37
+ - [Performance](#performance)
38
+ - [Understanding Performance Context](#understanding-performance-context)
39
+ - [1. Modern Runtimes (Bun)](#1-modern-runtimes-bun)
40
+ - [2. Standard Runtimes (Node.js)](#2-standard-runtimes-nodejs)
41
+ - [Edge \& Serverless Ready](#edge--serverless-ready)
42
+ - [Features](#features)
43
+ - [Security Philosophy: Hermetic Validation](#security-philosophy-hermetic-validation)
44
+ - [Why No Remote References?](#why-no-remote-references)
14
45
  - [No Code Generation](#no-code-generation)
15
46
  - [Error Handling](#error-handling)
16
47
  - [Adding Custom Types](#adding-custom-types)
@@ -23,7 +54,8 @@ Despite its feature-rich and easy extendable nature, SchemaShield is designed to
23
54
  - [Method Signature](#method-signature-2)
24
55
  - [Example: Adding a Custom Keyword](#example-adding-a-custom-keyword)
25
56
  - [Complex example: Adding a Custom Keyword that uses the instance](#complex-example-adding-a-custom-keyword-that-uses-the-instance)
26
- - [No Code Generation Opened Possibilities](#no-code-generation-opened-possibilities)
57
+ - [Supported Formats](#supported-formats)
58
+ - [Validating Runtime Objects](#validating-runtime-objects)
27
59
  - [More on Error Handling](#more-on-error-handling)
28
60
  - [ValidationError Properties](#validationerror-properties)
29
61
  - [Get the path to the error location](#get-the-path-to-the-error-location)
@@ -32,22 +64,40 @@ Despite its feature-rich and easy extendable nature, SchemaShield is designed to
32
64
  - [Immutable Mode](#immutable-mode)
33
65
  - [TypeScript Support](#typescript-support)
34
66
  - [Known Limitations](#known-limitations)
35
- - [Schema References and Schema Definitions](#schema-references-and-schema-definitions)
36
- - [Unsupported Formats](#unsupported-formats)
67
+ - [1. Dynamic ID Scope Resolution (Scope Alteration)](#1-dynamic-id-scope-resolution-scope-alteration)
68
+ - [2. Unicode Length Validation](#2-unicode-length-validation)
69
+ - [3. Conservative Equality Path (Performance Trade-off)](#3-conservative-equality-path-performance-trade-off)
37
70
  - [Testing](#testing)
38
71
  - [Contribute](#contribute)
39
72
  - [Legal](#legal)
40
73
 
41
- ## Features
74
+ ## Why SchemaShield?
42
75
 
43
- - Supports draft-06 and draft-07 of the [JSON Schema](https://json-schema.org/) specification.
44
- - No Code Generation for Enhanced Safety and Validation Flexibility.
45
- - Custom type, keyword, and format validators.
46
- - Immutable mode for data protection.
47
- - Lightweight and fast.
48
- - Easy to use and extend.
49
- - No dependencies.
50
- - Typescript support.
76
+ Most validators optimize for "operations per second" in synthetic benchmarks, often sacrificing security, stability, or maintainability. SchemaShield optimizes for the **Total Cost of Ownership** of your software.
77
+
78
+ | Feature | JIT Compilers | SchemaShield | Why it matters |
79
+ | :------------------- | :------------------------------------------------------------------- | :--------------------------------------------------------- | :-------------------------------------------------------------------------------------- |
80
+ | **Security Model** | **Reactive**<br>(Requires config to prevent Prototype Pollution/DoS) | **Preventive**<br>(Hermetic & Immutable by design) | "Secure by default" prevents human error and vulnerabilities in production. |
81
+ | **Debug Experience** | **Black Box**<br>(Debugs opaque generated strings/code) | **White Box**<br>(Standard JS stack traces) | Drastically reduces time-to-fix when validation fails in complex logic. |
82
+ | **Stability** | **Recursive**<br>(Risk of Stack Overflow on deep data) | **Flat Loop**<br>(Constant memory usage) | Protects your server availability against malicious deep-payload attacks. |
83
+ | **Domain Logic** | **Disconnected**<br>(Hard to validate Class Instances/State) | **Integrated**<br>(Native `instanceof` & state validation) | Unifies DTO validation and Business Rules, eliminating "spaghetti code" in controllers. |
84
+ | **Ecosystem** | **Fragmented**<br>(Requires plugins for errors/formats) | **Cohesive**<br>(Advanced error trees & formats built-in) | Reduces dependency fatigue and maintenance burden. |
85
+
86
+ > **The Trade-off:** While JIT compilers can be faster in raw throughput on V8 (Node.js), SchemaShield offers a balanced architecture where validation is never the bottleneck in real-world I/O bound applications (Database/Network APIs).
87
+
88
+ ### Comparison with Other Approaches
89
+
90
+ | Feature | SchemaShield | JIT Compilers | Classic Interpreters |
91
+ | :---------------------------- | :-------------------------------------------------- | :------------------------------- | :-------------------- |
92
+ | **Architecture** | **Secure Flat Interpreter** | JIT Compiler (eval/new Function) | Recursive Interpreter |
93
+ | **Relative Speed** | **High (~70%)** | Reference (100%) | Low (1% - 20%) |
94
+ | **CSP Compliance** | **Native (100% Safe)** | Requires Build Config | Variable |
95
+ | **Edge Ready** | **Native** | Complex Setup | Variable |
96
+ | **Stack Safety** | **Minimized stack usage (non-recursive core loop)** | Risk of Overflow | Risk of Overflow |
97
+ | **Class Instance Validation** | **Native** | No | No |
98
+ | **Debug Experience** | **Clean Stack Trace** | Opaque Generated Code | Variable |
99
+
100
+ > **Note:** Stack Safety refers to the risk of stack overflow errors when validating deeply nested data structures. SchemaShield's flat interpreter design minimizes this risk in its core validation loop. Keep in mind that custom keywords can still introduce recursion if not implemented carefully.
51
101
 
52
102
  ## Usage
53
103
 
@@ -56,7 +106,7 @@ Despite its feature-rich and easy extendable nature, SchemaShield is designed to
56
106
  ```bash
57
107
  npm install schema-shield
58
108
  # or
59
- yarn add schema-shield
109
+ bun add schema-shield
60
110
  ```
61
111
 
62
112
  **2. Import the SchemaShield class**
@@ -70,10 +120,11 @@ const { SchemaShield } = require("schema-shield");
70
120
  **3. Instantiate the SchemaShield class**
71
121
 
72
122
  ```javascript
73
- const schemaShield = new SchemaShield({ immutable: true });
123
+ const schemaShield = new SchemaShield();
74
124
  ```
75
125
 
76
- **`immutable`** (optional): Set to `true` to ensure that input data remains unmodified during validation. Default is `false` for better performance.
126
+ - **`immutable`** (optional): Set to `true` to ensure that input data remains unmodified during validation. Default is `false` for better performance.
127
+ - **`failFast`** (optional): Set to `false` to receive detailed error objects on validation failure. Default is `true` for lightweight failure indication.
77
128
 
78
129
  **3.5. Add custom types, keywords, and formats (optional)**
79
130
 
@@ -128,9 +179,92 @@ if (validationResult.valid) {
128
179
  **`validationResult`**: Contains the following properties:
129
180
 
130
181
  - `data`: The validated (and potentially modified) data.
131
- - `error`: A `ValidationError` instance if validation failed, otherwise null.
182
+ - `error`: A `ValidationError` instance if validation failed (when `failFast: false`), `true` if validation failed in fail-fast mode, otherwise `null`.
132
183
  - `valid`: true if validation was successful, otherwise false.
133
184
 
185
+ > Note: When SchemaShield is instantiated with `{ failFast: false }`, `validationResult.error` will contain a detailed `ValidationError` instance if validation fails. In `failFast: true` mode, `error` is just `true` as a lightweight sentinel.
186
+
187
+ **6. Intelligent Defaults**
188
+
189
+ SchemaShield applies `default` values only when necessary to fulfill the schema contract. A `default` value is injected if and only if:
190
+
191
+ 1. The property is missing in the input data.
192
+ 2. The property is marked as `required` in the schema.
193
+
194
+ ## Performance
195
+
196
+ SchemaShield is engineered with a **Flat Loop Interpreter** architecture. This design choice implies zero compilation overhead, making it exceptionally stable and significantly faster in modern runtimes.
197
+
198
+ ### Understanding Performance Context
199
+
200
+ In real-world applications, validation latency is often negligible compared to Network I/O (~20-100ms) or Database queries (~5-50ms).
201
+
202
+ SchemaShield is engineered to be **"Elite Fast" (Sufficiently Fast)**:
203
+
204
+ - **Zero Compilation Overhead:** Ideal for Serverless/Edge cold-starts.
205
+ - **Predictable Throughput:** Consistent performance regardless of schema complexity.
206
+
207
+ While JIT compilers may show higher numbers in micro-benchmarks on V8, SchemaShield processes thousands of requests per second—more than enough for high-traffic APIs—without the architectural risks of code generation.
208
+
209
+ ### 1. Modern Runtimes (Bun)
210
+
211
+ In runtimes using JavaScriptCore (like Bun), SchemaShield outperforms JIT compilers because it avoids the heavy cost of runtime code generation and optimization overhead.
212
+
213
+ | Validator | Relative Speed | Context |
214
+ | :----------------- | :------------- | :----------- |
215
+ | **SchemaShield** | **100%** | **Fastest** |
216
+ | ajv | ~40% | JIT Compiler |
217
+ | @exodus/schemasafe | ~24% | Interpreter |
218
+ | jsonschema | ~2% | Legacy |
219
+
220
+ ### 2. Standard Runtimes (Node.js)
221
+
222
+ In V8-based environments (Node.js), SchemaShield maintains elite performance for a secure interpreter, being roughly **70x faster** than legacy libraries.
223
+
224
+ | Validator | Relative Speed | Context |
225
+ | :----------------- | :------------- | :------------------ |
226
+ | ajv | 100% | Reference (JIT) |
227
+ | @exodus/schemasafe | ~74% | Interpreter |
228
+ | **SchemaShield** | **~70%** | **Secure Standard** |
229
+ | jsonschema | ~1% | Legacy |
230
+
231
+ **Key Takeaway:** SchemaShield delivers consistent high performance in Node.js without the security risks, memory leaks, or "cold start" latency associated with code generation.
232
+
233
+ ## Edge & Serverless Ready
234
+
235
+ SchemaShield is designed to run seamlessly in restrictive environments like **Cloudflare Workers**, **Vercel Edge Functions**, **Deno Deploy**, and **Bun**.
236
+
237
+ - **Zero Dependencies:** No strict reliance on Node.js built-ins.
238
+ - **CSP Compliant:** Works in environments where `eval()` and `new Function()` are banned for security.
239
+ - **Instant Startup:** No compilation overhead, minimizing "cold start" latency in Serverless functions.
240
+
241
+ ## Features
242
+
243
+ - Supports draft-06 and draft-07 of the [JSON Schema](https://json-schema.org/) specification.
244
+ - Full support for internal references ($ref) and anchors ($id).
245
+ - No Code Generation for Enhanced Safety and Validation Flexibility.
246
+ - Custom type, keyword, and format validators.
247
+ - Runtime object validation: first-class support for business logic checks (type checking and schema validation).
248
+ - Immutable mode for data protection.
249
+ - Lightweight and fast.
250
+ - Easy to use and extend.
251
+ - No dependencies.
252
+ - TypeScript support.
253
+
254
+ ## Security Philosophy: Hermetic Validation
255
+
256
+ SchemaShield adopts a **Zero Trust** and **Hermetic Architecture** approach. Unlike validators that allow runtime network access, SchemaShield is strictly synchronous and offline by design.
257
+
258
+ ### Why No Remote References?
259
+
260
+ Allowing a validator to fetch schemas from remote URLs (`$ref: "https://..."`) at runtime introduces critical security vectors and stability issues:
261
+
262
+ 1. **SSRF (Server-Side Request Forgery):** Prevents attackers from manipulating schemas to force internal network scanning or access metadata services.
263
+ 2. **Supply Chain Attacks:** Eliminates the risk of a remote schema being silently compromised, which could alter validation logic without code deployment.
264
+ 3. **Deterministic Reliability:** Validation never fails due to network latency, DNS issues, or third-party server downtime.
265
+
266
+ **Recommendation:** Treat schemas as **code dependencies**, not dynamic assets. Download and bundle remote schemas locally during your build process to ensure immutable, versioned, and audit-ready validation.
267
+
134
268
  ## No Code Generation
135
269
 
136
270
  Unlike some other validation libraries that rely on code generation to achieve fast performance, SchemaShield does not use code generation.
@@ -146,18 +280,21 @@ class CustomDate extends Date {}
146
280
  schemaShield.addType("custom-date-class", (data) => data instanceof CustomDate);
147
281
  ```
148
282
 
149
- You can see a full example of this in the [No Code Generation opened possibilities](#no-code-generation-opened-possibilities) section.
150
-
151
283
  ## Error Handling
152
284
 
153
- SchemaShield provides comprehensive error handling for schema validation. When a validation error occurs, a `ValidationError` instance is returned in the error property of the validation result. This error has the `getPath()` method, which is particularly useful for quickly identifying the location of an error in both the schema and the data.
285
+ SchemaShield provides comprehensive error handling for schema validation. When a validation error occurs:
286
+
287
+ - If the instance was created with `{ failFast: true }` (the default), the `error` property will be `true` as a lightweight sentinel indicating that validation failed.
288
+ - If the instance was created with `{ failFast: false }`, the `error` property will contain a `ValidationError` instance with rich debugging information.
289
+
290
+ This error object has the `getPath()` method, which is particularly useful for quickly identifying the location of an error in both the schema and the data.
154
291
 
155
292
  **Example:**
156
293
 
157
294
  ```javascript
158
295
  import { SchemaShield } from "schema-shield";
159
296
 
160
- const schemaShield = new SchemaShield();
297
+ const schemaShield = new SchemaShield({ failFast: false });
161
298
 
162
299
  const schema = {
163
300
  type: "object",
@@ -218,7 +355,7 @@ In this example, we'll add a custom type called age that validates if a given nu
218
355
  ```javascript
219
356
  import { SchemaShield } from "schema-shield";
220
357
 
221
- const schemaShield = new SchemaShield();
358
+ const schemaShield = new SchemaShield({ failFast: false });
222
359
 
223
360
  // Custom type 'age' validator function
224
361
  const ageValidator = (data) => {
@@ -275,9 +412,9 @@ addFormat(name: string, validator: FormatFunction, overwrite?: boolean): void;
275
412
  In this example, we'll add a custom format called ssn that validates if a given string is a valid U.S. Social Security Number (SSN).
276
413
 
277
414
  ```javascript
278
- import { SchemaShield } from "./path/to/SchemaShield";
415
+ import { SchemaShield } from "schema-shield";
279
416
 
280
- const schemaShield = new SchemaShield();
417
+ const schemaShield = new SchemaShield({ failFast: false });
281
418
 
282
419
  // Custom format 'ssn' validator function
283
420
  const ssnValidator = (data) => {
@@ -314,21 +451,21 @@ if (validationResult.valid) {
314
451
 
315
452
  ## Adding Custom Keywords
316
453
 
317
- SchemaShield allows you to add custom keywords for validation using the addKeyword method. This is the most powerful method for adding custom validation logic to SchemaShield because it allows to interact with the entire schema and data being validated at the level of the keyword.
454
+ SchemaShield allows you to add custom keywords for validation using the `addKeyword` method. This is the most powerful method for adding custom validation logic to SchemaShield because it allows you to interact with the entire schema and data being validated at the level of the keyword.
318
455
 
319
456
  ### Method Signature
320
457
 
321
458
  ```javascript
322
- type Result = void | ValidationError;
459
+ type Result = void | ValidationError | true;
323
460
 
324
461
  interface DefineErrorOptions {
325
462
  item?: any; // Final item in the path
326
- cause?: ValidationError; // Cause of the error
463
+ cause?: ValidationError | true; // Cause of the error (or true in failFast mode)
327
464
  data?: any; // Data that caused the error
328
465
  }
329
466
 
330
467
  interface DefineErrorFunction {
331
- (message: string, options?: DefineErrorOptions): ValidationError;
468
+ (message: string, options?: DefineErrorOptions): ValidationError | true;
332
469
  }
333
470
 
334
471
  interface ValidateFunction {
@@ -349,8 +486,9 @@ interface TypeFunction {
349
486
  }
350
487
 
351
488
  declare class SchemaShield {
352
- constructor({ immutable }?: {
353
- immutable?: boolean;
489
+ constructor(options?: {
490
+ immutable?: boolean;
491
+ failFast?: boolean;
354
492
  });
355
493
  compile(schema: any): Validator;
356
494
  addType(name: string, validator: TypeFunction, overwrite?: boolean): void;
@@ -377,7 +515,7 @@ addKeyword(name: string, validator: KeywordFunction, overwrite?: boolean): void;
377
515
  ```
378
516
 
379
517
  - `name`: The name of the custom keyword. This should be a unique string that does not conflict with existing keywords.
380
- - `validator`: A `KeywordFunction` that takes four arguments: `schema`, `data`, `defineError`, and `instance` (The SchemaShield instance that is currently running the validation). The function should not return anything if the data is valid for the custom keyword, and should return a `ValidationError` instance if the data is invalid.
518
+ - `validator`: A `KeywordFunction` that takes four arguments: `schema`, `data`, `defineError`, and `instance` (The SchemaShield instance that is currently running the validation). The function should not return anything if the data is valid for the custom keyword, and should return a `ValidationError` instance if the data is invalid when `failFast` is `false`, or `true` when `failFast` is `true`.
381
519
  - `overwrite` (optional): Set to true to overwrite an existing keyword with the same name. Default is false. If set to false and a keyword with the same name already exists, an error will be thrown.
382
520
 
383
521
  #### About the `defineError` Function
@@ -387,9 +525,11 @@ Take into account that the error must be generated using the `defineError` funct
387
525
  - `message`: A string that describes the validation error.
388
526
  - `options`: An optional object with properties that provide more context for the error:
389
527
  - `item`?: An optional value representing the final item in the path where the validation error occurred. (e.g. index of an array item)
390
- - `cause`?: An optional `ValidationError` that represents the cause of the current error.
528
+ - `cause`?: An optional `ValidationError` (or `true` in fail-fast mode) that represents the cause of the current error.
391
529
  - `data`?: An optional value representing the data that caused the validation error.
392
530
 
531
+ When the SchemaShield instance is created with `failFast: true`, `defineError` returns `true` instead of a `ValidationError`, and keyword implementations should simply `return` whatever `defineError` gives them.
532
+
393
533
  #### About the `instance` Argument
394
534
 
395
535
  The `instance` argument is the SchemaShield instance that is currently running the validation. This can be used to access to other `types`, `keywords` or `formats` that have been added to the instance.
@@ -399,9 +539,9 @@ The `instance` argument is the SchemaShield instance that is currently running t
399
539
  In this example, we'll add a custom keyword called divisibleBy that validates if a given number is divisible by a specified divisor.
400
540
 
401
541
  ```javascript
402
- import { SchemaShield, ValidationError } from "./path/to/SchemaShield";
542
+ import { SchemaShield, ValidationError } from "schema-shield";
403
543
 
404
- const schemaShield = new SchemaShield();
544
+ const schemaShield = new SchemaShield({ failFast: false });
405
545
 
406
546
  // Custom keyword 'divisibleBy' validator function
407
547
  const divisibleByValidator = (schema, data, defineError, instance) => {
@@ -450,7 +590,7 @@ In this example we'll add a custom keyword called `prefixedUsername` that will v
450
590
  ```javascript
451
591
  import { SchemaShield, ValidationError } from "schema-shield";
452
592
 
453
- const schemaShield = new SchemaShield();
593
+ const schemaShield = new SchemaShield({ failFast: false });
454
594
 
455
595
  // Custom type validator: nonEmptyString
456
596
  const nonEmptyStringValidator = (data) =>
@@ -479,7 +619,7 @@ const prefixedUsername = (schema, data, defineError, instance) => {
479
619
  // Get the validators for the specified types and formats from the instance
480
620
  // (if they exist)
481
621
  const typeValidator = instance.getType(validType);
482
- const prefixValidator = instance.getKeyword(prefixValidator);
622
+ const prefixKeyword = instance.getKeyword(prefixValidator);
483
623
  const formatValidator = instance.getFormat(validFormat);
484
624
 
485
625
  for (let i = 0; i < data.length; i++) {
@@ -506,8 +646,8 @@ const prefixedUsername = (schema, data, defineError, instance) => {
506
646
  }
507
647
 
508
648
  // Validate that the data has the correct prefix if specified
509
- if (prefixValidator) {
510
- const error = prefixValidator(schema, item, defineError, instance);
649
+ if (prefixKeyword) {
650
+ const error = prefixKeyword(schema, item, defineError, instance);
511
651
  if (error) {
512
652
  return defineError(`Invalid prefix: ${prefixValidator}`, {
513
653
  cause: error,
@@ -546,16 +686,30 @@ if (validationResult.valid) {
546
686
  }
547
687
  ```
548
688
 
549
- ## No Code Generation Opened Possibilities
689
+ ## Supported Formats
690
+
691
+ SchemaShield includes built-in validators for the following formats:
692
+
693
+ - **Date & Time:** `date`, `time`, `date-time`, `duration`.
694
+ - **Email:** `email`, `idn-email`.
695
+ - **Hostnames:** `hostname`, `idn-hostname`.
696
+ - **IP Addresses:** `ipv4`, `ipv6`.
697
+ - **Resource Identifiers:** `uuid`, `uri`, `uri-reference`, `uri-template`, `iri`, `iri-reference`.
698
+ - **JSON Pointers:** `json-pointer`, `relative-json-pointer`.
699
+ - **Regex:** `regex`.
700
+
701
+ You can override any of these or add new ones using `schemaShield.addFormat`.
702
+
703
+ ## Validating Runtime Objects
550
704
 
551
- With the no code generation nature of SchemaShield, you can create complex validation logic that incorporates custom classes, objects, or variables. This flexibility allows you to seamlessly integrate the validation process into your application's unique requirements and data structures.
705
+ JSON Schema is traditionally for serialized JSON text. SchemaShield extends this concept to **JavaScript Objects**. It allows validation of class instances, Dates, and internal application state directly.
552
706
 
553
707
  For example, imagine you have a custom class representing a project and another representing an employee. You could create a custom validator to ensure that only employees with the right qualifications are assigned to a specific project:
554
708
 
555
709
  ```javascript
556
710
  import { SchemaShield, ValidationError } from "schema-shield";
557
711
 
558
- const schemaShield = new SchemaShield();
712
+ const schemaShield = new SchemaShield({ failFast: false });
559
713
 
560
714
  // Custom classes
561
715
  class Project {
@@ -653,7 +807,7 @@ const dataToValidate = {
653
807
  };
654
808
 
655
809
  // Validate the data
656
- const validationResult = validator(schema);
810
+ const validationResult = validator(dataToValidate);
657
811
 
658
812
  if (validationResult.valid) {
659
813
  console.log("Assignment is valid:", validationResult.data);
@@ -666,9 +820,9 @@ In this example, SchemaShield safely accesses instances of custom classes and ut
666
820
 
667
821
  ## More on Error Handling
668
822
 
669
- SchemaShield provides a `ValidationError` class to handle errors that occur during schema validation. When a validation error is encountered, a `ValidationError` instance is returned in the error property of the validation result.
823
+ SchemaShield provides a `ValidationError` class to handle errors that occur during schema validation. When a validation error is encountered, a `ValidationError` instance is returned in the error property of the validation result when `failFast: false` is used; otherwise `error` is `true`.
670
824
 
671
- This error instance uses the new [Error: cause](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) property introduced in ES6. This allows you to analyze the whole error chain or to retrieve the root cause of the error using the `getCause()` `getTree()` and `getPath()` methods.
825
+ This error instance uses the [`Error.cause`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause) property. This allows you to analyze the whole error chain or retrieve the root cause of the error using the `getCause()`, `getTree()`, and `getPath()` methods.
672
826
 
673
827
  ### ValidationError Properties
674
828
 
@@ -692,7 +846,7 @@ You can use the `getPath` method to get the JSON Pointer path to the error locat
692
846
  ```javascript
693
847
  import { SchemaShield } from "schema-shield";
694
848
 
695
- const schemaShield = new SchemaShield();
849
+ const schemaShield = new SchemaShield({ failFast: false });
696
850
 
697
851
  const schema = {
698
852
  type: "object",
@@ -768,7 +922,7 @@ interface ErrorTree {
768
922
  ```javascript
769
923
  import { SchemaShield } from "schema-shield";
770
924
 
771
- const schemaShield = new SchemaShield();
925
+ const schemaShield = new SchemaShield({ failFast: false });
772
926
 
773
927
  const schema = {
774
928
  type: "object",
@@ -856,7 +1010,7 @@ You can use the `getCause()` method to retrieve the root cause of a validation e
856
1010
  ```javascript
857
1011
  import { SchemaShield } from "schema-shield";
858
1012
 
859
- const schemaShield = new SchemaShield();
1013
+ const schemaShield = new SchemaShield({ failFast: false });
860
1014
 
861
1015
  const schema = {
862
1016
  type: "object",
@@ -937,26 +1091,26 @@ With the built in TypeScript support, you can take advantage of features like st
937
1091
 
938
1092
  ## Known Limitations
939
1093
 
940
- SchemaShield is a powerful and flexible library, but there are some limitations to be aware of when using it. Some features are not yet supported in the current version.
1094
+ SchemaShield is optimized for local execution and strict security.
1095
+
1096
+ ### 1. Dynamic ID Scope Resolution (Scope Alteration)
941
1097
 
942
- ### Schema References and Schema Definitions
1098
+ SchemaShield resolves references based on static JSON Pointers and unique IDs. It does not support changing the resolution base URI dynamically based on nested `$id` properties within sub-schemas.
943
1099
 
944
- SchemaShield currently does not support schema references and schema definitions (i.e. `$ref` and `definitions`). This is planned to be addressed in future updates of SchemaShield.
1100
+ - **Impact:** Rare edge-cases in draft-07 involving complex relative URI resolution inside nested scopes are not supported.
945
1101
 
946
- For now, consider using custom implementations using the `addKeyword` method or use alternative libraries to handle these specific features if you need them.
1102
+ ### 2. Unicode Length Validation
947
1103
 
948
- ### Unsupported Formats
1104
+ SchemaShield validates `minLength` and `maxLength` based on JavaScript's `length` property (UTF-16 code units), not Unicode Code Points.
949
1105
 
950
- #### Internationalized Formats
1106
+ - **Impact:** Emoji or surrogate pairs may be counted as length 2.
951
1107
 
952
- There is no plan to support the following formats in SchemaShield, as they are not relevant to the majority of use cases. If you need to use these formats, consider using custom implementations using the `addFormat` method to handle them.
1108
+ ### 3. Conservative Equality Path (Performance Trade-off)
953
1109
 
954
- - `idn-email`
955
- - `idn-hostname`
956
- - `iri`
957
- - `iri-reference`
1110
+ For keywords like `enum`, `const`, and `uniqueItems`, SchemaShield prioritizes exact structural comparisons to preserve predictable behavior.
958
1111
 
959
- Also you can contribute to SchemaShield and add support for these keywords and formats or leve a comment requesting support for them.
1112
+ - **Impact:** For very large arrays or enums with many complex objects, this conservative path can be slower than aggressive hashing strategies.
1113
+ - **Future Option:** An opt-in aggressive mode based on structural hashing/bucketing could improve throughput in those extreme cases, but it is intentionally not enabled by default to avoid edge-case semantic divergence.
960
1114
 
961
1115
  ## Testing
962
1116
 
@@ -994,5 +1148,5 @@ We appreciate your interest in contributing to SchemaShield and look forward to
994
1148
 
995
1149
  ## Legal
996
1150
 
997
- Author: [Masquerade Circus](http://masquerade-circus.net).
1151
+ Author: [Masquerade Circus](http://masquerade-circus.net).
998
1152
  License [Apache-2.0](https://opensource.org/licenses/Apache-2.0)
@@ -1 +1 @@
1
- {"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../lib/formats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA+O1D,CAAC"}
1
+ {"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../lib/formats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA8TzC,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA4O1D,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { DefineErrorFunction, ValidationError } from "./utils";
2
- export { ValidationError } from "./utils";
3
- export { deepClone } from "./utils";
4
- export type Result = void | ValidationError;
1
+ /****************** Path: lib/index.ts ******************/
2
+ import { DefineErrorFunction, ValidationError } from "./utils/main-utils";
3
+ export { ValidationError } from "./utils/main-utils";
4
+ export { deepCloneUnfreeze as deepClone } from "./utils/deep-freeze";
5
+ export type Result = void | ValidationError | true;
5
6
  export interface KeywordFunction {
6
7
  (schema: CompiledSchema, data: any, defineError: DefineErrorFunction, instance: SchemaShield): Result;
7
8
  }
@@ -21,7 +22,7 @@ export interface CompiledSchema {
21
22
  export interface Validator {
22
23
  (data: any): {
23
24
  data: any;
24
- error: ValidationError | null;
25
+ error: ValidationError | null | true;
25
26
  valid: boolean;
26
27
  };
27
28
  compiledSchema: CompiledSchema;
@@ -31,17 +32,35 @@ export declare class SchemaShield {
31
32
  private formats;
32
33
  private keywords;
33
34
  private immutable;
34
- constructor({ immutable }?: {
35
+ private rootSchema;
36
+ private idRegistry;
37
+ private failFast;
38
+ constructor({ immutable, failFast }?: {
35
39
  immutable?: boolean;
40
+ failFast?: boolean;
36
41
  });
37
42
  addType(name: string, validator: TypeFunction, overwrite?: boolean): void;
38
43
  getType(type: string): TypeFunction | false;
39
44
  addFormat(name: string, validator: FormatFunction, overwrite?: boolean): void;
40
45
  getFormat(format: string): FormatFunction | false;
46
+ isDefaultFormatValidator(format: string, validator: FormatFunction): boolean;
41
47
  addKeyword(name: string, validator: KeywordFunction, overwrite?: boolean): void;
42
48
  getKeyword(keyword: string): KeywordFunction | false;
49
+ getSchemaRef(path: string): CompiledSchema | undefined;
50
+ getSchemaById(id: string): CompiledSchema | undefined;
43
51
  compile(schema: any): Validator;
52
+ private isPlainObject;
53
+ private isTrivialAlwaysValidSubschema;
54
+ private shallowArrayEquals;
55
+ private flattenAssociativeBranches;
56
+ private flattenSingleWrapperOneOf;
57
+ private normalizeSchemaForCompile;
58
+ private markSchemaHasRef;
59
+ private shouldSkipKeyword;
60
+ private hasRequiredDefaults;
61
+ private isDefaultTypeValidator;
44
62
  private compileSchema;
45
63
  isSchemaLike(subSchema: any): boolean;
64
+ private linkReferences;
46
65
  }
47
66
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,eAAe,EAKhB,MAAM,SAAS,CAAC;AAMjB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,eAAe,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,CACE,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,mBAAmB,EAChC,QAAQ,EAAE,YAAY,GACrB,MAAM,CAAC;CACX;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,IAAI,EAAE,GAAG,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1E,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,OAAO,CAA8C;IAC7D,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,SAAS,CAAS;gBAEd,EACV,SAAiB,EAClB,GAAE;QACD,SAAS,CAAC,EAAE,OAAO,CAAC;KAChB;IAoBN,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,UAAQ;IAOhE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,KAAK;IAI3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,UAAQ;IAOpE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK;IAIjD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,SAAS,UAAQ;IAOtE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,KAAK;IAIpD,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS;IA6B/B,OAAO,CAAC,aAAa;IA0IrB,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO;CActC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"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"}