@hyperjump/json-schema 1.16.5 → 1.17.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 (61) hide show
  1. package/README.md +99 -11
  2. package/annotations/annotated-instance.js +1 -1
  3. package/draft-04/format.js +31 -0
  4. package/draft-04/index.js +3 -1
  5. package/draft-06/format.js +34 -0
  6. package/draft-06/index.js +3 -1
  7. package/draft-07/format.js +42 -0
  8. package/draft-07/index.js +3 -1
  9. package/draft-2019-09/format-assertion.js +44 -0
  10. package/draft-2019-09/format.js +44 -0
  11. package/draft-2019-09/index.js +5 -1
  12. package/draft-2020-12/format-assertion.js +43 -0
  13. package/draft-2020-12/format.js +44 -0
  14. package/draft-2020-12/index.js +6 -2
  15. package/formats/handlers/date-time.js +7 -0
  16. package/formats/handlers/date.js +7 -0
  17. package/formats/handlers/draft-04/hostname.js +7 -0
  18. package/formats/handlers/duration.js +7 -0
  19. package/formats/handlers/email.js +7 -0
  20. package/formats/handlers/hostname.js +7 -0
  21. package/formats/handlers/idn-email.js +7 -0
  22. package/formats/handlers/idn-hostname.js +7 -0
  23. package/formats/handlers/ipv4.js +7 -0
  24. package/formats/handlers/ipv6.js +7 -0
  25. package/formats/handlers/iri-reference.js +7 -0
  26. package/formats/handlers/iri.js +7 -0
  27. package/formats/handlers/json-pointer.js +7 -0
  28. package/formats/handlers/regex.js +7 -0
  29. package/formats/handlers/relative-json-pointer.js +7 -0
  30. package/formats/handlers/time.js +7 -0
  31. package/formats/handlers/uri-reference.js +7 -0
  32. package/formats/handlers/uri-template.js +7 -0
  33. package/formats/handlers/uri.js +7 -0
  34. package/formats/handlers/uuid.js +7 -0
  35. package/formats/index.js +11 -0
  36. package/formats/lite.js +38 -0
  37. package/lib/configuration.js +7 -2
  38. package/lib/experimental.d.ts +11 -2
  39. package/lib/experimental.js +1 -0
  40. package/lib/index.d.ts +2 -0
  41. package/lib/index.js +3 -1
  42. package/lib/keywords/dynamicRef.js +1 -1
  43. package/lib/keywords/format.js +35 -2
  44. package/lib/keywords.js +25 -3
  45. package/openapi-3-0/index.js +1 -1
  46. package/package.json +8 -5
  47. package/v1/extension-tests/conditional.json +289 -0
  48. package/v1/extension-tests/itemPattern.json +462 -0
  49. package/{stable → v1}/index.d.ts +2 -2
  50. package/{stable → v1}/index.js +25 -30
  51. package/{stable → v1}/meta/applicator.js +1 -3
  52. package/{stable → v1}/meta/content.js +1 -3
  53. package/{stable → v1}/meta/core.js +5 -4
  54. package/v1/meta/format.js +8 -0
  55. package/{stable → v1}/meta/meta-data.js +1 -3
  56. package/{stable → v1}/meta/unevaluated.js +1 -3
  57. package/{stable → v1}/meta/validation.js +1 -3
  58. package/v1/schema.js +24 -0
  59. package/stable/meta/format-annotation.js +0 -10
  60. package/stable/meta/format-assertion.js +0 -10
  61. package/stable/validation.js +0 -24
package/README.md CHANGED
@@ -4,18 +4,19 @@ A collection of modules for working with JSON Schemas.
4
4
 
5
5
  * Validate JSON-compatible values against a JSON Schemas
6
6
  * Dialects: draft-2020-12, draft-2019-09, draft-07, draft-06, draft-04
7
+ * Complete validation support for all formats defined for the `format` keyword
7
8
  * Schemas can reference other schemas using a different dialect
8
9
  * Work directly with schemas on the filesystem or HTTP
9
10
  * OpenAPI
10
11
  * Versions: 3.0, 3.1, 3.2
11
12
  * Validate an OpenAPI document
12
13
  * Validate values against a schema from an OpenAPI document
13
- * Create custom keywords, vocabularies, and dialects
14
+ * Create custom keywords, formats, vocabularies, and dialects
14
15
  * Bundle multiple schemas into one document
15
16
  * Uses the process defined in the 2020-12 specification but works with any
16
17
  dialect.
17
- * Utilities for building non-validation JSON Schema tooling
18
- * Utilities for working with annotations
18
+ * API for building non-validation JSON Schema tooling
19
+ * API for working with annotations
19
20
 
20
21
  ## Install
21
22
 
@@ -68,8 +69,8 @@ import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
68
69
  import "@hyperjump/json-schema/draft-07";
69
70
  ```
70
71
 
71
- **Note**: The default export (`@hyperjump/json-schema`) is reserved for the
72
- stable version of JSON Schema that will hopefully be released in near future.
72
+ **Note**: The default export (`@hyperjump/json-schema`) is reserved for v1 of
73
+ JSON Schema that will hopefully be released in near future.
73
74
 
74
75
  **Validate schema from JavaScript**
75
76
 
@@ -98,7 +99,7 @@ const output1 = isString("foo");
98
99
  const output2 = isString(42);
99
100
  ```
100
101
 
101
- **Fetching schemas**
102
+ **File-based and web-based schemas**
102
103
 
103
104
  Schemas that are available on the web can be loaded automatically without
104
105
  needing to load them manually.
@@ -130,15 +131,42 @@ You can add/modify/remove support for any URI scheme using the [plugin
130
131
  system](https://github.com/hyperjump-io/browser/#uri-schemes) provided by
131
132
  `@hyperjump/browser`.
132
133
 
134
+ **Format**
135
+
136
+ Format validation support needs to be explicitly loaded by importing
137
+ `@hyperjump/json-schema/formats`. Once loaded, it depends on the dialect whether
138
+ validation is enabled by default or not. You should explicitly enable/disable it
139
+ with the `setShouldValidateFormat` function.
140
+
141
+ The `hostname`, `idn-hostname`, and `idn-email` validators are fairly large. If
142
+ you don't need support for those formats and bundle size is a concern, you can
143
+ use `@hyperjump/json-schema/formats-lite` instead to leave out support for those
144
+ formats.
145
+
146
+ ```javascript
147
+ import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
148
+ import { setShouldValidateFormat } from "@hyperjump/json-schema/formats";
149
+
150
+ const schemaUri = "https://example.com/number";
151
+ registerSchema({
152
+ "type": "string",
153
+ "format": "date"
154
+ }, schemaUri);
155
+
156
+ setShouldValidateFormat(true);
157
+ const output = await validate(schemaUri, "Feb 29, 2031"); // { valid: false }
158
+ ```
159
+
133
160
  **OpenAPI**
134
161
 
135
- The OpenAPI 3.0 and 3.1 and 3.2 meta-schemas are pre-loaded and the OpenAPI JSON Schema
136
- dialects for each of those versions is supported. A document with a Content-Type
137
- of `application/openapi+json` (web) or a file extension of `openapi.json`
138
- (filesystem) is understood as an OpenAPI document.
162
+ The OpenAPI 3.0 and 3.1 and 3.2 meta-schemas are pre-loaded and the OpenAPI JSON
163
+ Schema dialects for each of those versions is supported. A document with a
164
+ Content-Type of `application/openapi+json` (web) or a file extension of
165
+ `openapi.json` (filesystem) is understood as an OpenAPI document.
139
166
 
140
167
  Use the pattern `@hyperjump/json-schema/*` to import the version you need. The
141
- available versions are `openapi-3-0` for 3.0, `openapi-3-1` for 3.1, and `openapi-3-2` for 3.2.
168
+ available versions are `openapi-3-0` for 3.0, `openapi-3-1` for 3.1, and
169
+ `openapi-3-2` for 3.2.
142
170
 
143
171
  ```javascript
144
172
  import { validate } from "@hyperjump/json-schema/openapi-3-2";
@@ -472,6 +500,47 @@ registerSchema({
472
500
  const output = await validate("https://example.com/schema1", 42);
473
501
  ```
474
502
 
503
+ ### Custom Formats
504
+
505
+ Custom formats work similarly to keywords. You define a format handler and then
506
+ associate that format handler with the format keyword that applies to the
507
+ dialects you're targeting.
508
+
509
+ ```JavaScript
510
+ import { registerSchema, validate, setShouldValidateFormat } from "@hyperjump/json-schema/draft-2020-12";
511
+ import { addFormat, setFormatHandler } from "@hyperjump/json-schema/experimental";
512
+
513
+ const isoDateFormatUri = "https://example.com/format/iso-8601-date";
514
+
515
+ // Add the iso-date format handler
516
+ addFormat({
517
+ id: isoDateFormatUri,
518
+ handler: (date) => new Date(date).toISOString() === date
519
+ });
520
+
521
+ // Add the "iso-date" format to the 2020-12 version of `format`
522
+ setFormatHandler("https://json-schema.org/keyword/draft-2020-12/format", "iso-date", isoDateFormatUri);
523
+ setFormatHandler("https://json-schema.org/keyword/draft-2020-12/format-assertion", "iso-date", isoDateFormatUri);
524
+
525
+ // Optional: Add the "iso-date" format to other dialects
526
+ setFormatHandler("https://json-schema.org/keyword/draft-2019-09/format", "iso-date", isoDateFormatUri);
527
+ setFormatHandler("https://json-schema.org/keyword/draft-2019-09/format-assertion", "iso-date", isoDateFormatUri);
528
+ setFormatHandler("https://json-schema.org/keyword/draft-07/format", "iso-date", isoDateFormatUri);
529
+ setFormatHandler("https://json-schema.org/keyword/draft-06/format", "iso-date", isoDateFormatUri);
530
+ setFormatHandler("https://json-schema.org/keyword/draft-04/format", "iso-date", isoDateFormatUri);
531
+
532
+ const schemaUri = "https://example.com/main";
533
+ registerSchema({
534
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
535
+
536
+ "type": "string",
537
+ "format": "iso-date"
538
+ }, schemaUri);
539
+
540
+ setShouldValidateFormat(true);
541
+ const output = await validate(schemaUri, "Feb 28, 2031"); // { valid: false }
542
+ ```
543
+
475
544
  ### Custom Meta Schema
476
545
 
477
546
  You can use a custom meta-schema to restrict users to a subset of JSON Schema
@@ -605,6 +674,25 @@ These are available from the `@hyperjump/json-schema/experimental` export.
605
674
  * **ValidationContext**: object
606
675
  * ast: AST
607
676
  * plugins: EvaluationPlugins[]
677
+ * **addFormat**: (formatHandler: Format) => void
678
+
679
+ Add a format handler.
680
+
681
+ * **Format**: object
682
+ * id: string
683
+
684
+ A URI that uniquely identifies the format. It should use a domain you
685
+ own to avoid conflict with keywords defined by others.
686
+ * handler: (value: any) => boolean
687
+
688
+ A function that takes the value and returns a boolean determining if
689
+ it passes validation for the format.
690
+ * **setFormatHandler**: (keywordUri: string, formatName: string, formatUri: string) => void
691
+
692
+ Add support for a format to the specified keyword.
693
+ * **removeFormatHandler**: (keywordUri, formatName) => void
694
+
695
+ Remove support for a format from the specified keyword.
608
696
  * **defineVocabulary**: (id: string, keywords: { [keyword: string]: string }) => void
609
697
 
610
698
  Define a vocabulary that maps keyword name to keyword URIs defined using
@@ -2,7 +2,7 @@ import * as Instance from "../lib/instance.js";
2
2
  import { getKeywordId } from "../lib/keywords.js";
3
3
 
4
4
 
5
- const defaultDialectId = "https://json-schema.org/validation";
5
+ const defaultDialectId = "https://json-schema.org/v1";
6
6
 
7
7
  export const annotation = (node, keyword, dialect = defaultDialectId) => {
8
8
  const keywordUri = getKeywordId(keyword, dialect);
@@ -0,0 +1,31 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-04/format";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (getShouldValidateFormat() === false) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "email": "https://json-schema.org/format/email",
25
+ "hostname": "https://json-schema.org/format/draft-04/hostname",
26
+ "ipv4": "https://json-schema.org/format/ipv4",
27
+ "ipv6": "https://json-schema.org/format/ipv6",
28
+ "uri": "https://json-schema.org/format/uri"
29
+ };
30
+
31
+ export default { id, compile, interpret, annotation, formats };
package/draft-04/index.js CHANGED
@@ -7,6 +7,7 @@ import exclusiveMaximum from "./exclusiveMaximum.js";
7
7
  import exclusiveMinimum from "./exclusiveMinimum.js";
8
8
  import id from "./id.js";
9
9
  import items from "./items.js";
10
+ import format from "./format.js";
10
11
  import maximum from "./maximum.js";
11
12
  import minimum from "./minimum.js";
12
13
  import ref from "./ref.js";
@@ -20,6 +21,7 @@ addKeyword(maximum);
20
21
  addKeyword(minimum);
21
22
  addKeyword(id);
22
23
  addKeyword(items);
24
+ addKeyword(format);
23
25
  addKeyword(ref);
24
26
 
25
27
  const jsonSchemaVersion = "http://json-schema.org/draft-04/schema";
@@ -38,7 +40,7 @@ defineVocabulary(jsonSchemaVersion, {
38
40
  "enum": "https://json-schema.org/keyword/enum",
39
41
  "exclusiveMaximum": "https://json-schema.org/keyword/draft-04/exclusiveMaximum",
40
42
  "exclusiveMinimum": "https://json-schema.org/keyword/draft-04/exclusiveMinimum",
41
- "format": "https://json-schema.org/keyword/format",
43
+ "format": "https://json-schema.org/keyword/draft-04/format",
42
44
  "items": "https://json-schema.org/keyword/draft-04/items",
43
45
  "maxItems": "https://json-schema.org/keyword/maxItems",
44
46
  "maxLength": "https://json-schema.org/keyword/maxLength",
@@ -0,0 +1,34 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-06/format";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (getShouldValidateFormat() === false) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "email": "https://json-schema.org/format/email",
25
+ "hostname": "https://json-schema.org/format/draft-04/hostname",
26
+ "ipv4": "https://json-schema.org/format/ipv4",
27
+ "ipv6": "https://json-schema.org/format/ipv6",
28
+ "uri": "https://json-schema.org/format/uri",
29
+ "uri-reference": "https://json-schema.org/format/uri-reference",
30
+ "uri-template": "https://json-schema.org/format/uri-template",
31
+ "json-pointer": "https://json-schema.org/format/json-pointer"
32
+ };
33
+
34
+ export default { id, compile, interpret, annotation, formats };
package/draft-06/index.js CHANGED
@@ -7,6 +7,7 @@ import contains from "./contains.js";
7
7
  import dependencies from "../draft-04/dependencies.js";
8
8
  import id from "../draft-04/id.js";
9
9
  import items from "../draft-04/items.js";
10
+ import format from "./format.js";
10
11
  import ref from "../draft-04/ref.js";
11
12
 
12
13
 
@@ -15,6 +16,7 @@ addKeyword(dependencies);
15
16
  addKeyword(contains);
16
17
  addKeyword(id);
17
18
  addKeyword(items);
19
+ addKeyword(format);
18
20
  addKeyword(ref);
19
21
 
20
22
  const jsonSchemaVersion = "http://json-schema.org/draft-06/schema";
@@ -36,7 +38,7 @@ defineVocabulary(jsonSchemaVersion, {
36
38
  "examples": "https://json-schema.org/keyword/examples",
37
39
  "exclusiveMaximum": "https://json-schema.org/keyword/exclusiveMaximum",
38
40
  "exclusiveMinimum": "https://json-schema.org/keyword/exclusiveMinimum",
39
- "format": "https://json-schema.org/keyword/format",
41
+ "format": "https://json-schema.org/keyword/draft-06/format",
40
42
  "items": "https://json-schema.org/keyword/draft-04/items",
41
43
  "maxItems": "https://json-schema.org/keyword/maxItems",
42
44
  "maxLength": "https://json-schema.org/keyword/maxLength",
@@ -0,0 +1,42 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-07/format";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (getShouldValidateFormat() === false) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "date": "https://json-schema.org/format/date",
25
+ "time": "https://json-schema.org/format/time",
26
+ "email": "https://json-schema.org/format/email",
27
+ "idn-email": "https://json-schema.org/format/idn-email",
28
+ "hostname": "https://json-schema.org/format/hostname",
29
+ "idn-hostname": "https://json-schema.org/format/idn-hostname",
30
+ "ipv4": "https://json-schema.org/format/ipv4",
31
+ "ipv6": "https://json-schema.org/format/ipv6",
32
+ "uri": "https://json-schema.org/format/uri",
33
+ "uri-reference": "https://json-schema.org/format/uri-reference",
34
+ "iri": "https://json-schema.org/format/iri",
35
+ "iri-reference": "https://json-schema.org/format/iri-reference",
36
+ "uri-template": "https://json-schema.org/format/uri-template",
37
+ "json-pointer": "https://json-schema.org/format/json-pointer",
38
+ "relative-json-pointer": "https://json-schema.org/format/relative-json-pointer",
39
+ "regex": "https://json-schema.org/format/regex"
40
+ };
41
+
42
+ export default { id, compile, interpret, annotation, formats };
package/draft-07/index.js CHANGED
@@ -7,6 +7,7 @@ import contains from "../draft-06/contains.js";
7
7
  import dependencies from "../draft-04/dependencies.js";
8
8
  import items from "../draft-04/items.js";
9
9
  import id from "../draft-04/id.js";
10
+ import format from "./format.js";
10
11
  import ref from "../draft-04/ref.js";
11
12
 
12
13
 
@@ -15,6 +16,7 @@ addKeyword(contains);
15
16
  addKeyword(dependencies);
16
17
  addKeyword(id);
17
18
  addKeyword(items);
19
+ addKeyword(format);
18
20
  addKeyword(ref);
19
21
 
20
22
  const jsonSchemaVersion = "http://json-schema.org/draft-07/schema";
@@ -39,7 +41,7 @@ defineVocabulary(jsonSchemaVersion, {
39
41
  "examples": "https://json-schema.org/keyword/examples",
40
42
  "exclusiveMaximum": "https://json-schema.org/keyword/exclusiveMaximum",
41
43
  "exclusiveMinimum": "https://json-schema.org/keyword/exclusiveMinimum",
42
- "format": "https://json-schema.org/keyword/format",
44
+ "format": "https://json-schema.org/keyword/draft-07/format",
43
45
  "if": "https://json-schema.org/keyword/if",
44
46
  "then": "https://json-schema.org/keyword/then",
45
47
  "else": "https://json-schema.org/keyword/else",
@@ -0,0 +1,44 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-2019-09/format-assertion";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (getShouldValidateFormat() === false) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "date": "https://json-schema.org/format/date",
25
+ "time": "https://json-schema.org/format/time",
26
+ "duration": "https://json-schema.org/format/duration",
27
+ "email": "https://json-schema.org/format/email",
28
+ "idn-email": "https://json-schema.org/format/idn-email",
29
+ "hostname": "https://json-schema.org/format/hostname",
30
+ "idn-hostname": "https://json-schema.org/format/idn-hostname",
31
+ "ipv4": "https://json-schema.org/format/ipv4",
32
+ "ipv6": "https://json-schema.org/format/ipv6",
33
+ "uri": "https://json-schema.org/format/uri",
34
+ "uri-reference": "https://json-schema.org/format/uri-reference",
35
+ "iri": "https://json-schema.org/format/iri",
36
+ "iri-reference": "https://json-schema.org/format/iri-reference",
37
+ "uuid": "https://json-schema.org/format/uuid",
38
+ "uri-template": "https://json-schema.org/format/uri-template",
39
+ "json-pointer": "https://json-schema.org/format/json-pointer",
40
+ "relative-json-pointer": "https://json-schema.org/format/relative-json-pointer",
41
+ "regex": "https://json-schema.org/format/regex"
42
+ };
43
+
44
+ export default { id, compile, interpret, annotation, formats };
@@ -0,0 +1,44 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-2019-09/format";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (!getShouldValidateFormat()) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "date": "https://json-schema.org/format/date",
25
+ "time": "https://json-schema.org/format/time",
26
+ "duration": "https://json-schema.org/format/duration",
27
+ "email": "https://json-schema.org/format/email",
28
+ "idn-email": "https://json-schema.org/format/idn-email",
29
+ "hostname": "https://json-schema.org/format/hostname",
30
+ "idn-hostname": "https://json-schema.org/format/idn-hostname",
31
+ "ipv4": "https://json-schema.org/format/ipv4",
32
+ "ipv6": "https://json-schema.org/format/ipv6",
33
+ "uri": "https://json-schema.org/format/uri",
34
+ "uri-reference": "https://json-schema.org/format/uri-reference",
35
+ "iri": "https://json-schema.org/format/iri",
36
+ "iri-reference": "https://json-schema.org/format/iri-reference",
37
+ "uuid": "https://json-schema.org/format/uuid",
38
+ "uri-template": "https://json-schema.org/format/uri-template",
39
+ "json-pointer": "https://json-schema.org/format/json-pointer",
40
+ "relative-json-pointer": "https://json-schema.org/format/relative-json-pointer",
41
+ "regex": "https://json-schema.org/format/regex"
42
+ };
43
+
44
+ export default { id, compile, interpret, annotation, formats };
@@ -11,12 +11,16 @@ import contentMetaSchema from "./meta/content.js";
11
11
 
12
12
  import additionalItems from "../draft-04/additionalItems.js";
13
13
  import items from "../draft-04/items.js";
14
+ import formatAssertion from "./format-assertion.js";
15
+ import format from "./format.js";
14
16
  import recursiveAnchor from "./recursiveAnchor.js";
15
17
  import recursiveRef from "../draft-2020-12/dynamicRef.js";
16
18
 
17
19
 
18
20
  addKeyword(additionalItems);
19
21
  addKeyword(items);
22
+ addKeyword(formatAssertion);
23
+ addKeyword(format);
20
24
  addKeyword(recursiveAnchor);
21
25
  addKeyword(recursiveRef);
22
26
 
@@ -85,7 +89,7 @@ defineVocabulary("https://json-schema.org/draft/2019-09/vocab/meta-data", {
85
89
  });
86
90
 
87
91
  defineVocabulary("https://json-schema.org/draft/2019-09/vocab/format", {
88
- "format": "https://json-schema.org/keyword/format"
92
+ "format": "https://json-schema.org/keyword/draft-2019-09/format-assertion"
89
93
  });
90
94
 
91
95
  defineVocabulary("https://json-schema.org/draft/2019-09/vocab/content", {
@@ -0,0 +1,43 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getFormatHandler } from "../lib/keywords.js";
4
+
5
+
6
+ const id = "https://json-schema.org/keyword/draft-2020-12/format-assertion";
7
+
8
+ const compile = (schema) => Browser.value(schema);
9
+
10
+ const interpret = (format, instance) => {
11
+ const handler = getFormatHandler(formats[format]);
12
+ if (!handler) {
13
+ throw Error(`The '${format}' format is not supported.`);
14
+ }
15
+
16
+ return handler(Instance.value(instance));
17
+ };
18
+
19
+ const annotation = (format) => format;
20
+
21
+ const formats = {
22
+ "date-time": "https://json-schema.org/format/date-time",
23
+ "date": "https://json-schema.org/format/date",
24
+ "time": "https://json-schema.org/format/time",
25
+ "duration": "https://json-schema.org/format/duration",
26
+ "email": "https://json-schema.org/format/email",
27
+ "idn-email": "https://json-schema.org/format/idn-email",
28
+ "hostname": "https://json-schema.org/format/hostname",
29
+ "idn-hostname": "https://json-schema.org/format/idn-hostname",
30
+ "ipv4": "https://json-schema.org/format/ipv4",
31
+ "ipv6": "https://json-schema.org/format/ipv6",
32
+ "uri": "https://json-schema.org/format/uri",
33
+ "uri-reference": "https://json-schema.org/format/uri-reference",
34
+ "iri": "https://json-schema.org/format/iri",
35
+ "iri-reference": "https://json-schema.org/format/iri-reference",
36
+ "uuid": "https://json-schema.org/format/uuid",
37
+ "uri-template": "https://json-schema.org/format/uri-template",
38
+ "json-pointer": "https://json-schema.org/format/json-pointer",
39
+ "relative-json-pointer": "https://json-schema.org/format/relative-json-pointer",
40
+ "regex": "https://json-schema.org/format/regex"
41
+ };
42
+
43
+ export default { id, compile, interpret, annotation, formats };
@@ -0,0 +1,44 @@
1
+ import * as Browser from "@hyperjump/browser";
2
+ import * as Instance from "../lib/instance.js";
3
+ import { getShouldValidateFormat } from "../lib/configuration.js";
4
+ import { getFormatHandler } from "../lib/keywords.js";
5
+
6
+
7
+ const id = "https://json-schema.org/keyword/draft-2020-12/format";
8
+
9
+ const compile = (schema) => Browser.value(schema);
10
+
11
+ const interpret = (format, instance) => {
12
+ if (!getShouldValidateFormat()) {
13
+ return true;
14
+ }
15
+
16
+ const handler = getFormatHandler(formats[format]);
17
+ return handler?.(Instance.value(instance)) ?? true;
18
+ };
19
+
20
+ const annotation = (format) => format;
21
+
22
+ const formats = {
23
+ "date-time": "https://json-schema.org/format/date-time",
24
+ "date": "https://json-schema.org/format/date",
25
+ "time": "https://json-schema.org/format/time",
26
+ "duration": "https://json-schema.org/format/duration",
27
+ "email": "https://json-schema.org/format/email",
28
+ "idn-email": "https://json-schema.org/format/idn-email",
29
+ "hostname": "https://json-schema.org/format/hostname",
30
+ "idn-hostname": "https://json-schema.org/format/idn-hostname",
31
+ "ipv4": "https://json-schema.org/format/ipv4",
32
+ "ipv6": "https://json-schema.org/format/ipv6",
33
+ "uri": "https://json-schema.org/format/uri",
34
+ "uri-reference": "https://json-schema.org/format/uri-reference",
35
+ "iri": "https://json-schema.org/format/iri",
36
+ "iri-reference": "https://json-schema.org/format/iri-reference",
37
+ "uuid": "https://json-schema.org/format/uuid",
38
+ "uri-template": "https://json-schema.org/format/uri-template",
39
+ "json-pointer": "https://json-schema.org/format/json-pointer",
40
+ "relative-json-pointer": "https://json-schema.org/format/relative-json-pointer",
41
+ "regex": "https://json-schema.org/format/regex"
42
+ };
43
+
44
+ export default { id, compile, interpret, annotation, formats };
@@ -13,10 +13,14 @@ import unevaluatedMetaSchema from "./meta/unevaluated.js";
13
13
 
14
14
  import dynamicAnchor from "./dynamicAnchor.js";
15
15
  import dynamicRef from "./dynamicRef.js";
16
+ import format from "./format.js";
17
+ import formatAssertion from "./format-assertion.js";
16
18
 
17
19
 
18
20
  addKeyword(dynamicRef);
19
21
  addKeyword(dynamicAnchor);
22
+ addKeyword(format);
23
+ addKeyword(formatAssertion);
20
24
 
21
25
  defineVocabulary("https://json-schema.org/draft/2020-12/vocab/core", {
22
26
  "$anchor": "https://json-schema.org/keyword/anchor",
@@ -81,11 +85,11 @@ defineVocabulary("https://json-schema.org/draft/2020-12/vocab/meta-data", {
81
85
  });
82
86
 
83
87
  defineVocabulary("https://json-schema.org/draft/2020-12/vocab/format-annotation", {
84
- "format": "https://json-schema.org/keyword/format"
88
+ "format": "https://json-schema.org/keyword/draft-2020-12/format"
85
89
  });
86
90
 
87
91
  defineVocabulary("https://json-schema.org/draft/2020-12/vocab/format-assertion", {
88
- "format": "https://json-schema.org/keyword/format-assertion"
92
+ "format": "https://json-schema.org/keyword/draft-2020-12/format-assertion"
89
93
  });
90
94
 
91
95
  defineVocabulary("https://json-schema.org/draft/2020-12/vocab/content", {
@@ -0,0 +1,7 @@
1
+ import { isDateTime } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/date-time",
6
+ handler: (dateTime) => typeof dateTime !== "string" || isDateTime(dateTime)
7
+ };
@@ -0,0 +1,7 @@
1
+ import { isDate } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/date",
6
+ handler: (date) => typeof date !== "string" || isDate(date)
7
+ };
@@ -0,0 +1,7 @@
1
+ import { isAsciiIdn } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/draft-04/hostname",
6
+ handler: (hostname) => typeof hostname !== "string" || isAsciiIdn(hostname)
7
+ };
@@ -0,0 +1,7 @@
1
+ import { isDuration } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/duration",
6
+ handler: (duration) => typeof duration !== "string" || isDuration(duration)
7
+ };
@@ -0,0 +1,7 @@
1
+ import { isEmail } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/email",
6
+ handler: (email) => typeof email !== "string" || isEmail(email)
7
+ };
@@ -0,0 +1,7 @@
1
+ import { isAsciiIdn } from "@hyperjump/json-schema-formats";
2
+
3
+
4
+ export default {
5
+ id: "https://json-schema.org/format/hostname",
6
+ handler: (hostname) => typeof hostname !== "string" || isAsciiIdn(hostname)
7
+ };