@hyperjump/json-schema 1.1.0 → 1.1.2

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.
@@ -7,7 +7,6 @@ const id = "https://json-schema.org/keyword/draft-04/maximum";
7
7
 
8
8
  const compile = async (schema, ast, parentSchema) => {
9
9
  const exclusiveMaximumKeyword = getKeywordName(schema.dialectId, "https://json-schema.org/keyword/draft-04/exclusiveMaximum");
10
- console.log(exclusiveMaximumKeyword);
11
10
  const exclusiveMaximum = await Schema.step(exclusiveMaximumKeyword, parentSchema);
12
11
  const isExclusive = Schema.value(exclusiveMaximum);
13
12
 
@@ -3,10 +3,11 @@ import Validation from "../lib/keywords/validation.js";
3
3
 
4
4
  const id = "https://json-schema.org/keyword/draft-2019-09/recursiveRef";
5
5
 
6
- const compile = async (schema) => schema.id;
6
+ const compile = (schema) => schema.id;
7
7
 
8
8
  const interpret = (id, instance, ast, dynamicAnchors) => {
9
9
  if ("" in ast.metaData[id].dynamicAnchors) {
10
+ dynamicAnchors = { ...ast.metaData[id].dynamicAnchors, ...dynamicAnchors };
10
11
  return Validation.interpret(dynamicAnchors[""], instance, ast, dynamicAnchors);
11
12
  } else {
12
13
  return Validation.interpret(`${id}#`, instance, ast, dynamicAnchors);
@@ -1,19 +1,20 @@
1
1
  import Validation from "../lib/keywords/validation.js";
2
2
  import * as Schema from "../lib/schema.js";
3
+ import { uriFragment } from "../lib/common.js";
3
4
 
4
5
 
5
6
  const id = "https://json-schema.org/keyword/draft-2020-12/dynamicRef";
6
7
 
7
8
  const compile = async (dynamicRef, ast) => {
8
- const [, fragment] = splitUrl(Schema.value(dynamicRef));
9
+ const fragment = uriFragment(Schema.value(dynamicRef));
9
10
  const referencedSchema = await Schema.get(Schema.value(dynamicRef), dynamicRef);
10
11
  await Validation.compile(referencedSchema, ast);
11
12
  return [referencedSchema.id, fragment, Schema.uri(referencedSchema)];
12
-
13
13
  };
14
14
 
15
15
  const interpret = ([id, fragment, ref], instance, ast, dynamicAnchors) => {
16
16
  if (fragment in ast.metaData[id].dynamicAnchors) {
17
+ dynamicAnchors = { ...ast.metaData[id].dynamicAnchors, ...dynamicAnchors };
17
18
  return Validation.interpret(dynamicAnchors[fragment], instance, ast, dynamicAnchors);
18
19
  } else {
19
20
  return Validation.interpret(ref, instance, ast, dynamicAnchors);
@@ -23,13 +24,4 @@ const interpret = ([id, fragment, ref], instance, ast, dynamicAnchors) => {
23
24
  const collectEvaluatedProperties = Validation.collectEvaluatedProperties;
24
25
  const collectEvaluatedItems = Validation.collectEvaluatedItems;
25
26
 
26
- const splitUrl = (url) => {
27
- const indexOfHash = url.indexOf("#");
28
- const ndx = indexOfHash === -1 ? url.length : indexOfHash;
29
- const urlReference = url.slice(0, ndx);
30
- const urlFragment = url.slice(ndx + 1);
31
-
32
- return [decodeURI(urlReference), decodeURI(urlFragment)];
33
- };
34
-
35
27
  export default { id, compile, interpret, collectEvaluatedProperties, collectEvaluatedItems };
package/lib/common.js CHANGED
@@ -1,3 +1,6 @@
1
+ import { resolveIri, toAbsoluteIri, parseIriReference } from "@hyperjump/uri";
2
+
3
+
1
4
  const isObject = (value) => typeof value === "object" && !Array.isArray(value) && value !== null;
2
5
  const isType = {
3
6
  null: (value) => value === null,
@@ -10,15 +13,16 @@ const isType = {
10
13
  };
11
14
  export const jsonTypeOf = (value, type) => isType[type](value);
12
15
 
13
- export const resolveUrl = (url, baseUri = undefined) => {
14
- const resolved = new URL(url, baseUri);
15
- if (baseUri && new URL("", baseUri).protocol !== "file:" && resolved.protocol === "file:") {
16
- throw Error(`Can't access file '${resolved.href}' resource from network context '${baseUri}'`);
16
+ export const resolveUri = (uri, baseUri) => {
17
+ const resolved = resolveIri(uri, baseUri);
18
+ if (resolved.startsWith("file:") && baseUri && !baseUri.startsWith("file:")) {
19
+ throw Error(`Can't access file '${resolved}' resource from network context '${baseUri}'`);
17
20
  }
18
- return resolved.href;
21
+ return resolved;
19
22
  };
20
23
 
21
- export const urlFragment = (url) => decodeURIComponent(new URL(url).hash.slice(1));
24
+ export const toAbsoluteUri = (uri) => toAbsoluteIri(uri);
25
+ export const uriFragment = (uri) => decodeURIComponent(parseIriReference(uri).fragment || "");
22
26
 
23
27
  const CHAR_BACKWARD_SLASH = 47;
24
28
 
@@ -1,6 +1,6 @@
1
1
  let metaSchemaOutputFormat;
2
2
  let shouldValidateSchema = true;
3
- let enabledExperimentalKeywords = {};
3
+ const enabledExperimentalKeywords = {};
4
4
 
5
5
  export const getMetaSchemaOutputFormat = () => metaSchemaOutputFormat;
6
6
  export const setMetaSchemaOutputFormat = (format) => {
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { addSchema, validate, FLAG } from "./core.js";
2
- export type { Validator, OutputFormat, CompiledSchema, Result } from "./core.js";
2
+ export type { Validator, OutputFormat, CompiledSchema, OutputUnit } from "./core.js";
3
3
  export {
4
4
  getMetaSchemaOutputFormat,
5
5
  setMetaSchemaOutputFormat,
package/lib/instance.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import * as JsonPointer from "@hyperjump/json-pointer";
2
2
  import curry from "just-curry-it";
3
- import { resolveUrl, jsonTypeOf } from "./common.js";
3
+ import { toAbsoluteUri, jsonTypeOf } from "./common.js";
4
4
  import * as Reference from "./reference.js";
5
5
 
6
6
 
7
- export const nil = Object.freeze({ id: undefined, pointer: "", instance: undefined, value: undefined });
8
- export const cons = (instance, id = undefined) => Object.freeze({
7
+ export const nil = { id: undefined, pointer: "", instance: undefined, value: undefined };
8
+ export const cons = (instance, id = undefined) => ({
9
9
  ...nil,
10
- id: id ? resolveUrl("", id) : "",
10
+ id: id ? toAbsoluteUri(id) : "",
11
11
  instance,
12
12
  value: instance
13
13
  });
@@ -17,7 +17,7 @@ export const get = (url, instance = nil) => {
17
17
  throw Error(`No JSON document found at '${url.split("#")[0]}'`);
18
18
  }
19
19
 
20
- return Object.freeze({ ...instance, pointer: url.substr(1) });
20
+ return { ...instance, pointer: url.substr(1) };
21
21
  };
22
22
 
23
23
  export const uri = (doc) => `${doc.id || ""}#${encodeURI(doc.pointer)}`;
@@ -25,7 +25,7 @@ export const value = (doc) => Reference.isReference(doc.value) ? Reference.value
25
25
  export const has = (key, doc) => key in value(doc);
26
26
  export const typeOf = curry((doc, type) => jsonTypeOf(value(doc), type));
27
27
 
28
- export const step = (key, doc) => Object.freeze({
28
+ export const step = (key, doc) => ({
29
29
  ...doc,
30
30
  pointer: JsonPointer.append(key, doc.pointer),
31
31
  value: value(doc)[key]
@@ -18,14 +18,14 @@ const interpret = (anyOf, instance, ast, dynamicAnchors) => {
18
18
  const collectEvaluatedProperties = (anyOf, instance, ast, dynamicAnchors) => {
19
19
  return anyOf.reduce((acc, schemaUrl) => {
20
20
  const propertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, ast, dynamicAnchors);
21
- return propertyNames !== false ? [...acc || [], ...propertyNames] : acc;
21
+ return propertyNames === false ? acc : [...acc || [], ...propertyNames];
22
22
  }, false);
23
23
  };
24
24
 
25
25
  const collectEvaluatedItems = (anyOf, instance, ast, dynamicAnchors) => {
26
26
  return anyOf.reduce((acc, schemaUrl) => {
27
27
  const itemIndexes = Validation.collectEvaluatedItems(schemaUrl, instance, ast, dynamicAnchors);
28
- return itemIndexes !== false ? new Set([...acc || [], ...itemIndexes]) : acc;
28
+ return itemIndexes === false ? acc : new Set([...acc || [], ...itemIndexes]);
29
29
  }, false);
30
30
  };
31
31
 
@@ -32,17 +32,17 @@ const interpret = ({ contains, minContains, maxContains }, instance, ast, dynami
32
32
  };
33
33
 
34
34
  const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
35
- return interpret(keywordValue, instance, ast, dynamicAnchors) &&
36
- Instance.typeOf(instance, "array") &&
37
- Instance.reduce((matchedIndexes, item, itemIndex) => {
35
+ return interpret(keywordValue, instance, ast, dynamicAnchors)
36
+ && Instance.typeOf(instance, "array")
37
+ && Instance.reduce((matchedIndexes, item, itemIndex) => {
38
38
  return Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors) ? matchedIndexes.add(itemIndex) : matchedIndexes;
39
39
  }, new Set(), instance);
40
40
  };
41
41
 
42
42
  const collectEvaluatedProperties = (keywordValue, instance, ast, dynamicAnchors) => {
43
- return interpret(keywordValue, instance, ast, dynamicAnchors) &&
44
- Instance.typeOf(instance, "object") &&
45
- Instance.entries(instance).reduce((matchedPropertyNames, [propertyName, item]) => {
43
+ return interpret(keywordValue, instance, ast, dynamicAnchors)
44
+ && Instance.typeOf(instance, "object")
45
+ && Instance.entries(instance).reduce((matchedPropertyNames, [propertyName, item]) => {
46
46
  if (Validation.interpret(keywordValue.contains, item, ast, dynamicAnchors)) {
47
47
  matchedPropertyNames.push(propertyName);
48
48
  }
@@ -23,10 +23,9 @@ const interpret = ([guard, block], instance, ast, dynamicAnchors) => {
23
23
  const quietInterpretSchema = (url, instance, ast, dynamicAnchors) => {
24
24
  const nodes = ast[url][2];
25
25
 
26
- return typeof nodes === "boolean" ? nodes : nodes
27
- .every(([keywordId, , keywordValue]) => {
28
- return getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
29
- });
26
+ return typeof nodes === "boolean" ? nodes : nodes.every(([keywordId, , keywordValue]) => {
27
+ return getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
28
+ });
30
29
  };
31
30
 
32
31
  const collectEvaluatedProperties = ([guard, block], instance, ast, dynamicAnchors) => {
@@ -4,7 +4,7 @@ import * as Instance from "../instance.js";
4
4
 
5
5
  const id = "https://json-schema.org/keyword/exclusiveMaximum";
6
6
 
7
- const compile = async (schema) => Schema.value(schema);
7
+ const compile = (schema) => Schema.value(schema);
8
8
  const interpret = (exclusiveMaximum, instance) => !Instance.typeOf(instance, "number") || Instance.value(instance) < exclusiveMaximum;
9
9
 
10
10
  export default { id, compile, interpret };
@@ -4,7 +4,7 @@ import * as Instance from "../instance.js";
4
4
 
5
5
  const id = "https://json-schema.org/keyword/exclusiveMinimum";
6
6
 
7
- const compile = async (schema) => Schema.value(schema);
7
+ const compile = (schema) => Schema.value(schema);
8
8
  const interpret = (exclusiveMinimum, instance) => !Instance.typeOf(instance, "number") || Instance.value(instance) > exclusiveMinimum;
9
9
 
10
10
  export default { id, compile, interpret };
@@ -4,7 +4,7 @@ import * as Instance from "../instance.js";
4
4
 
5
5
  const id = "https://json-schema.org/keyword/maximum";
6
6
 
7
- const compile = async (schema) => Schema.value(schema);
7
+ const compile = (schema) => Schema.value(schema);
8
8
  const interpret = (maximum, instance) => !Instance.typeOf(instance, "number") || Instance.value(instance) <= maximum;
9
9
 
10
10
  export default { id, compile, interpret };
@@ -4,7 +4,7 @@ import * as Instance from "../instance.js";
4
4
 
5
5
  const id = "https://json-schema.org/keyword/minimum";
6
6
 
7
- const compile = async (schema) => Schema.value(schema);
7
+ const compile = (schema) => Schema.value(schema);
8
8
  const interpret = (minimum, instance) => !Instance.typeOf(instance, "number") || Instance.value(instance) >= minimum;
9
9
 
10
10
  export default { id, compile, interpret };
@@ -7,7 +7,7 @@ import Validation from "./validation.js";
7
7
  const id = "https://json-schema.org/keyword/propertyDependencies";
8
8
  const experimental = true;
9
9
 
10
- const compile = async (schema, ast) => {
10
+ const compile = (schema, ast) => {
11
11
  return Pact.pipeline([
12
12
  Schema.entries,
13
13
  Pact.reduce(async (propertyDependencies, [propertyName, valueMappings]) => {
@@ -18,7 +18,7 @@ const compile = async (schema, ast, parentSchema) => {
18
18
  };
19
19
 
20
20
  const interpret = (required, instance) => {
21
- return !Instance.typeOf(instance, "object") || required.every((propertyName) => Instance.value(instance).hasOwnProperty(propertyName));
21
+ return !Instance.typeOf(instance, "object") || required.every((propertyName) => Object.hasOwn(Instance.value(instance), propertyName));
22
22
  };
23
23
 
24
24
  export default { id, experimental, compile, interpret };
@@ -7,7 +7,7 @@ const id = "https://json-schema.org/keyword/required";
7
7
  const compile = (schema) => Schema.value(schema);
8
8
 
9
9
  const interpret = (required, instance) => {
10
- return !Instance.typeOf(instance, "object") || required.every((propertyName) => Object.prototype.hasOwnProperty.call(Instance.value(instance), propertyName));
10
+ return !Instance.typeOf(instance, "object") || required.every((propertyName) => Object.hasOwn(Instance.value(instance), propertyName));
11
11
  };
12
12
 
13
13
  export default { id, compile, interpret };
@@ -23,10 +23,9 @@ const interpret = ([guard, block], instance, ast, dynamicAnchors) => {
23
23
  const quietInterpretSchema = (url, instance, ast, dynamicAnchors) => {
24
24
  const nodes = ast[url][2];
25
25
 
26
- return typeof nodes === "boolean" ? nodes : nodes
27
- .every(([keywordId, , keywordValue]) => {
28
- return getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
29
- });
26
+ return typeof nodes === "boolean" ? nodes : nodes.every(([keywordId, , keywordValue]) => {
27
+ return getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
28
+ });
30
29
  };
31
30
 
32
31
  const collectEvaluatedProperties = ([guard, block], instance, ast, dynamicAnchors) => {
@@ -21,7 +21,7 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, ast, dynamicAnc
21
21
  .every(([, property]) => Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors));
22
22
  };
23
23
 
24
- const collectEvaluatedProperties = (keywordValue, instance, ast, dynamicAnchors) =>{
24
+ const collectEvaluatedProperties = (keywordValue, instance, ast, dynamicAnchors) => {
25
25
  return interpret(keywordValue, instance, ast, dynamicAnchors) && [new RegExp("")];
26
26
  };
27
27
 
@@ -3,7 +3,7 @@ import { publishAsync, publish } from "../pubsub.js";
3
3
  import { isExperimentalKeywordEnabled } from "../configuration.js";
4
4
  import * as Instance from "../instance.js";
5
5
  import { getKeywordId, getKeyword } from "../keywords.js";
6
- import { resolveUrl } from "../common.js";
6
+ import { toAbsoluteUri } from "../common.js";
7
7
  import * as Schema from "../schema.js";
8
8
 
9
9
 
@@ -60,24 +60,23 @@ const compile = async (schema, ast) => {
60
60
  const interpret = (url, instance, ast, dynamicAnchors) => {
61
61
  const [keywordId, schemaUrl, nodes] = ast[url];
62
62
 
63
- dynamicAnchors = { ...ast.metaData[resolveUrl("", url)].dynamicAnchors, ...dynamicAnchors };
63
+ dynamicAnchors = { ...ast.metaData[toAbsoluteUri(url)].dynamicAnchors, ...dynamicAnchors };
64
64
 
65
65
  publish("result.start");
66
- const isValid = typeof nodes === "boolean" ? nodes : nodes
67
- .every(([keywordId, schemaUrl, keywordValue]) => {
68
- publish("result.start");
69
- const isValid = getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
70
-
71
- publish("result", {
72
- keyword: keywordId,
73
- absoluteKeywordLocation: schemaUrl,
74
- instanceLocation: Instance.uri(instance),
75
- valid: isValid,
76
- ast: keywordValue
77
- });
78
- publish("result.end");
79
- return isValid;
66
+ const isValid = typeof nodes === "boolean" ? nodes : nodes.every(([keywordId, schemaUrl, keywordValue]) => {
67
+ publish("result.start");
68
+ const isValid = getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors);
69
+
70
+ publish("result", {
71
+ keyword: keywordId,
72
+ absoluteKeywordLocation: schemaUrl,
73
+ instanceLocation: Instance.uri(instance),
74
+ valid: isValid,
75
+ ast: keywordValue
80
76
  });
77
+ publish("result.end");
78
+ return isValid;
79
+ });
81
80
 
82
81
  publish("result", {
83
82
  keyword: keywordId,
package/lib/keywords.js CHANGED
@@ -6,8 +6,12 @@ export const getKeyword = (id) => _keywords[id] || id.startsWith("https://json-s
6
6
 
7
7
  export const addKeyword = (keywordHandler) => {
8
8
  _keywords[keywordHandler.id] = {
9
- collectEvaluatedItems: (keywordValue, instance, ast, dynamicAnchors, isTop) => keywordHandler.interpret(keywordValue, instance, ast, dynamicAnchors, isTop) && new Set(),
10
- collectEvaluatedProperties: (keywordValue, instance, ast, dynamicAnchors, isTop) => keywordHandler.interpret(keywordValue, instance, ast, dynamicAnchors, isTop) && [],
9
+ collectEvaluatedItems: (keywordValue, instance, ast, dynamicAnchors, isTop) => {
10
+ return keywordHandler.interpret(keywordValue, instance, ast, dynamicAnchors, isTop) && new Set();
11
+ },
12
+ collectEvaluatedProperties: (keywordValue, instance, ast, dynamicAnchors, isTop) => {
13
+ return keywordHandler.interpret(keywordValue, instance, ast, dynamicAnchors, isTop) && [];
14
+ },
11
15
  ...keywordHandler
12
16
  };
13
17
  };
package/lib/pubsub.js CHANGED
@@ -37,6 +37,4 @@ export const publishAsync = async (message, data) => {
37
37
  }
38
38
 
39
39
  await Promise.all(promises);
40
-
41
- return;
42
40
  };
package/lib/reference.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const $__value = Symbol("$__value");
2
2
  const $__href = Symbol("$__href");
3
3
 
4
- export const cons = (href, value) => Object.freeze({
4
+ export const cons = (href, value) => ({
5
5
  [$__href]: href,
6
6
  [$__value]: value
7
7
  });
package/lib/schema.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { JsonType } from "./common.js";
2
2
 
3
3
 
4
- export const add: <A extends SchemaObject | boolean>(schema: A, url?: string, defaultSchemaVersion?: string) => string;
4
+ export const add: <A extends SchemaObject | boolean>(schema: A, retrievalUri?: string, defaultSchemaVersion?: string) => string;
5
5
  export const get: (url: string, context?: SchemaDocument) => Promise<SchemaDocument>;
6
6
  export const markValidated: (id: string) => void;
7
7
  export const uri: (doc: SchemaDocument) => string;
package/lib/schema.js CHANGED
@@ -2,7 +2,7 @@ import curry from "just-curry-it";
2
2
  import * as Pact from "@hyperjump/pact";
3
3
  import * as Json from "@hyperjump/json";
4
4
  import * as JsonPointer from "@hyperjump/json-pointer";
5
- import { jsonTypeOf, resolveUrl, urlFragment, pathRelative } from "./common.js";
5
+ import { jsonTypeOf, resolveUri, toAbsoluteUri, uriFragment, pathRelative } from "./common.js";
6
6
  import fetch from "./fetch.js";
7
7
  import * as Keywords from "./keywords.js";
8
8
  import * as MediaTypes from "./media-types.js";
@@ -15,11 +15,11 @@ const schemaStoreAlias = {};
15
15
 
16
16
  const defaultDialectId = "https://json-schema.org/validation";
17
17
 
18
- export const add = (schema, url = undefined, contextDialectId = undefined) => {
18
+ export const add = (schema, retrievalUri = undefined, contextDialectId = undefined) => {
19
19
  schema = JSON.parse(JSON.stringify(schema));
20
20
 
21
21
  // Dialect / JSON Schema Version
22
- const dialectId = resolveUrl("", schema.$schema || contextDialectId || defaultDialectId);
22
+ const dialectId = toAbsoluteUri(schema.$schema || contextDialectId || defaultDialectId);
23
23
  delete schema.$schema;
24
24
 
25
25
  if (!Keywords.hasDialect(dialectId)) {
@@ -29,11 +29,14 @@ export const add = (schema, url = undefined, contextDialectId = undefined) => {
29
29
  // Identifiers
30
30
  const idToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/id")
31
31
  || Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id");
32
- const internalUrl = resolveUrl(schema[idToken] || url, url);
33
- const id = resolveUrl("", internalUrl);
32
+ if (retrievalUri === undefined && !(idToken in schema)) {
33
+ throw Error(`Unable to determine an identifier for the schema. Use the '${idToken}' keyword or pass a retrievalUri when loading the schema.`);
34
+ }
35
+ const internalUrl = resolveUri(schema[idToken] || retrievalUri, retrievalUri);
36
+ const id = toAbsoluteUri(internalUrl);
34
37
  delete schema[idToken];
35
- if (url) {
36
- const externalId = resolveUrl("", url);
38
+ if (retrievalUri) {
39
+ const externalId = toAbsoluteUri(retrievalUri);
37
40
  schemaStoreAlias[externalId] = id;
38
41
  }
39
42
 
@@ -80,7 +83,7 @@ const processSchema = (subject, id, dialectId, pointer, anchors, dynamicAnchors)
80
83
  anchors[anchor] = pointer;
81
84
  } else {
82
85
  delete subject[legacyIdToken].$schema;
83
- subject[legacyIdToken] = resolveUrl(subject[legacyIdToken], id);
86
+ subject[legacyIdToken] = resolveUri(subject[legacyIdToken], id);
84
87
  add(subject, undefined, dialectId);
85
88
  return Reference.cons(subject[legacyIdToken], subject);
86
89
  }
@@ -88,10 +91,10 @@ const processSchema = (subject, id, dialectId, pointer, anchors, dynamicAnchors)
88
91
  }
89
92
 
90
93
  // Embedded Schema
91
- const embeddedDialectId = typeof subject.$schema === "string" ? resolveUrl("", subject.$schema) : dialectId;
94
+ const embeddedDialectId = typeof subject.$schema === "string" ? toAbsoluteUri(subject.$schema) : dialectId;
92
95
  const idToken = Keywords.getKeywordName(embeddedDialectId, "https://json-schema.org/keyword/id");
93
96
  if (typeof subject[idToken] === "string") {
94
- subject[idToken] = resolveUrl(subject[idToken], id);
97
+ subject[idToken] = resolveUri(subject[idToken], id);
95
98
  add(subject, undefined, dialectId);
96
99
  return Reference.cons(subject[idToken], subject);
97
100
  }
@@ -142,7 +145,7 @@ export const markValidated = (id) => {
142
145
  };
143
146
 
144
147
  // Schema Retrieval
145
- const nil = Object.freeze({
148
+ const nil = {
146
149
  id: undefined,
147
150
  dialectId: undefined,
148
151
  pointer: JsonPointer.nil,
@@ -151,12 +154,12 @@ const nil = Object.freeze({
151
154
  anchors: {},
152
155
  dynamicAnchors: {},
153
156
  validated: true
154
- });
157
+ };
155
158
 
156
159
  export const get = async (url, contextDoc = nil) => {
157
- const resolvedUrl = resolveUrl(url, uri(contextDoc));
158
- const id = resolveUrl("", resolvedUrl);
159
- const fragment = urlFragment(resolvedUrl);
160
+ const resolvedUrl = resolveUri(url, contextDoc.id);
161
+ const id = toAbsoluteUri(resolvedUrl);
162
+ const fragment = uriFragment(resolvedUrl);
160
163
 
161
164
  if (!hasStoredSchema(id)) {
162
165
  const response = await fetch(id, { headers: { Accept: "application/schema+json" } });
@@ -168,7 +171,7 @@ export const get = async (url, contextDoc = nil) => {
168
171
  const [schema, contextDialectId] = await MediaTypes.parse(response);
169
172
 
170
173
  // Try to determine the dialect from the meta-schema if it isn't already known
171
- const dialectId = resolveUrl("", schema.$schema || contextDialectId || defaultDialectId);
174
+ const dialectId = toAbsoluteUri(schema.$schema || contextDialectId || defaultDialectId);
172
175
  if (!Keywords.hasDialect(dialectId) && !hasStoredSchema(dialectId)) {
173
176
  await get(dialectId);
174
177
  }
@@ -177,12 +180,12 @@ export const get = async (url, contextDoc = nil) => {
177
180
  }
178
181
 
179
182
  const storedSchema = getStoredSchema(id);
180
- const pointer = fragment[0] !== "/" ? getAnchorPointer(storedSchema, fragment) : fragment;
181
- const doc = Object.freeze({
183
+ const pointer = fragment[0] === "/" ? fragment : getAnchorPointer(storedSchema, fragment);
184
+ const doc = {
182
185
  ...storedSchema,
183
186
  pointer: pointer,
184
187
  value: JsonPointer.get(pointer, storedSchema.schema)
185
- });
188
+ };
186
189
 
187
190
  return followReferences(doc);
188
191
  };
@@ -205,13 +208,12 @@ export const typeOf = (doc, type) => jsonTypeOf(value(doc), type);
205
208
 
206
209
  export const step = (key, doc) => {
207
210
  const storedSchema = getStoredSchema(doc.id);
208
- const nextDoc = Object.freeze({
211
+ return followReferences({
209
212
  ...doc,
210
213
  pointer: JsonPointer.append(`${key}`, doc.pointer),
211
214
  value: value(doc)[key],
212
215
  validated: storedSchema.validated
213
216
  });
214
- return followReferences(nextDoc);
215
217
  };
216
218
 
217
219
  export const keys = (doc) => Object.keys(value(doc));
@@ -254,16 +256,14 @@ export const toSchema = (schemaDoc, options = {}) => {
254
256
 
255
257
  const dynamicAnchors = {};
256
258
  for (const anchor in schemaDoc.dynamicAnchors) {
257
- const pointer = urlFragment(schemaDoc.dynamicAnchors[anchor]);
259
+ const pointer = uriFragment(schemaDoc.dynamicAnchors[anchor]);
258
260
  dynamicAnchors[pointer] = anchor;
259
261
  }
260
262
 
261
263
  const schema = JSON.parse(Json.stringify(schemaDoc.schema, (key, value, pointer) => {
262
264
  if (Reference.isReference(value)) {
263
265
  const refValue = Reference.value(value);
264
- if (!fullOptions.includeEmbedded && idToken in refValue) {
265
- return;
266
- } else {
266
+ if (fullOptions.includeEmbedded || !(idToken in refValue)) {
267
267
  return Reference.value(value);
268
268
  }
269
269
  } else {
@@ -292,8 +292,8 @@ export const toSchema = (schemaDoc, options = {}) => {
292
292
  const id = relativeUri(fullOptions.parentId, schemaDoc.id);
293
293
  const dialect = fullOptions.parentDialect === schemaDoc.dialectId ? "" : schemaDoc.dialectId;
294
294
  return {
295
- ...(id && { [idToken]: id }),
296
- ...(dialect && { $schema: dialect }),
295
+ ...id && { [idToken]: id },
296
+ ...dialect && { $schema: dialect },
297
297
  ...schema
298
298
  };
299
299
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperjump/json-schema",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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",
@@ -22,8 +22,8 @@
22
22
  },
23
23
  "scripts": {
24
24
  "clean": "xargs -a .gitignore rm -rf",
25
- "lint": "eslint lib",
26
- "test": "mocha 'lib/**/*.spec.ts' 'stable/**/*.spec.ts' 'draft-*/**/*.spec.ts' 'oas-*/**/*.spec.ts'"
25
+ "lint": "eslint lib stable draft-* openapi-*",
26
+ "test": "mocha 'lib/**/*.spec.ts' 'stable/**/*.spec.ts' 'draft-*/**/*.spec.ts' 'openapi-*/**/*.spec.ts'"
27
27
  },
28
28
  "repository": "github:hyperjump-io/json-schema",
29
29
  "keywords": [
@@ -64,6 +64,7 @@
64
64
  "@hyperjump/json": "^0.1.0",
65
65
  "@hyperjump/json-pointer": "^0.9.5",
66
66
  "@hyperjump/pact": "^0.2.4",
67
+ "@hyperjump/uri": "^1.0.0",
67
68
  "content-type": "^1.0.4",
68
69
  "fastest-stable-stringify": "^2.0.2",
69
70
  "node-fetch": "^3.3.0"