@hyperjump/json-schema 1.6.7 → 1.7.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.
Files changed (104) hide show
  1. package/README.md +247 -255
  2. package/annotations/annotated-instance.js +3 -3
  3. package/annotations/index.d.ts +7 -1
  4. package/annotations/index.js +3 -3
  5. package/bundle/index.d.ts +1 -5
  6. package/bundle/index.js +112 -156
  7. package/draft-04/additionalItems.js +6 -7
  8. package/draft-04/dependencies.js +5 -5
  9. package/draft-04/index.js +2 -2
  10. package/draft-04/items.js +5 -5
  11. package/draft-04/maximum.js +8 -8
  12. package/draft-04/minimum.js +8 -8
  13. package/draft-06/contains.js +2 -2
  14. package/draft-06/index.js +3 -2
  15. package/draft-07/index.js +3 -2
  16. package/draft-2019-09/index.js +9 -11
  17. package/draft-2020-12/dynamicRef.js +5 -5
  18. package/draft-2020-12/index.js +11 -13
  19. package/lib/common.d.ts +1 -1
  20. package/lib/common.js +44 -60
  21. package/lib/configuration.js +0 -6
  22. package/lib/core.js +32 -30
  23. package/lib/experimental.d.ts +75 -5
  24. package/lib/experimental.js +2 -2
  25. package/lib/index.d.ts +43 -11
  26. package/lib/index.js +11 -11
  27. package/lib/instance.d.ts +1 -17
  28. package/lib/instance.js +3 -3
  29. package/lib/keywords/additionalProperties.js +12 -13
  30. package/lib/keywords/allOf.js +3 -3
  31. package/lib/keywords/anyOf.js +3 -3
  32. package/lib/keywords/conditional.js +6 -7
  33. package/lib/keywords/const.js +2 -2
  34. package/lib/keywords/contains.js +14 -35
  35. package/lib/keywords/contentSchema.js +1 -1
  36. package/lib/keywords/definitions.js +2 -2
  37. package/lib/keywords/dependentRequired.js +4 -4
  38. package/lib/keywords/dependentSchemas.js +5 -5
  39. package/lib/keywords/dynamicRef.js +10 -5
  40. package/lib/keywords/else.js +5 -6
  41. package/lib/keywords/enum.js +4 -4
  42. package/lib/keywords/exclusiveMaximum.js +3 -3
  43. package/lib/keywords/exclusiveMinimum.js +3 -3
  44. package/lib/keywords/if.js +1 -1
  45. package/lib/keywords/itemPattern.js +17 -14
  46. package/lib/keywords/items.js +6 -7
  47. package/lib/keywords/maxItems.js +3 -3
  48. package/lib/keywords/maxLength.js +3 -3
  49. package/lib/keywords/maxProperties.js +3 -3
  50. package/lib/keywords/maximum.js +3 -3
  51. package/lib/keywords/meta-data.js +1 -1
  52. package/lib/keywords/minItems.js +3 -3
  53. package/lib/keywords/minLength.js +3 -3
  54. package/lib/keywords/minProperties.js +3 -3
  55. package/lib/keywords/minimum.js +3 -3
  56. package/lib/keywords/multipleOf.js +3 -3
  57. package/lib/keywords/not.js +1 -1
  58. package/lib/keywords/oneOf.js +3 -3
  59. package/lib/keywords/pattern.js +3 -3
  60. package/lib/keywords/patternProperties.js +5 -5
  61. package/lib/keywords/prefixItems.js +5 -5
  62. package/lib/keywords/properties.js +5 -5
  63. package/lib/keywords/propertyDependencies.js +6 -7
  64. package/lib/keywords/propertyNames.js +2 -2
  65. package/lib/keywords/ref.js +2 -7
  66. package/lib/keywords/requireAllExcept.js +8 -9
  67. package/lib/keywords/required.js +3 -3
  68. package/lib/keywords/then.js +5 -5
  69. package/lib/keywords/type.js +9 -3
  70. package/lib/keywords/unevaluatedItems.js +4 -4
  71. package/lib/keywords/unevaluatedProperties.js +4 -5
  72. package/lib/keywords/uniqueItems.js +3 -3
  73. package/lib/keywords/validation.js +11 -23
  74. package/lib/keywords.js +27 -14
  75. package/lib/openapi.js +19 -6
  76. package/lib/schema.js +236 -227
  77. package/openapi-3-0/index.js +5 -5
  78. package/openapi-3-0/type.js +13 -7
  79. package/openapi-3-1/index.js +22 -21
  80. package/openapi-3-1/{schema-base/2022-10-07.js → schema-base.js} +12 -2
  81. package/openapi-3-1/schema-draft-04.js +33 -0
  82. package/openapi-3-1/schema-draft-06.js +33 -0
  83. package/openapi-3-1/schema-draft-07.js +33 -0
  84. package/openapi-3-1/schema-draft-2019-09.js +33 -0
  85. package/openapi-3-1/schema-draft-2020-12.js +33 -0
  86. package/package.json +11 -11
  87. package/stable/index.js +10 -10
  88. package/annotations/validation-error.d.ts +0 -8
  89. package/draft-2019-09/contains.js +0 -44
  90. package/lib/configuration.d.ts +0 -9
  91. package/lib/context-uri.browser.js +0 -1
  92. package/lib/context-uri.js +0 -4
  93. package/lib/core.d.ts +0 -48
  94. package/lib/fetch.browser.js +0 -1
  95. package/lib/fetch.js +0 -20
  96. package/lib/invalid-schema-error.d.ts +0 -8
  97. package/lib/keywords.d.ts +0 -19
  98. package/lib/media-types.d.ts +0 -11
  99. package/lib/media-types.js +0 -48
  100. package/lib/reference.d.ts +0 -11
  101. package/lib/reference.js +0 -11
  102. package/lib/schema.d.ts +0 -60
  103. /package/openapi-3-0/{schema/2021-09-28.js → schema.js} +0 -0
  104. /package/openapi-3-1/{schema/2022-10-07.js → schema.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { toAbsoluteUri } from "../lib/common.js";
1
+ import { toAbsoluteIri } from "@hyperjump/uri";
2
2
  import { nil as nilInstance, get } from "../lib/instance.js";
3
3
  import { getKeywordId } from "../lib/keywords.js";
4
4
 
@@ -8,13 +8,13 @@ const defaultDialectId = "https://json-schema.org/validation";
8
8
  export const nil = { ...nilInstance, annotations: {} };
9
9
  export const cons = (instance, id = undefined) => ({
10
10
  ...nil,
11
- id: id ? toAbsoluteUri(id) : "",
11
+ id: id ? toAbsoluteIri(id) : "",
12
12
  instance,
13
13
  value: instance
14
14
  });
15
15
 
16
16
  export const annotation = (instance, keyword, dialectId = defaultDialectId) => {
17
- const keywordId = getKeywordId(dialectId, keyword);
17
+ const keywordId = getKeywordId(keyword, dialectId);
18
18
  return instance.annotations[instance.pointer]?.[keywordId] || [];
19
19
  };
20
20
 
@@ -1,4 +1,4 @@
1
- import type { OutputFormat } from "../lib/core.js";
1
+ import type { OutputFormat, OutputUnit } from "../lib/index.js";
2
2
  import type { AnnotatedJsonDocument } from "./annotated-instance.js";
3
3
 
4
4
 
@@ -9,3 +9,9 @@ export const annotate: (
9
9
  );
10
10
 
11
11
  export type Annotator = (value: unknown, outputFormat?: OutputFormat) => AnnotatedJsonDocument;
12
+
13
+ export class ValidationError extends Error {
14
+ public output: OutputUnit;
15
+
16
+ public constructor(output: OutputUnit);
17
+ }
@@ -1,13 +1,13 @@
1
1
  import { subscribe, unsubscribe } from "../lib/pubsub.js";
2
- import { compile, interpret as validate, BASIC } from "../lib/core.js";
3
- import { getKeyword } from "../lib/keywords.js";
4
2
  import * as Instance from "./annotated-instance.js";
5
3
  import { ValidationError } from "./validation-error.js";
4
+ import { getSchema, getKeyword, compile, interpret as validate, BASIC } from "../lib/experimental.js";
6
5
 
7
6
 
8
7
  export const annotate = async (schemaUri, json = undefined, outputFormat = undefined) => {
9
8
  loadKeywordSupport();
10
- const compiled = await compile(schemaUri);
9
+ const schema = await getSchema(schemaUri);
10
+ const compiled = await compile(schema);
11
11
  const interpretAst = (json, outputFormat) => interpret(compiled, Instance.cons(json), outputFormat);
12
12
 
13
13
  return json === undefined ? interpretAst : interpretAst(json, outputFormat);
package/bundle/index.d.ts CHANGED
@@ -1,18 +1,14 @@
1
- import type { SchemaObject } from "../lib/schema.js";
1
+ import type { SchemaObject } from "../lib/index.js";
2
2
 
3
3
 
4
4
  export const bundle: <A = SchemaObject>(uri: string, options?: BundleOptions) => Promise<A>;
5
- export const FULL: "full";
6
- export const FLAT: "flat";
7
5
  export const URI: "uri";
8
6
  export const UUID: "uuid";
9
7
 
10
8
  export type BundleOptions = {
11
9
  alwaysIncludeDialect?: boolean;
12
- bundleMode?: BundleMode;
13
10
  definitionNamingStrategy?: DefinitionNamingStrategy;
14
11
  externalSchemas?: string[];
15
12
  };
16
13
 
17
- export type BundleMode = "full" | "flat";
18
14
  export type DefinitionNamingStrategy = "uri" | "uuid";
package/bundle/index.js CHANGED
@@ -1,18 +1,20 @@
1
+ import curry from "just-curry-it";
1
2
  import { v4 as uuid } from "uuid";
3
+ import * as Browser from "@hyperjump/browser";
2
4
  import * as JsonPointer from "@hyperjump/json-pointer";
3
- import { toAbsoluteUri } from "../lib/common.js";
4
- import { compile } from "../lib/core.js";
5
- import { getKeywordName, getKeyword } from "../lib/keywords.js";
6
- import Validation from "../lib/keywords/validation.js";
7
- import * as Schema from "../lib/schema.js";
5
+ import { asyncCollectSet, asyncFilter, asyncFlatten, asyncMap, pipe } from "@hyperjump/pact";
6
+ import { resolveUri } from "@hyperjump/uri";
7
+ import {
8
+ Validation,
9
+ canonicalUri, getSchema, toSchema,
10
+ getKeywordName, getKeyword, getKeywordByName
11
+ } from "../lib/experimental.js";
8
12
 
9
13
 
10
- export const FULL = "full", FLAT = "flat";
11
14
  export const URI = "uri", UUID = "uuid";
12
15
 
13
16
  const defaultOptions = {
14
17
  alwaysIncludeDialect: false,
15
- bundleMode: FLAT,
16
18
  definitionNamingStrategy: URI,
17
19
  externalSchemas: []
18
20
  };
@@ -21,30 +23,35 @@ export const bundle = async (url, options = {}) => {
21
23
  loadKeywordSupport();
22
24
  const fullOptions = { ...defaultOptions, ...options };
23
25
 
24
- const schemaDoc = await Schema.get(url);
25
- const externalIds = await collectExternalIds(url, fullOptions);
26
+ const mainSchema = await getSchema(url);
27
+ const contextUri = mainSchema.document.baseUri;
28
+ const contextDialectId = mainSchema.document.dialectId;
29
+ const bundled = toSchema(mainSchema);
26
30
 
27
- const bundled = Schema.toSchema(schemaDoc, {
28
- includeEmbedded: fullOptions.bundleMode === FULL
29
- });
31
+ const externalIds = await Validation.collectExternalIds(new Set(), mainSchema, mainSchema);
30
32
 
31
- const bundlingLocation = "/" + getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/definitions");
33
+ // Bundle
34
+ const bundlingLocation = "/" + getKeywordName(contextDialectId, "https://json-schema.org/keyword/definitions");
32
35
  if (JsonPointer.get(bundlingLocation, bundled) === undefined && externalIds.size > 0) {
33
36
  JsonPointer.assign(bundlingLocation, bundled, {});
34
37
  }
35
38
 
36
- for (const uri of externalIds.values()) {
37
- const externalSchema = await Schema.get(uri);
38
- const embeddedSchema = Schema.toSchema(externalSchema, {
39
- parentId: schemaDoc.id,
40
- parentDialect: fullOptions.alwaysIncludeDialect ? "" : schemaDoc.dialectId,
41
- includeEmbedded: fullOptions.bundleMode === FULL
39
+ for (const uri of externalIds) {
40
+ const externalSchema = await getSchema(uri);
41
+ const embeddedSchema = toSchema(externalSchema, {
42
+ selfIdentify: true,
43
+ contextUri: contextUri,
44
+ includeDialect: fullOptions.alwaysIncludeDialect ? "always" : "auto",
45
+ contextDialectId: contextDialectId
42
46
  });
43
47
  let id;
44
48
  if (fullOptions.definitionNamingStrategy === URI) {
45
- const idToken = getKeywordName(externalSchema.dialectId, "https://json-schema.org/keyword/id")
46
- || getKeywordName(externalSchema.dialectId, "https://json-schema.org/keyword/draft-04/id");
49
+ const idToken = getKeywordName(externalSchema.document.dialectId, "https://json-schema.org/keyword/id")
50
+ || getKeywordName(externalSchema.document.dialectId, "https://json-schema.org/keyword/draft-04/id");
47
51
  id = embeddedSchema[idToken];
52
+ if (id in JsonPointer.get(bundlingLocation, bundled)) {
53
+ id = resolveUri(id, contextUri);
54
+ }
48
55
  } else if (fullOptions.definitionNamingStrategy === UUID) {
49
56
  id = uuid();
50
57
  } else {
@@ -57,74 +64,76 @@ export const bundle = async (url, options = {}) => {
57
64
  return bundled;
58
65
  };
59
66
 
60
- const collectExternalIds = async (uri, options) => {
61
- const { ast, schemaUri } = await compile(uri);
62
- const subSchemaUris = new Set();
63
- Validation.collectExternalIds(schemaUri, subSchemaUris, ast, {});
64
- const externalIds = new Set([...subSchemaUris]
65
- .map(toAbsoluteUri)
66
- .filter((uri) => !options.externalSchemas.includes(uri)));
67
- externalIds.delete(toAbsoluteUri(schemaUri));
68
-
69
- return externalIds;
70
- };
71
-
72
- Validation.collectExternalIds = (schemaUri, externalIds, ast, dynamicAnchors) => {
73
- if (externalIds.has(schemaUri) || typeof ast[schemaUri] === "boolean") {
74
- return;
67
+ Validation.collectExternalIds = curry(async (visited, parentSchema, schema) => {
68
+ const uri = canonicalUri(schema);
69
+ if (visited.has(uri) || Browser.typeOf(schema) === "boolean") {
70
+ return new Set();
75
71
  }
76
- externalIds.add(schemaUri);
77
-
78
- const id = toAbsoluteUri(schemaUri);
79
- for (const [keywordId, , keywordValue] of ast[schemaUri]) {
80
- const keyword = getKeyword(keywordId);
81
72
 
82
- if (keyword.collectExternalIds) {
83
- keyword.collectExternalIds(keywordValue, externalIds, ast, {
84
- ...ast.metaData[id].dynamicAnchors, ...dynamicAnchors
85
- });
86
- }
73
+ visited.add(uri);
74
+
75
+ const externalIds = await pipe(
76
+ Browser.entries(schema),
77
+ asyncMap(async ([keyword, keywordSchema]) => {
78
+ const keywordHandler = getKeywordByName(keyword, schema.document.dialectId);
79
+
80
+ return "collectExternalIds" in keywordHandler
81
+ ? await keywordHandler.collectExternalIds(visited, schema, keywordSchema)
82
+ : new Set();
83
+ }),
84
+ asyncFlatten,
85
+ asyncCollectSet
86
+ );
87
+
88
+ if (parentSchema.document.baseUri !== schema.document.baseUri
89
+ && (!(schema.document.baseUri in parentSchema.document.embedded) || schema.document.baseUri in parentSchema._cache)
90
+ ) {
91
+ externalIds.add(schema.document.baseUri);
87
92
  }
88
- };
93
+
94
+ return externalIds;
95
+ });
96
+
97
+ const collectExternalIdsFromArrayOfSchemas = (visited, parentSchema, schema) => pipe(
98
+ Browser.iter(schema),
99
+ asyncMap(Validation.collectExternalIds(visited, parentSchema)),
100
+ asyncFlatten,
101
+ asyncCollectSet
102
+ );
103
+
104
+ const collectExternalIdsFromObjectOfSchemas = async (visited, parentSchema, schema) => pipe(
105
+ Browser.values(schema),
106
+ asyncMap(Validation.collectExternalIds(visited, parentSchema)),
107
+ asyncFlatten,
108
+ asyncCollectSet
109
+ );
89
110
 
90
111
  const loadKeywordSupport = () => {
91
112
  // Stable
92
113
 
93
114
  const additionalProperties = getKeyword("https://json-schema.org/keyword/additionalProperties");
94
115
  if (additionalProperties) {
95
- additionalProperties.collectExternalIds = ([, additionalProperties], externalIds, ast, dynamicAnchors) => {
96
- if (typeof additionalProperties === "string") {
97
- Validation.collectExternalIds(additionalProperties, externalIds, ast, dynamicAnchors);
98
- }
99
- };
116
+ additionalProperties.collectExternalIds = Validation.collectExternalIds;
100
117
  }
101
118
 
102
119
  const allOf = getKeyword("https://json-schema.org/keyword/allOf");
103
120
  if (allOf) {
104
- allOf.collectExternalIds = (allOf, externalIds, ast, dynamicAnchors) => {
105
- allOf.forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
106
- };
121
+ allOf.collectExternalIds = collectExternalIdsFromArrayOfSchemas;
107
122
  }
108
123
 
109
124
  const anyOf = getKeyword("https://json-schema.org/keyword/anyOf");
110
125
  if (anyOf) {
111
- anyOf.collectExternalIds = (anyOf, externalIds, ast, dynamicAnchors) => {
112
- anyOf.forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
113
- };
126
+ anyOf.collectExternalIds = collectExternalIdsFromArrayOfSchemas;
114
127
  }
115
128
 
116
129
  const contains = getKeyword("https://json-schema.org/keyword/contains");
117
130
  if (contains) {
118
- contains.collectExternalIds = ({ contains }, externalIds, ast, dynamicAnchors) => {
119
- Validation.collectExternalIds(contains, externalIds, ast, dynamicAnchors);
120
- };
131
+ contains.collectExternalIds = Validation.collectExternalIds;
121
132
  }
122
133
 
123
134
  const dependentSchemas = getKeyword("https://json-schema.org/keyword/dependentSchemas");
124
135
  if (dependentSchemas) {
125
- dependentSchemas.collectExternalIds = (dependentSchemas, externalIds, ast, dynamicAnchors) => {
126
- Object.values(dependentSchemas).forEach(([, schemaUri]) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
127
- };
136
+ dependentSchemas.collectExternalIds = collectExternalIdsFromObjectOfSchemas;
128
137
  }
129
138
 
130
139
  const if_ = getKeyword("https://json-schema.org/keyword/if");
@@ -134,23 +143,17 @@ const loadKeywordSupport = () => {
134
143
 
135
144
  const then = getKeyword("https://json-schema.org/keyword/then");
136
145
  if (then) {
137
- then.collectExternalIds = ([, then], externalIds, ast, dynamicAnchors) => {
138
- Validation.collectExternalIds(then, externalIds, ast, dynamicAnchors);
139
- };
146
+ then.collectExternalIds = Validation.collectExternalIds;
140
147
  }
141
148
 
142
149
  const else_ = getKeyword("https://json-schema.org/keyword/else");
143
150
  if (else_) {
144
- else_.collectExternalIds = ([, elseSchema], externalIds, ast, dynamicAnchors) => {
145
- Validation.collectExternalIds(elseSchema, externalIds, ast, dynamicAnchors);
146
- };
151
+ else_.collectExternalIds = Validation.collectExternalIds;
147
152
  }
148
153
 
149
154
  const items = getKeyword("https://json-schema.org/keyword/items");
150
155
  if (items) {
151
- items.collectExternalIds = ([, items], externalIds, ast, dynamicAnchors) => {
152
- Validation.collectExternalIds(items, externalIds, ast, dynamicAnchors);
153
- };
156
+ items.collectExternalIds = Validation.collectExternalIds;
154
157
  }
155
158
 
156
159
  const not = getKeyword("https://json-schema.org/keyword/not");
@@ -160,30 +163,22 @@ const loadKeywordSupport = () => {
160
163
 
161
164
  const oneOf = getKeyword("https://json-schema.org/keyword/oneOf");
162
165
  if (oneOf) {
163
- oneOf.collectExternalIds = (oneOf, externalIds, ast, dynamicAnchors) => {
164
- oneOf.forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
165
- };
166
+ oneOf.collectExternalIds = collectExternalIdsFromArrayOfSchemas;
166
167
  }
167
168
 
168
169
  const patternProperties = getKeyword("https://json-schema.org/keyword/patternProperties");
169
170
  if (patternProperties) {
170
- patternProperties.collectExternalIds = (patternProperties, externalIds, ast, dynamicAnchors) => {
171
- patternProperties.forEach(([, schemaUri]) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
172
- };
171
+ patternProperties.collectExternalIds = collectExternalIdsFromObjectOfSchemas;
173
172
  }
174
173
 
175
174
  const prefixItems = getKeyword("https://json-schema.org/keyword/prefixItems");
176
175
  if (prefixItems) {
177
- prefixItems.collectExternalIds = (tupleItems, externalIds, ast, dynamicAnchors) => {
178
- tupleItems.forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
179
- };
176
+ prefixItems.collectExternalIds = collectExternalIdsFromArrayOfSchemas;
180
177
  }
181
178
 
182
179
  const properties = getKeyword("https://json-schema.org/keyword/properties");
183
180
  if (properties) {
184
- properties.collectExternalIds = (properties, externalIds, ast, dynamicAnchors) => {
185
- Object.values(properties).forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
186
- };
181
+ properties.collectExternalIds = collectExternalIdsFromObjectOfSchemas;
187
182
  }
188
183
 
189
184
  const propertyNames = getKeyword("https://json-schema.org/keyword/propertyNames");
@@ -198,119 +193,80 @@ const loadKeywordSupport = () => {
198
193
 
199
194
  const unevaluatedItems = getKeyword("https://json-schema.org/keyword/unevaluatedItems");
200
195
  if (unevaluatedItems) {
201
- unevaluatedItems.collectExternalIds = ([, unevaluatedItems], externalIds, ast, dynamicAnchors) => {
202
- Validation.collectExternalIds(unevaluatedItems, externalIds, ast, dynamicAnchors);
203
- };
196
+ unevaluatedItems.collectExternalIds = Validation.collectExternalIds;
204
197
  }
205
198
 
206
199
  const unevaluatedProperties = getKeyword("https://json-schema.org/keyword/unevaluatedProperties");
207
200
  if (unevaluatedProperties) {
208
- unevaluatedProperties.collectExternalIds = ([, unevaluatedProperties], externalIds, ast, dynamicAnchors) => {
209
- Validation.collectExternalIds(unevaluatedProperties, externalIds, ast, dynamicAnchors);
210
- };
201
+ unevaluatedProperties.collectExternalIds = Validation.collectExternalIds;
211
202
  }
212
203
 
213
204
  // Draft-04
214
205
 
215
206
  const additionalItems4 = getKeyword("https://json-schema.org/keyword/draft-04/additionalItems");
216
207
  if (additionalItems4) {
217
- additionalItems4.collectExternalIds = ([, additionalItems], externalIds, ast, dynamicAnchors) => {
218
- if (typeof additionalItems === "string") {
219
- Validation.collectExternalIds(additionalItems, externalIds, ast, dynamicAnchors);
220
- }
221
- };
208
+ additionalItems4.collectExternalIds = Validation.collectExternalIds;
222
209
  }
223
210
 
224
211
  const dependencies = getKeyword("https://json-schema.org/keyword/draft-04/dependencies");
225
212
  if (dependencies) {
226
- dependencies.collectExternalIds = (dependencies, externalIds, ast, dynamicAnchors) => {
227
- Object.values(dependencies).forEach(([, dependency]) => {
228
- if (typeof dependency === "string") {
229
- Validation.collectExternalIds(dependency, externalIds, ast, dynamicAnchors);
230
- }
231
- });
232
- };
213
+ dependencies.collectExternalIds = (visited, parentSchema, schema) => pipe(
214
+ Browser.values(schema),
215
+ asyncFilter((subSchema) => Browser.typeOf(subSchema) === "object"),
216
+ asyncMap(Validation.collectExternalIds(visited, parentSchema)),
217
+ asyncFlatten,
218
+ asyncCollectSet
219
+ );
233
220
  }
234
221
 
235
222
  const items4 = getKeyword("https://json-schema.org/keyword/draft-04/items");
236
223
  if (items4) {
237
- items4.collectExternalIds = (items, externalIds, ast, dynamicAnchors) => {
238
- if (typeof items === "string") {
239
- Validation.collectExternalIds(items, externalIds, ast, dynamicAnchors);
240
- } else {
241
- items.forEach((schemaUri) => Validation.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
242
- }
243
- };
244
- }
245
-
246
- const ref4 = getKeyword("https://json-schema.org/keyword/draft-04/ref");
247
- if (ref4) {
248
- ref4.collectExternalIds = Validation.collectExternalIds;
224
+ items4.collectExternalIds = (visited, parentSchema, schema) => Browser.typeOf(schema) === "array"
225
+ ? collectExternalIdsFromArrayOfSchemas(visited, parentSchema, schema)
226
+ : Validation.collectExternalIds(visited, parentSchema, schema);
249
227
  }
250
228
 
251
229
  // Draft-06
252
230
 
253
231
  const contains6 = getKeyword("https://json-schema.org/keyword/draft-06/contains");
254
232
  if (contains6) {
255
- contains6.collectExternalIds = (contains, externalIds, ast, dynamicAnchors) => {
256
- Validation.collectExternalIds(contains, externalIds, ast, dynamicAnchors);
257
- };
233
+ contains6.collectExternalIds = Validation.collectExternalIds;
258
234
  }
259
235
 
260
236
  // Draft-2019-09
261
237
 
262
238
  const contains19 = getKeyword("https://json-schema.org/keyword/draft-2019-09/contains");
263
239
  if (contains19) {
264
- contains19.collectExternalIds = ({ contains }, externalIds, ast, dynamicAnchors) => {
265
- Validation.collectExternalIds(contains, externalIds, ast, dynamicAnchors);
266
- };
240
+ contains19.collectExternalIds = Validation.collectExternalIds;
267
241
  }
268
242
 
269
- // Experimental
243
+ // Extensions
270
244
 
271
245
  const propertyDependencies = getKeyword("https://json-schema.org/keyword/propertyDependencies");
272
246
  if (propertyDependencies) {
273
- propertyDependencies.collectExternalIds = (propertyDependencies, externalIds, ast, dynamicAnchors) => {
274
- for (const key in propertyDependencies) {
275
- for (const value in propertyDependencies[key]) {
276
- Validation.collectExternalIds(propertyDependencies[key][value], externalIds, ast, dynamicAnchors);
277
- }
278
- }
279
- };
247
+ propertyDependencies.collectExternalIds = (visited, parentSchema, schema) => pipe(
248
+ Browser.values(schema),
249
+ asyncMap((mapping) => Browser.values(mapping)),
250
+ asyncFlatten,
251
+ asyncMap(Validation.collectExternalIds(visited, parentSchema)),
252
+ asyncFlatten,
253
+ asyncCollectSet
254
+ );
280
255
  }
281
256
 
282
257
  const conditional = getKeyword("https://json-schema.org/keyword/conditional");
283
258
  if (conditional) {
284
- conditional.collectExternalIds = (conditional, externalIds, ast, dynamicAnchors) => {
285
- for (const schema of conditional) {
286
- Validation.collectExternalIds(schema, externalIds, ast, dynamicAnchors);
287
- }
288
- };
259
+ conditional.collectExternalIds = collectExternalIdsFromArrayOfSchemas;
289
260
  }
290
261
 
291
262
  const itemPattern = getKeyword("https://json-schema.org/keyword/itemPattern");
292
263
  if (itemPattern) {
293
- itemPattern.collectExternalIds = (nfa, externalIds, ast, dynamicAnchors) => {
294
- for (const itemSchema of collectNfaSchemas(nfa.start)) {
295
- Validation.collectExternalIds(itemSchema, externalIds, ast, dynamicAnchors);
296
- }
297
- };
264
+ itemPattern.collectExternalIds = (visited, parentSchema, schema) => pipe(
265
+ Browser.iter(schema),
266
+ asyncFilter((item) => Browser.typeOf(item) === "object"),
267
+ asyncMap(Validation.collectExternalIds(visited, parentSchema)),
268
+ asyncFlatten,
269
+ asyncCollectSet
270
+ );
298
271
  }
299
-
300
- const collectNfaSchemas = function* (node, visited = new Set()) {
301
- if (visited.has(node)) {
302
- return;
303
- }
304
-
305
- visited.add(node);
306
-
307
- for (const schema in node.transition) {
308
- yield schema;
309
- yield* collectNfaSchemas(node.transition[schema], visited);
310
- }
311
-
312
- for (const epsilon of node.epsilonTransitions) {
313
- yield* collectNfaSchemas(epsilon, visited);
314
- }
315
- };
316
272
  };
@@ -1,22 +1,21 @@
1
1
  import { pipe, drop, every } from "@hyperjump/pact";
2
+ import * as Browser from "@hyperjump/browser";
2
3
  import * as Instance from "../lib/instance.js";
3
- import * as Schema from "../lib/schema.js";
4
- import Validation from "../lib/keywords/validation.js";
5
- import { getKeywordName } from "../lib/keywords.js";
4
+ import { getKeywordName, Validation } from "../lib/experimental.js";
6
5
 
7
6
 
8
7
  const id = "https://json-schema.org/keyword/draft-04/additionalItems";
9
8
 
10
9
  const compile = async (schema, ast, parentSchema) => {
11
- const itemsKeywordName = getKeywordName(schema.dialectId, "https://json-schema.org/keyword/draft-04/items");
12
- const items = await Schema.step(itemsKeywordName, parentSchema);
13
- const numberOfItems = Schema.typeOf(items, "array") ? Schema.length(items) : Number.MAX_SAFE_INTEGER;
10
+ const itemsKeywordName = getKeywordName(schema.document.dialectId, "https://json-schema.org/keyword/draft-04/items");
11
+ const items = await Browser.step(itemsKeywordName, parentSchema);
12
+ const numberOfItems = Browser.typeOf(items) === "array" ? Browser.length(items) : Number.MAX_SAFE_INTEGER;
14
13
 
15
14
  return [numberOfItems, await Validation.compile(schema, ast)];
16
15
  };
17
16
 
18
17
  const interpret = ([numberOfItems, additionalItems], instance, ast, dynamicAnchors, quiet) => {
19
- if (!Instance.typeOf(instance, "array")) {
18
+ if (Instance.typeOf(instance) !== "array") {
20
19
  return true;
21
20
  }
22
21
 
@@ -1,16 +1,16 @@
1
1
  import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
+ import * as Browser from "@hyperjump/browser";
2
3
  import * as Instance from "../lib/instance.js";
3
- import * as Schema from "../lib/schema.js";
4
- import Validation from "../lib/keywords/validation.js";
4
+ import { Validation } from "../lib/experimental.js";
5
5
 
6
6
 
7
7
  const id = "https://json-schema.org/keyword/draft-04/dependencies";
8
8
 
9
9
  const compile = (schema, ast) => pipe(
10
- Schema.entries(schema),
10
+ Browser.entries(schema),
11
11
  asyncMap(async ([key, dependency]) => [
12
12
  key,
13
- Schema.typeOf(dependency, "array") ? Schema.value(dependency) : await Validation.compile(dependency, ast)
13
+ Browser.typeOf(dependency) === "array" ? Browser.value(dependency) : await Validation.compile(dependency, ast)
14
14
  ]),
15
15
  asyncCollectArray
16
16
  );
@@ -18,7 +18,7 @@ const compile = (schema, ast) => pipe(
18
18
  const interpret = (dependencies, instance, ast, dynamicAnchors, quiet) => {
19
19
  const value = Instance.value(instance);
20
20
 
21
- return !Instance.typeOf(instance, "object") || dependencies.every(([propertyName, dependency]) => {
21
+ return Instance.typeOf(instance) !== "object" || dependencies.every(([propertyName, dependency]) => {
22
22
  if (!(propertyName in value)) {
23
23
  return true;
24
24
  }
package/draft-04/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";
2
- import { addSchema } from "../lib/core.js";
2
+ import { registerSchema } from "../lib/index.js";
3
3
  import metaSchema from "./schema.js";
4
4
  import additionalItems from "./additionalItems.js";
5
5
  import dependencies from "./dependencies.js";
@@ -64,6 +64,6 @@ loadDialect(jsonSchemaVersion, {
64
64
  [jsonSchemaVersion]: true
65
65
  }, true);
66
66
 
67
- addSchema(metaSchema);
67
+ registerSchema(metaSchema);
68
68
 
69
69
  export * from "../lib/index.js";
package/draft-04/items.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { pipe, asyncMap, asyncCollectArray, every, zip, take, range, collectSet } from "@hyperjump/pact";
2
+ import * as Browser from "@hyperjump/browser";
2
3
  import * as Instance from "../lib/instance.js";
3
- import * as Schema from "../lib/schema.js";
4
- import Validation from "../lib/keywords/validation.js";
4
+ import { Validation } from "../lib/experimental.js";
5
5
 
6
6
 
7
7
  const id = "https://json-schema.org/keyword/draft-04/items";
8
8
 
9
9
  const compile = (schema, ast) => {
10
- if (Schema.typeOf(schema, "array")) {
10
+ if (Browser.typeOf(schema) === "array") {
11
11
  return pipe(
12
- Schema.iter(schema),
12
+ Browser.iter(schema),
13
13
  asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
14
14
  asyncCollectArray
15
15
  );
@@ -19,7 +19,7 @@ const compile = (schema, ast) => {
19
19
  };
20
20
 
21
21
  const interpret = (items, instance, ast, dynamicAnchors, quiet) => {
22
- if (!Instance.typeOf(instance, "array")) {
22
+ if (Instance.typeOf(instance) !== "array") {
23
23
  return true;
24
24
  }
25
25
 
@@ -1,20 +1,20 @@
1
+ import * as Browser from "@hyperjump/browser";
1
2
  import * as Instance from "../lib/instance.js";
2
- import * as Schema from "../lib/schema.js";
3
- import { getKeywordName } from "../lib/keywords.js";
3
+ import { getKeywordName } from "../lib/experimental.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/draft-04/maximum";
7
7
 
8
- const compile = async (schema, ast, parentSchema) => {
9
- const exclusiveMaximumKeyword = getKeywordName(schema.dialectId, "https://json-schema.org/keyword/draft-04/exclusiveMaximum");
10
- const exclusiveMaximum = await Schema.step(exclusiveMaximumKeyword, parentSchema);
11
- const isExclusive = Schema.value(exclusiveMaximum);
8
+ const compile = async (schema, _ast, parentSchema) => {
9
+ const exclusiveMaximumKeyword = getKeywordName(schema.document.dialectId, "https://json-schema.org/keyword/draft-04/exclusiveMaximum");
10
+ const exclusiveMaximum = await Browser.step(exclusiveMaximumKeyword, parentSchema);
11
+ const isExclusive = Browser.value(exclusiveMaximum);
12
12
 
13
- return [Schema.value(schema), isExclusive];
13
+ return [Browser.value(schema), isExclusive];
14
14
  };
15
15
 
16
16
  const interpret = ([maximum, isExclusive], instance) => {
17
- if (!Instance.typeOf(instance, "number")) {
17
+ if (Instance.typeOf(instance) !== "number") {
18
18
  return true;
19
19
  }
20
20
 
@@ -1,20 +1,20 @@
1
+ import * as Browser from "@hyperjump/browser";
1
2
  import * as Instance from "../lib/instance.js";
2
- import * as Schema from "../lib/schema.js";
3
- import { getKeywordName } from "../lib/keywords.js";
3
+ import { getKeywordName } from "../lib/experimental.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/draft-04/minimum";
7
7
 
8
- const compile = async (schema, ast, parentSchema) => {
9
- const exclusiveMinimumKeyword = getKeywordName(schema.dialectId, "https://json-schema.org/keyword/draft-04/exclusiveMinimum");
10
- const exclusiveMinimum = await Schema.step(exclusiveMinimumKeyword, parentSchema);
11
- const isExclusive = Schema.value(exclusiveMinimum);
8
+ const compile = async (schema, _ast, parentSchema) => {
9
+ const exclusiveMinimumKeyword = getKeywordName(schema.document.dialectId, "https://json-schema.org/keyword/draft-04/exclusiveMinimum");
10
+ const exclusiveMinimum = await Browser.step(exclusiveMinimumKeyword, parentSchema);
11
+ const isExclusive = Browser.value(exclusiveMinimum);
12
12
 
13
- return [Schema.value(schema), isExclusive];
13
+ return [Browser.value(schema), isExclusive];
14
14
  };
15
15
 
16
16
  const interpret = ([minimum, isExclusive], instance) => {
17
- if (!Instance.typeOf(instance, "number")) {
17
+ if (Instance.typeOf(instance) !== "number") {
18
18
  return true;
19
19
  }
20
20