@hyperjump/json-schema 1.4.6 → 1.5.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.
package/README.md CHANGED
@@ -254,7 +254,7 @@ import { addSchema } from "@hyperjump/json-schema/draft-2020-12";
254
254
  import { bundle } from "@hyperjump/json-schema/bundle";
255
255
 
256
256
  addSchema({
257
- "$id": "https://example.com/main"
257
+ "$id": "https://example.com/main",
258
258
  "$schema": "https://json-schema.org/draft/2020-12/schema",
259
259
 
260
260
  "type": "object",
@@ -280,8 +280,8 @@ const bundledSchema = await bundle("https://example.com/main"); // {
280
280
  // },
281
281
  //
282
282
  // "$defs": {
283
- // "https://example.com/main": {
284
- // "$id": "https://example.com/main",
283
+ // "https://example.com/string": {
284
+ // "$id": "https://example.com/string",
285
285
  // "type": "string"
286
286
  // }
287
287
  // }
@@ -564,15 +564,18 @@ set of functions for working with SchemaDocuments.
564
564
  * **Schema.step**: (key: string, doc: SchemaDocument) => Promise<SchemaDocument>
565
565
 
566
566
  Similar to `schema[key]`, but returns an SchemaDocument.
567
- * **Schema.entries**: (doc: SchemaDocument) => Promise<[[string, SchemaDocument]]>
567
+ * **Schema.iter**: (doc: SchemaDocument) => AsyncGenerator<SchemaDocument>
568
568
 
569
- Similar to `Object.entries`, but returns SchemaDocuments for values.
570
- * **Schema.keys**: (doc: SchemaDocument) => [string]
569
+ Iterate over the items in the array that the SchemaDocument represents
570
+ * **Schema.entries**: (doc: SchemaDocument) => AsyncGenerator<[string, SchemaDocument]>
571
571
 
572
- Similar to `Object.keys`.
573
- * **Schema.map**: (fn: (item: Promise<SchemaDocument>, index: integer) => T, doc: SchemaDocument) => Promise<[T]>
572
+ Similar to `Object.entries`, but yields SchemaDocuments for values.
573
+ * **Schema.values**: (doc: SchemaDocument) => AsyncGenerator<SchemaDocument>
574
+
575
+ Similar to `Object.values`, but yields SchemaDocuments for values.
576
+ * **Schema.keys**: (doc: SchemaDocument) => Generator<string>
574
577
 
575
- A `map` function for an SchemaDocument whose value is an array.
578
+ Similar to `Object.keys`.
576
579
  * **Schema.length**: (doc: SchemaDocument) => number
577
580
 
578
581
  Similar to `Array.prototype.length`.
@@ -622,24 +625,18 @@ set of functions for working with InstanceDocuments.
622
625
  * **Instance.step**: (key: string, doc: InstanceDocument) => InstanceDocument
623
626
 
624
627
  Similar to `schema[key]`, but returns a InstanceDocument.
625
- * **Instance.entries**: (doc: InstanceDocument) => [string, InstanceDocument]
626
-
627
- Similar to `Object.entries`, but returns IDocs for values.
628
- * **Instance.keys**: (doc: InstanceDocument) => [string]
628
+ * **Instance.iter**: (doc: InstanceDocument) => Generator<InstanceDocument>
629
629
 
630
- Similar to `Object.keys`.
631
- * **Instance.map**: (fn: (item: InstanceDocument, index: integer) => T, doc: InstanceDocument) => [T]
632
-
633
- A `map` function for an InstanceDocument whose value is an array.
634
- * **Instance.reduce**: (fn: (accumulator: T, item: InstanceDocument, index: integer) => T, initial: T, doc: InstanceDocument) => T
630
+ Iterate over the items in the array that the SchemaDocument represents.
631
+ * **Instance.entries**: (doc: InstanceDocument) => Generator<[string, InstanceDocument]>
635
632
 
636
- A `reduce` function for an InstanceDocument whose value is an array.
637
- * **Instance.every**: (fn: (doc: InstanceDocument, index: integer) => boolean, doc: InstanceDocument) => boolean
633
+ Similar to `Object.entries`, but yields InstanceDocuments for values.
634
+ * **Instance.values**: (doc: InstanceDocument) => Generator<InstanceDocument>
638
635
 
639
- An `every` function for an InstanceDocument whose value is an array.
640
- * **Instance.some**: (fn: (doc: InstanceDocument, index: integer) => boolean, doc: InstanceDocument) => boolean
636
+ Similar to `Object.values`, but yields InstanceDocuments for values.
637
+ * **Instance.keys**: (doc: InstanceDocument) => Generator<string>
641
638
 
642
- A `some` function for an InstanceDocument whose value is an array.
639
+ Similar to `Object.keys`.
643
640
  * **Instance.length**: (doc: InstanceDocument) => number
644
641
 
645
642
  Similar to `Array.prototype.length`.
@@ -708,10 +705,9 @@ const unknowns = AnnotatedInstance.annotation(instance, "unknown", dialectId); /
708
705
  const types = AnnotatedInstance.annotation(instance, "type", dialectId); // => []
709
706
 
710
707
  // Get the title of each of the properties in the object
711
- AnnotatedInstance.entries(instance)
712
- .map(([propertyName, propertyInstance]) => {
713
- return { propertyName, titles: Instance.annotation(propertyInstance, "title", dialectId) }; // => (Example) { propertyName: "givenName", titles: ["Given Name", "Name"] });
714
- });
708
+ for (const [propertyName, propertyInstance] of AnnotatedInstance.entries(instance)) {
709
+ console.log(propertyName, Instance.annotation(propertyInstance, "title", dialectId));
710
+ }
715
711
 
716
712
  // List all locations in the instance that are deprecated
717
713
  for (const deprecated of AnnotatedInstance.annotatedWith(instance, "deprecated", dialectId)) {
@@ -1,3 +1,4 @@
1
+ import { pipe, drop, every } from "@hyperjump/pact";
1
2
  import * as Instance from "../lib/instance.js";
2
3
  import * as Schema from "../lib/schema.js";
3
4
  import Validation from "../lib/keywords/validation.js";
@@ -19,7 +20,11 @@ const interpret = ([numberOfItems, additionalItems], instance, ast, dynamicAncho
19
20
  return true;
20
21
  }
21
22
 
22
- return Instance.every((item, ndx) => ndx < numberOfItems || Validation.interpret(additionalItems, item, ast, dynamicAnchors), instance, quiet);
23
+ return pipe(
24
+ Instance.iter(instance),
25
+ drop(numberOfItems),
26
+ every((item) => Validation.interpret(additionalItems, item, ast, dynamicAnchors, quiet))
27
+ );
23
28
  };
24
29
 
25
30
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
@@ -1,18 +1,19 @@
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
1
2
  import * as Instance from "../lib/instance.js";
2
3
  import * as Schema from "../lib/schema.js";
3
4
  import Validation from "../lib/keywords/validation.js";
4
- import * as Pact from "@hyperjump/pact";
5
5
 
6
6
 
7
7
  const id = "https://json-schema.org/keyword/draft-04/dependencies";
8
8
 
9
- const compile = (schema, ast) => Pact.pipeline([
10
- Schema.entries,
11
- Pact.map(async ([key, dependency]) => {
12
- return [key, Schema.typeOf(dependency, "array") ? Schema.value(dependency) : await Validation.compile(dependency, ast)];
13
- }),
14
- Pact.all
15
- ], schema);
9
+ const compile = (schema, ast) => pipe(
10
+ Schema.entries(schema),
11
+ asyncMap(async ([key, dependency]) => [
12
+ key,
13
+ Schema.typeOf(dependency, "array") ? Schema.value(dependency) : await Validation.compile(dependency, ast)
14
+ ]),
15
+ asyncCollectArray
16
+ );
16
17
 
17
18
  const interpret = (dependencies, instance, ast, dynamicAnchors, quiet) => {
18
19
  const value = Instance.value(instance);
package/draft-04/items.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { pipe, asyncMap, asyncCollectArray, every, zip, take, range, collectSet } from "@hyperjump/pact";
1
2
  import * as Instance from "../lib/instance.js";
2
3
  import * as Schema from "../lib/schema.js";
3
4
  import Validation from "../lib/keywords/validation.js";
@@ -5,10 +6,13 @@ import Validation from "../lib/keywords/validation.js";
5
6
 
6
7
  const id = "https://json-schema.org/keyword/draft-04/items";
7
8
 
8
- const compile = async (schema, ast) => {
9
+ const compile = (schema, ast) => {
9
10
  if (Schema.typeOf(schema, "array")) {
10
- const tupleItems = await Schema.map((itemSchema) => Validation.compile(itemSchema, ast), schema);
11
- return Promise.all(tupleItems);
11
+ return pipe(
12
+ Schema.iter(schema),
13
+ asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
14
+ asyncCollectArray
15
+ );
12
16
  } else {
13
17
  return Validation.compile(schema, ast);
14
18
  }
@@ -20,16 +24,20 @@ const interpret = (items, instance, ast, dynamicAnchors, quiet) => {
20
24
  }
21
25
 
22
26
  if (typeof items === "string") {
23
- return Instance.every((itemValue) => Validation.interpret(items, itemValue, ast, dynamicAnchors), instance, quiet);
27
+ return every((itemValue) => Validation.interpret(items, itemValue, ast, dynamicAnchors, quiet), Instance.iter(instance));
24
28
  } else {
25
- return Instance.every((item, ndx) => !(ndx in items) || Validation.interpret(items[ndx], item, ast, dynamicAnchors), instance, quiet);
29
+ return pipe(
30
+ zip(items, Instance.iter(instance)),
31
+ take(Instance.length(instance)),
32
+ every(([prefixItem, item]) => Validation.interpret(prefixItem, item, ast, dynamicAnchors, quiet))
33
+ );
26
34
  }
27
35
  };
28
36
 
29
37
  const collectEvaluatedItems = (items, instance, ast, dynamicAnchors) => {
30
38
  return interpret(items, instance, ast, dynamicAnchors) && (typeof items === "string"
31
- ? new Set(Instance.map((item, itemIndex) => itemIndex, instance))
32
- : new Set(items.map((item, itemIndex) => itemIndex)));
39
+ ? collectSet(range(0, Instance.length(instance)))
40
+ : collectSet(range(0, items.length)));
33
41
  };
34
42
 
35
43
  export default { id, compile, interpret, collectEvaluatedItems };
@@ -1,3 +1,4 @@
1
+ import { some } from "@hyperjump/pact";
1
2
  import * as Instance from "../lib/instance.js";
2
3
  import Validation from "../lib/keywords/validation.js";
3
4
 
@@ -7,7 +8,7 @@ const id = "https://json-schema.org/keyword/draft-06/contains";
7
8
  const compile = (schema, ast) => Validation.compile(schema, ast);
8
9
 
9
10
  const interpret = (contains, instance, ast, dynamicAnchors, quiet) => {
10
- return !Instance.typeOf(instance, "array") || Instance.some((item) => Validation.interpret(contains, item, ast, dynamicAnchors), instance, quiet);
11
+ return !Instance.typeOf(instance, "array") || some((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet), Instance.iter(instance));
11
12
  };
12
13
 
13
14
  export default { id, compile, interpret };
@@ -1,3 +1,4 @@
1
+ import { pipe, filter, reduce, zip, range, map, collectSet } from "@hyperjump/pact";
1
2
  import * as Instance from "../lib/instance.js";
2
3
  import * as Schema from "../lib/schema.js";
3
4
  import { getKeywordName } from "../lib/keywords.js";
@@ -21,20 +22,23 @@ const compile = async (schema, ast, parentSchema) => {
21
22
  };
22
23
 
23
24
  const interpret = ({ contains, minContains, maxContains }, instance, ast, dynamicAnchors, quiet) => {
24
- if (!Instance.typeOf(instance, "array")) {
25
- return true;
26
- }
27
-
28
- const matches = Instance.reduce((matches, item) => {
29
- return Validation.interpret(contains, item, ast, dynamicAnchors, quiet) ? matches + 1 : matches;
30
- }, 0, instance);
25
+ const matches = !Instance.typeOf(instance, "array") || pipe(
26
+ Instance.iter(instance),
27
+ filter((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet)),
28
+ reduce((matches) => matches + 1, 0)
29
+ );
31
30
  return matches >= minContains && matches <= maxContains;
32
31
  };
33
32
 
34
33
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
35
- return interpret(keywordValue, instance, ast, dynamicAnchors) && Instance.reduce((matchedIndexes, item, itemIndex) => {
36
- return Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors) ? matchedIndexes.add(itemIndex) : matchedIndexes;
37
- }, new Set(), instance);
34
+ return interpret(keywordValue, instance, ast, dynamicAnchors, true)
35
+ && Instance.typeOf(instance, "array")
36
+ && pipe(
37
+ zip(Instance.iter(instance), range(0)),
38
+ filter(([item]) => Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors, true)),
39
+ map(([, itemIndex]) => itemIndex),
40
+ collectSet
41
+ );
38
42
  };
39
43
 
40
44
  export default { id, compile, interpret, collectEvaluatedItems };
package/lib/instance.d.ts CHANGED
@@ -26,40 +26,10 @@ export const typeOf: (
26
26
  (doc: JsonDocument) => (type: JsonType) => boolean
27
27
  );
28
28
  export const step: (key: string, doc: JsonDocument<JsonObject | Json[]>) => JsonDocument<typeof doc.value>;
29
- export const entries: (doc: JsonDocument<JsonObject>) => [string, JsonDocument][];
30
- export const keys: (doc: JsonDocument<JsonObject>) => string[];
31
- export const map: (
32
- <A>(fn: MapFn<A>, doc: JsonDocument<Json[]>) => A[]
33
- ) & (
34
- <A>(fn: MapFn<A>) => (doc: JsonDocument<Json[]>) => A[]
35
- );
36
- export const forEach: (
37
- (fn: ForEachFn, doc: JsonDocument<Json[]>) => void
38
- ) & (
39
- (fn: ForEachFn) => (doc: JsonDocument<Json[]>) => void
40
- );
41
- export const filter: (
42
- (fn: FilterFn, doc: JsonDocument<Json[]>) => JsonDocument[]
43
- ) & (
44
- (fn: FilterFn) => (doc: JsonDocument<Json[]>) => JsonDocument[]
45
- );
46
- export const reduce: (
47
- <A>(fn: ReduceFn<A>, acc: A, doc: JsonDocument<Json[]>) => A
48
- ) & (
49
- <A>(fn: ReduceFn<A>) => (acc: A, doc: JsonDocument<Json[]>) => A
50
- ) & (
51
- <A>(fn: ReduceFn<A>) => (acc: A) => (doc: JsonDocument<Json[]>) => A
52
- );
53
- export const every: (
54
- (fn: FilterFn, doc: JsonDocument<Json[]>) => boolean
55
- ) & (
56
- (fn: FilterFn) => (doc: JsonDocument<Json[]>) => boolean
57
- );
58
- export const some: (
59
- (fn: FilterFn, doc: JsonDocument<Json[]>) => boolean
60
- ) & (
61
- (fn: FilterFn) => (doc: JsonDocument<Json[]>) => boolean
62
- );
29
+ export const iter: (doc: JsonDocument<JsonObject>) => Generator<JsonDocument>;
30
+ export const keys: (doc: JsonDocument<JsonObject>) => Generator<string>;
31
+ export const values: (doc: JsonDocument<JsonObject>) => Generator<JsonDocument>;
32
+ export const entries: (doc: JsonDocument<JsonObject>) => Generator<[string, JsonDocument]>;
63
33
  export const length: (doc: JsonDocument<Json[] | string>) => number;
64
34
 
65
35
  type MapFn<A> = (element: JsonDocument, index: number) => A;
package/lib/instance.js CHANGED
@@ -32,28 +32,28 @@ export const step = (key, doc) => ({
32
32
  value: value(doc)[key]
33
33
  });
34
34
 
35
- export const entries = (doc) => Object.keys(value(doc))
36
- .map((key) => [key, step(key, doc)]);
37
-
38
- export const keys = (doc) => Object.keys(value(doc));
39
-
40
- export const map = curry((fn, doc) => value(doc)
41
- .map((item, ndx, array, thisArg) => fn(step(ndx, doc), ndx, array, thisArg)));
42
-
43
- export const forEach = curry((fn, doc) => value(doc)
44
- .forEach((item, ndx, array, thisArg) => fn(step(ndx, doc), ndx, array, thisArg)));
45
-
46
- export const filter = curry((fn, doc) => value(doc)
47
- .map((item, ndx, array, thisArg) => step(ndx, doc, array, thisArg))
48
- .filter((item, ndx, array, thisArg) => fn(item, ndx, array, thisArg)));
35
+ export const iter = function* (doc) {
36
+ for (let index = 0; index < value(doc).length; index++) {
37
+ yield step(index, doc);
38
+ }
39
+ };
49
40
 
50
- export const reduce = curry((fn, acc, doc) => value(doc)
51
- .reduce((acc, item, ndx) => fn(acc, step(ndx, doc), ndx), acc));
41
+ export const keys = function* (doc) {
42
+ for (const key in value(doc)) {
43
+ yield key;
44
+ }
45
+ };
52
46
 
53
- export const every = curry((fn, doc) => value(doc)
54
- .every((item, ndx, array, thisArg) => fn(step(ndx, doc), ndx, array, thisArg)));
47
+ export const values = function* (doc) {
48
+ for (const key in value(doc)) {
49
+ yield step(key, doc);
50
+ }
51
+ };
55
52
 
56
- export const some = curry((fn, doc) => value(doc)
57
- .some((item, ndx, array, thisArg) => fn(step(ndx, doc), ndx, array, thisArg)));
53
+ export const entries = function* (doc) {
54
+ for (const key in value(doc)) {
55
+ yield [key, step(key, doc)];
56
+ }
57
+ };
58
58
 
59
59
  export const length = (doc) => value(doc).length;
@@ -1,3 +1,4 @@
1
+ import { filter, every, pipe } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import * as Instance from "../instance.js";
3
4
  import { getKeywordName } from "../keywords.js";
@@ -38,9 +39,11 @@ const interpret = ([isDefinedProperty, additionalProperties], instance, ast, dyn
38
39
  return true;
39
40
  }
40
41
 
41
- return Instance.entries(instance)
42
- .filter(([propertyName]) => !isDefinedProperty.test(propertyName))
43
- .every(([, property]) => Validation.interpret(additionalProperties, property, ast, dynamicAnchors, quiet));
42
+ return pipe(
43
+ Instance.entries(instance),
44
+ filter(([propertyName]) => !isDefinedProperty.test(propertyName)),
45
+ every(([, property]) => Validation.interpret(additionalProperties, property, ast, dynamicAnchors, quiet))
46
+ );
44
47
  };
45
48
 
46
49
  const collectEvaluatedProperties = ([isDefinedProperty, additionalProperties], instance, ast, dynamicAnchors) => {
@@ -1,14 +1,15 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import Validation from "./validation.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/allOf";
7
7
 
8
- const compile = (schema, ast) => Pact.pipeline([
9
- Schema.map(async (itemSchema) => Validation.compile(await itemSchema, ast)),
10
- Pact.all
11
- ], schema);
8
+ const compile = (schema, ast) => pipe(
9
+ Schema.iter(schema),
10
+ asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
11
+ asyncCollectArray
12
+ );
12
13
 
13
14
  const interpret = (allOf, instance, ast, dynamicAnchors, quiet) => {
14
15
  return allOf.every((schemaUrl) => Validation.interpret(schemaUrl, instance, ast, dynamicAnchors, quiet));
@@ -1,14 +1,15 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import Validation from "./validation.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/anyOf";
7
7
 
8
- const compile = (schema, ast) => Pact.pipeline([
9
- Schema.map(async (itemSchema) => Validation.compile(await itemSchema, ast)),
10
- Pact.all
11
- ], schema);
8
+ const compile = (schema, ast) => pipe(
9
+ Schema.iter(schema),
10
+ asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
11
+ asyncCollectArray
12
+ );
12
13
 
13
14
  const interpret = (anyOf, instance, ast, dynamicAnchors, quiet) => {
14
15
  const matches = anyOf.filter((schemaUrl) => Validation.interpret(schemaUrl, instance, ast, dynamicAnchors, quiet));
@@ -1,3 +1,4 @@
1
+ import { pipe, map, filter, reduce, collectSet, zip, range } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import * as Instance from "../instance.js";
3
4
  import { getKeywordName } from "../keywords.js";
@@ -21,33 +22,43 @@ const compile = async (schema, ast, parentSchema) => {
21
22
  };
22
23
 
23
24
  const interpret = ({ contains, minContains, maxContains }, instance, ast, dynamicAnchors, quiet) => {
24
- if (!Instance.typeOf(instance, "array") && !Instance.typeOf(instance, "object")) {
25
+ let iterator;
26
+ if (Instance.typeOf(instance, "array")) {
27
+ iterator = Instance.iter(instance);
28
+ } else if (Instance.typeOf(instance, "object")) {
29
+ iterator = Instance.values(instance);
30
+ } else {
25
31
  return true;
26
32
  }
27
33
 
28
- const matches = Instance.entries(instance).reduce((matches, [, item]) => {
29
- return Validation.interpret(contains, item, ast, dynamicAnchors, quiet) ? matches + 1 : matches;
30
- }, 0);
34
+ const matches = pipe(
35
+ iterator,
36
+ filter((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet)),
37
+ reduce((matches) => matches + 1, 0)
38
+ );
31
39
  return matches >= minContains && matches <= maxContains;
32
40
  };
33
41
 
34
42
  const collectEvaluatedProperties = (keywordValue, instance, ast, dynamicAnchors) => {
35
43
  return interpret(keywordValue, instance, ast, dynamicAnchors, true)
36
44
  && Instance.typeOf(instance, "object")
37
- && Instance.entries(instance).reduce((matchedPropertyNames, [propertyName, item]) => {
38
- if (Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors, true)) {
39
- matchedPropertyNames.add(propertyName);
40
- }
41
- return matchedPropertyNames;
42
- }, new Set(), instance);
45
+ && pipe(
46
+ Instance.entries(instance),
47
+ filter(([, item]) => Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors, true)),
48
+ map(([propertyName]) => propertyName),
49
+ collectSet
50
+ );
43
51
  };
44
52
 
45
53
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
46
54
  return interpret(keywordValue, instance, ast, dynamicAnchors, true)
47
55
  && Instance.typeOf(instance, "array")
48
- && Instance.reduce((matchedIndexes, item, itemIndex) => {
49
- return Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors, true) ? matchedIndexes.add(itemIndex) : matchedIndexes;
50
- }, new Set(), instance);
56
+ && pipe(
57
+ zip(Instance.iter(instance), range(0)),
58
+ filter(([item]) => Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors, true)),
59
+ map(([, itemIndex]) => itemIndex),
60
+ collectSet
61
+ );
51
62
  };
52
63
 
53
64
  export default { id, compile, interpret, collectEvaluatedItems, collectEvaluatedProperties };
@@ -1,17 +1,15 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import Validation from "./validation.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/definitions";
7
7
 
8
- const compile = async (schema, ast) => {
9
- await Pact.pipeline([
10
- Schema.entries,
11
- Pact.map(([, definitionSchema]) => Validation.compile(definitionSchema, ast)),
12
- Pact.all
13
- ], schema);
14
- };
8
+ const compile = (schema, ast) => pipe(
9
+ Schema.values(schema),
10
+ asyncMap((definitionSchema) => Validation.compile(definitionSchema, ast)),
11
+ asyncCollectArray
12
+ );
15
13
 
16
14
  const interpret = () => true;
17
15
 
@@ -1,15 +1,15 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import * as Instance from "../instance.js";
4
4
 
5
5
 
6
6
  const id = "https://json-schema.org/keyword/dependentRequired";
7
7
 
8
- const compile = (schema) => Pact.pipeline([
9
- Schema.entries,
10
- Pact.map(([key, dependentRequired]) => [key, Schema.value(dependentRequired)]),
11
- Pact.all
12
- ], schema);
8
+ const compile = (schema) => pipe(
9
+ Schema.entries(schema),
10
+ asyncMap(([key, dependentRequired]) => [key, Schema.value(dependentRequired)]),
11
+ asyncCollectArray
12
+ );
13
13
 
14
14
  const interpret = (dependentRequired, instance) => {
15
15
  const value = Instance.value(instance);
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import * as Instance from "../instance.js";
4
4
  import Validation from "./validation.js";
@@ -6,11 +6,11 @@ import Validation from "./validation.js";
6
6
 
7
7
  const id = "https://json-schema.org/keyword/dependentSchemas";
8
8
 
9
- const compile = (schema, ast) => Pact.pipeline([
10
- Schema.entries,
11
- Pact.map(async ([key, dependentSchema]) => [key, await Validation.compile(dependentSchema, ast)]),
12
- Pact.all
13
- ], schema);
9
+ const compile = (schema, ast) => pipe(
10
+ Schema.entries(schema),
11
+ asyncMap(async ([key, dependentSchema]) => [key, await Validation.compile(dependentSchema, ast)]),
12
+ asyncCollectArray
13
+ );
14
14
 
15
15
  const interpret = (dependentSchemas, instance, ast, dynamicAnchors, quiet) => {
16
16
  const value = Instance.value(instance);
@@ -1,3 +1,4 @@
1
+ import { pipe, drop, every } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import * as Instance from "../instance.js";
3
4
  import { getKeywordName } from "../keywords.js";
@@ -19,7 +20,11 @@ const interpret = ([numberOfPrefixItems, items], instance, ast, dynamicAnchors,
19
20
  return true;
20
21
  }
21
22
 
22
- return Instance.every((item, ndx) => ndx < numberOfPrefixItems || Validation.interpret(items, item, ast, dynamicAnchors, quiet), instance);
23
+ return pipe(
24
+ Instance.iter(instance),
25
+ drop(numberOfPrefixItems),
26
+ every((item) => Validation.interpret(items, item, ast, dynamicAnchors, quiet))
27
+ );
23
28
  };
24
29
 
25
30
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
@@ -5,6 +5,8 @@ import * as Instance from "../instance.js";
5
5
  const id = "https://json-schema.org/keyword/maxProperties";
6
6
 
7
7
  const compile = (schema) => Schema.value(schema);
8
- const interpret = (maxProperties, instance) => !Instance.typeOf(instance, "object") || Instance.keys(instance).length <= maxProperties;
8
+ const interpret = (maxProperties, instance) => {
9
+ return !Instance.typeOf(instance, "object") || [...Instance.keys(instance)].length <= maxProperties;
10
+ };
9
11
 
10
12
  export default { id, compile, interpret };
@@ -5,6 +5,8 @@ import * as Instance from "../instance.js";
5
5
  const id = "https://json-schema.org/keyword/minProperties";
6
6
 
7
7
  const compile = (schema) => Schema.value(schema);
8
- const interpret = (minProperties, instance) => !Instance.typeOf(instance, "object") || Instance.keys(instance).length >= minProperties;
8
+ const interpret = (minProperties, instance) => {
9
+ return !Instance.typeOf(instance, "object") || [...Instance.keys(instance)].length >= minProperties;
10
+ };
9
11
 
10
12
  export default { id, compile, interpret };
@@ -1,13 +1,15 @@
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import Validation from "./validation.js";
3
4
 
4
5
 
5
6
  const id = "https://json-schema.org/keyword/oneOf";
6
7
 
7
- const compile = async (schema, ast) => {
8
- const oneOf = await Schema.map((itemSchema) => Validation.compile(itemSchema, ast), schema);
9
- return Promise.all(oneOf);
10
- };
8
+ const compile = (schema, ast) => pipe(
9
+ Schema.iter(schema),
10
+ asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
11
+ asyncCollectArray
12
+ );
11
13
 
12
14
  const interpret = (oneOf, instance, ast, dynamicAnchors, quiet) => {
13
15
  let validCount = 0;
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray, filter, every } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import * as Instance from "../instance.js";
4
4
  import Validation from "./validation.js";
@@ -6,17 +6,22 @@ import Validation from "./validation.js";
6
6
 
7
7
  const id = "https://json-schema.org/keyword/patternProperties";
8
8
 
9
- const compile = (schema, ast) => Pact.pipeline([
10
- Schema.entries,
11
- Pact.map(async ([pattern, propertySchema]) => [new RegExp(pattern, "u"), await Validation.compile(propertySchema, ast)]),
12
- Pact.all
13
- ], schema);
9
+ const compile = (schema, ast) => pipe(
10
+ Schema.entries(schema),
11
+ asyncMap(async ([pattern, propertySchema]) => [
12
+ new RegExp(pattern, "u"),
13
+ await Validation.compile(propertySchema, ast)
14
+ ]),
15
+ asyncCollectArray
16
+ );
14
17
 
15
18
  const interpret = (patternProperties, instance, ast, dynamicAnchors, quiet) => {
16
19
  return !Instance.typeOf(instance, "object") || patternProperties.every(([pattern, schemaUrl]) => {
17
- return Instance.entries(instance)
18
- .filter(([propertyName]) => pattern.test(propertyName))
19
- .every(([, propertyValue]) => Validation.interpret(schemaUrl, propertyValue, ast, dynamicAnchors, quiet));
20
+ return pipe(
21
+ Instance.entries(instance),
22
+ filter(([propertyName]) => pattern.test(propertyName)),
23
+ every(([, propertyValue]) => Validation.interpret(schemaUrl, propertyValue, ast, dynamicAnchors, quiet))
24
+ );
20
25
  });
21
26
  };
22
27
 
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray, every, zip, take } from "@hyperjump/pact";
2
2
  import * as Instance from "../instance.js";
3
3
  import * as Schema from "../schema.js";
4
4
  import Validation from "./validation.js";
@@ -6,19 +6,22 @@ import Validation from "./validation.js";
6
6
 
7
7
  const id = "https://json-schema.org/keyword/prefixItems";
8
8
 
9
- const compile = (schema, ast) => {
10
- return Pact.pipeline([
11
- Schema.map((itemSchema) => Validation.compile(itemSchema, ast)),
12
- Pact.all
13
- ], schema);
14
- };
9
+ const compile = (schema, ast) => pipe(
10
+ Schema.iter(schema),
11
+ asyncMap((itemSchema) => Validation.compile(itemSchema, ast)),
12
+ asyncCollectArray
13
+ );
15
14
 
16
- const interpret = (items, instance, ast, dynamicAnchors, quiet) => {
15
+ const interpret = (prefixItems, instance, ast, dynamicAnchors, quiet) => {
17
16
  if (!Instance.typeOf(instance, "array")) {
18
17
  return true;
19
18
  }
20
19
 
21
- return Instance.every((item, ndx) => !(ndx in items) || Validation.interpret(items[ndx], item, ast, dynamicAnchors, quiet), instance);
20
+ return pipe(
21
+ zip(prefixItems, Instance.iter(instance)),
22
+ take(Instance.length(instance)),
23
+ every(([prefixItem, item]) => Validation.interpret(prefixItem, item, ast, dynamicAnchors, quiet))
24
+ );
22
25
  };
23
26
 
24
27
  const collectEvaluatedItems = (items, instance, ast, dynamicAnchors) => {
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectObject, filter, every } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import * as Instance from "../instance.js";
4
4
  import Validation from "./validation.js";
@@ -6,18 +6,18 @@ import Validation from "./validation.js";
6
6
 
7
7
  const id = "https://json-schema.org/keyword/properties";
8
8
 
9
- const compile = (schema, ast) => Pact.pipeline([
10
- Schema.entries,
11
- Pact.reduce(async (acc, [propertyName, propertySchema]) => {
12
- acc[propertyName] = await Validation.compile(propertySchema, ast);
13
- return acc;
14
- }, Object.create(null))
15
- ], schema);
9
+ const compile = (schema, ast) => pipe(
10
+ Schema.entries(schema),
11
+ asyncMap(async ([propertyName, propertySchema]) => [propertyName, await Validation.compile(propertySchema, ast)]),
12
+ asyncCollectObject
13
+ );
16
14
 
17
15
  const interpret = (properties, instance, ast, dynamicAnchors, quiet) => {
18
- return !Instance.typeOf(instance, "object") || Instance.entries(instance)
19
- .filter(([propertyName]) => propertyName in properties)
20
- .every(([propertyName, schemaUrl]) => Validation.interpret(properties[propertyName], schemaUrl, ast, dynamicAnchors, quiet));
16
+ return !Instance.typeOf(instance, "object") || pipe(
17
+ Instance.entries(instance),
18
+ filter(([propertyName]) => propertyName in properties),
19
+ every(([propertyName, property]) => Validation.interpret(properties[propertyName], property, ast, dynamicAnchors, quiet))
20
+ );
21
21
  };
22
22
 
23
23
  const collectEvaluatedProperties = (properties, instance, ast, dynamicAnchors) => {
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectObject } from "@hyperjump/pact";
2
2
  import * as Schema from "../schema.js";
3
3
  import * as Instance from "../instance.js";
4
4
  import Validation from "./validation.js";
@@ -8,19 +8,17 @@ const id = "https://json-schema.org/keyword/propertyDependencies";
8
8
  const experimental = true;
9
9
 
10
10
  const compile = (schema, ast) => {
11
- return Pact.pipeline([
12
- Schema.entries,
13
- Pact.reduce(async (propertyDependencies, [propertyName, valueMappings]) => {
14
- propertyDependencies[propertyName] = await Pact.pipeline([
15
- Schema.entries,
16
- Pact.reduce(async (valueMappings, [propertyValue, conditionalSchema]) => {
17
- valueMappings[propertyValue] = await Validation.compile(conditionalSchema, ast);
18
- return valueMappings;
19
- }, {})
20
- ], valueMappings);
21
- return propertyDependencies;
22
- }, {})
23
- ], schema);
11
+ return pipe(
12
+ Schema.entries(schema),
13
+ asyncMap(async ([propertyName, valueMappings]) => {
14
+ return [propertyName, await pipe(
15
+ Schema.entries(valueMappings),
16
+ asyncMap(async ([propertyValue, conditionalSchema]) => [propertyValue, await Validation.compile(conditionalSchema, ast)]),
17
+ asyncCollectObject
18
+ )];
19
+ }),
20
+ asyncCollectObject
21
+ );
24
22
  };
25
23
 
26
24
  const interpret = (propertyDependencies, instance, ast, dynamicAnchors, quiet) => {
@@ -1,3 +1,4 @@
1
+ import { every } from "@hyperjump/pact";
1
2
  import * as Instance from "../instance.js";
2
3
  import Validation from "./validation.js";
3
4
 
@@ -7,8 +8,9 @@ const id = "https://json-schema.org/keyword/propertyNames";
7
8
  const compile = (schema, ast) => Validation.compile(schema, ast);
8
9
 
9
10
  const interpret = (propertyNames, instance, ast, dynamicAnchors) => {
10
- return !Instance.typeOf(instance, "object") || Instance.keys(instance)
11
- .every((key) => Validation.interpret(propertyNames, Instance.cons(key), ast, dynamicAnchors, true));
11
+ return !Instance.typeOf(instance, "object") || every((key) => {
12
+ return Validation.interpret(propertyNames, Instance.cons(key), ast, dynamicAnchors, true);
13
+ }, Instance.keys(instance));
12
14
  };
13
15
 
14
16
  export default { id, compile, interpret };
@@ -1,3 +1,4 @@
1
+ import { pipe, filter, every, zip, range } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import * as Instance from "../instance.js";
3
4
  import Validation from "./validation.js";
@@ -15,9 +16,11 @@ const interpret = ([schemaUrl, unevaluatedItems], instance, ast, dynamicAnchors,
15
16
  }
16
17
 
17
18
  const itemIndexes = Validation.collectEvaluatedItems(schemaUrl, instance, ast, dynamicAnchors, true);
18
- return itemIndexes === false || Instance.every((item, itemIndex) => {
19
- return itemIndexes.has(itemIndex) || Validation.interpret(unevaluatedItems, Instance.step(itemIndex, instance), ast, dynamicAnchors, quiet);
20
- }, instance);
19
+ return itemIndexes === false || pipe(
20
+ zip(Instance.iter(instance), range(0)),
21
+ filter(([, index]) => !itemIndexes.has(index)),
22
+ every(([item]) => Validation.interpret(unevaluatedItems, item, ast, dynamicAnchors, quiet))
23
+ );
21
24
  };
22
25
 
23
26
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
@@ -1,3 +1,4 @@
1
+ import { pipe, filter, every } from "@hyperjump/pact";
1
2
  import * as Schema from "../schema.js";
2
3
  import * as Instance from "../instance.js";
3
4
  import Validation from "./validation.js";
@@ -16,9 +17,11 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, ast, dynamicAnc
16
17
 
17
18
  const evaluatedPropertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, ast, dynamicAnchors, true);
18
19
 
19
- return !evaluatedPropertyNames || Instance.entries(instance)
20
- .filter(([propertyName]) => !evaluatedPropertyNames.has(propertyName))
21
- .every(([, property]) => Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors, quiet));
20
+ return !evaluatedPropertyNames || pipe(
21
+ Instance.entries(instance),
22
+ filter(([propertyName]) => !evaluatedPropertyNames.has(propertyName)),
23
+ every(([, property]) => Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors, quiet))
24
+ );
22
25
  };
23
26
 
24
27
  const collectEvaluatedProperties = ([schemaUrl, unevaluatedProperties], instance, ast, dynamicAnchors) => {
@@ -12,7 +12,7 @@ const interpret = (uniqueItems, instance) => {
12
12
  return true;
13
13
  }
14
14
 
15
- const normalizedItems = Instance.map((item) => jsonStringify(Instance.value(item)), instance);
15
+ const normalizedItems = Instance.value(instance).map(jsonStringify);
16
16
  return new Set(normalizedItems).size === normalizedItems.length;
17
17
  };
18
18
 
@@ -1,4 +1,4 @@
1
- import * as Pact from "@hyperjump/pact";
1
+ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
2
2
  import { publishAsync, publish } from "../pubsub.js";
3
3
  import { isExperimentalKeywordEnabled } from "../configuration.js";
4
4
  import * as Instance from "../instance.js";
@@ -30,9 +30,9 @@ const compile = async (schema, ast) => {
30
30
  throw Error(`No schema found at '${url}'`);
31
31
  }
32
32
 
33
- ast[url] = typeof schemaValue === "boolean" ? schemaValue : await Pact.pipeline([
34
- Schema.entries,
35
- Pact.map(async ([keyword, keywordSchema]) => {
33
+ ast[url] = typeof schemaValue === "boolean" ? schemaValue : await pipe(
34
+ Schema.entries(schema),
35
+ asyncMap(async ([keyword, keywordSchema]) => {
36
36
  const keywordId = getKeywordId(schema.dialectId, keyword);
37
37
  if (!keywordId) {
38
38
  throw Error(`Encountered unknown keyword '${keyword}' at ${url}`);
@@ -49,8 +49,8 @@ const compile = async (schema, ast) => {
49
49
  const keywordAst = await keywordHandler.compile(keywordSchema, ast, schema);
50
50
  return [keywordId, Schema.uri(keywordSchema), keywordAst];
51
51
  }),
52
- Pact.all
53
- ], schema);
52
+ asyncCollectArray
53
+ );
54
54
  }
55
55
 
56
56
  return url;
package/lib/schema.d.ts CHANGED
@@ -25,18 +25,14 @@ export const typeOf: (
25
25
  );
26
26
  export const has: (key: string, doc: SchemaDocument) => boolean;
27
27
  export const step: (key: string, doc: SchemaDocument) => Promise<SchemaDocument>;
28
- export const keys: (doc: SchemaDocument) => string[];
29
- export const entries: (doc: SchemaDocument) => Promise<SchemaEntry[]>;
30
- export const map: (
31
- <A>(fn: MapFn<Promise<A> | A>, doc: SchemaDocument) => Promise<A[]>
32
- ) & (
33
- <A>(fn: MapFn<Promise<A> | A>) => (doc: SchemaDocument) => Promise<A[]>
34
- );
28
+ export const iter: (doc: SchemaDocument) => AsyncGenerator<SchemaDocument>;
29
+ export const keys: (doc: SchemaDocument) => Generator<string>;
30
+ export const values: (doc: SchemaDocument) => AsyncGenerator<string>;
31
+ export const entries: (doc: SchemaDocument) => AsyncGenerator<[string, SchemaDocument]>;
35
32
  export const length: (doc: SchemaDocument) => number;
36
33
  export const toSchema: (doc: SchemaDocument, options: ToSchemaOptions) => SchemaObject;
37
34
 
38
35
  type MapFn<A> = (element: SchemaDocument, index: number) => A;
39
- export type SchemaEntry = [string, SchemaDocument];
40
36
 
41
37
  export type ToSchemaOptions = {
42
38
  parentId?: string;
package/lib/schema.js CHANGED
@@ -1,5 +1,3 @@
1
- import curry from "just-curry-it";
2
- import * as Pact from "@hyperjump/pact";
3
1
  import { nil as nilPointer, append as pointerAppend, get as pointerGet } from "@hyperjump/json-pointer";
4
2
  import { toAbsoluteIri } from "@hyperjump/uri";
5
3
  import { jsonTypeOf, resolveUri, uriFragment, pathRelative, jsonStringify } from "./common.js";
@@ -220,20 +218,29 @@ export const step = (key, doc) => {
220
218
  });
221
219
  };
222
220
 
223
- export const keys = (doc) => Object.keys(value(doc));
221
+ export const iter = async function* (doc) {
222
+ for (let index = 0; index < value(doc).length; index++) {
223
+ yield step(index, doc);
224
+ }
225
+ };
224
226
 
225
- export const entries = (doc) => Pact.pipeline([
226
- value,
227
- Object.keys,
228
- Pact.map(async (key) => [key, await step(key, doc)]),
229
- Pact.all
230
- ], doc);
227
+ export const keys = function* (doc) {
228
+ for (const key in value(doc)) {
229
+ yield key;
230
+ }
231
+ };
231
232
 
232
- export const map = curry((fn, doc) => Pact.pipeline([
233
- value,
234
- Pact.map(async (item, ndx) => fn(await step(ndx, doc), ndx)),
235
- Pact.all
236
- ], doc));
233
+ export const values = async function* (doc) {
234
+ for (const key in value(doc)) {
235
+ yield step(key, doc);
236
+ }
237
+ };
238
+
239
+ export const entries = async function* (doc) {
240
+ for (const key in value(doc)) {
241
+ yield [key, await step(key, doc)];
242
+ }
243
+ };
237
244
 
238
245
  export const length = (doc) => value(doc).length;
239
246
 
@@ -65,6 +65,10 @@ loadDialect(jsonSchemaVersion, {
65
65
  [jsonSchemaVersion]: true
66
66
  });
67
67
 
68
+ loadDialect("https://spec.openapis.org/oas/3.0/schema", {
69
+ [jsonSchemaVersion]: true
70
+ });
71
+
68
72
  addSchema(dialectSchema);
69
73
 
70
74
  addSchema(schema20210928, "https://spec.openapis.org/oas/3.0/schema");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperjump/json-schema",
3
- "version": "1.4.6",
3
+ "version": "1.5.1",
4
4
  "description": "A JSON Schema validator with support for custom keywords, vocabularies, and dialects",
5
5
  "type": "module",
6
6
  "main": "./stable/index.js",
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@hyperjump/json-pointer": "^1.0.0",
67
- "@hyperjump/pact": "^0.2.4",
67
+ "@hyperjump/pact": "^1.0.0",
68
68
  "@hyperjump/uri": "^1.2.0",
69
69
  "content-type": "^1.0.4",
70
70
  "fastest-stable-stringify": "^2.0.2",