Skip to content

Commit 497c56f

Browse files
committed
fix: This corrects the behavior for nested resolution for json schemas.
For example the old behavior relied on relative path from the process directory instead of the schema definition directory as according to the spec. The interface change exposes receiving the parent/root schema in the argument to custom protocol handlers. This allows the user to read this schema and gain contextual information that is useful for resolving issues like the aforementioned.
1 parent 3f8035d commit 497c56f

File tree

5 files changed

+22
-9
lines changed

5 files changed

+22
-9
lines changed

nestedtest/test-schema.json

Whitespace-only changes.

src/default-protocol-handler-map.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { InvalidRemoteURLError, NonJsonRefError } from "./errors";
33
import { JSONSchema } from "@json-schema-tools/meta-schema";
44
import fetch from "isomorphic-fetch";
55

6-
const fetchHandler = async (uri: string): Promise<JSONSchema> => {
6+
const fetchHandler = async (uri: string, root: JSONSchema): Promise<JSONSchema> => {
77
let schemaReq;
88
try {
99
schemaReq = await fetch(uri);

src/index.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ describe("referenceResolver", () => {
7171
expect(resolved.$ref).toBe("./src/test-schema.json");
7272
});
7373

74+
it("works with nested folders when using different root context", async () => {
75+
expect.assertions(1);
76+
const resolved = await referenceResolver
77+
.resolve("./test-schema-1.json", {
78+
"$ref": "./nestedtest/test-schema.json"
79+
}) as JSONSchemaObject;
80+
expect(resolved.$ref).toBe("./src/test-schema.json");
81+
});
82+
7483
it("errors on urls that arent real", async () => {
7584
expect.assertions(1);
7685
try {

src/index.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import ReferenceResolver, { ProtocolHandlerMap } from "./reference-resolver";
22
import * as fs from "fs";
3-
import { JSONSchema } from "@json-schema-tools/meta-schema";
3+
import { JSONSchema, JSONSchemaObject } from "@json-schema-tools/meta-schema";
44
import { InvalidRemoteURLError, NonJsonRefError } from "./errors";
55
import defaultProtocolHandlerMap from "./default-protocol-handler-map";
6+
import path from "path";
67

78
const fileExistsAndReadable = (f: string): Promise<boolean> => {
89
return new Promise((resolve) => {
@@ -19,12 +20,15 @@ const readFile = (f: string): Promise<string> => {
1920

2021
const nodeProtocolHandlerMap: ProtocolHandlerMap = {
2122
...defaultProtocolHandlerMap,
22-
"file": async (uri) => {
23-
if (await fileExistsAndReadable(uri) === true) {
24-
const fileContents = await readFile(uri);
23+
"file": async (uri,root: JSONSchema) => {
24+
let filePath = uri;
25+
const ref = (root as JSONSchemaObject).$ref;
26+
if(ref && ref !== uri && await fileExistsAndReadable(ref)) filePath = `${path.parse(ref).dir}/${uri}`;
27+
if (await fileExistsAndReadable(filePath) === true) {
28+
const fileContents = await readFile(filePath);
2529
return JSON.parse(fileContents) as JSONSchema;
2630
}
27-
}
31+
},
2832
}
2933

3034
export default new ReferenceResolver(nodeProtocolHandlerMap);

src/reference-resolver.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const isUrlLike = (s: string) => {
1111
}
1212

1313
export interface ProtocolHandlerMap {
14-
[protocol: string]: (uri: string) => Promise<JSONSchema | undefined>;
14+
[protocol: string]: (uri: string, root: JSONSchema) => Promise<JSONSchema | undefined>;
1515
};
1616

1717
export default class ReferenceResolver {
@@ -41,7 +41,7 @@ export default class ReferenceResolver {
4141
// protocol handler
4242
let relativePathSchema;
4343
try {
44-
relativePathSchema = await this.protocolHandlerMap.file(hashlessRef);
44+
relativePathSchema = await this.protocolHandlerMap.file(hashlessRef, root);
4545
} catch (e) {
4646
throw new NonJsonRefError({ $ref: ref }, e.message);
4747
}
@@ -57,7 +57,7 @@ export default class ReferenceResolver {
5757

5858
for (const protocol of Object.keys(this.protocolHandlerMap)) {
5959
if (hashlessRef.startsWith(protocol)) {
60-
const maybeSchema = await this.protocolHandlerMap[protocol](hashlessRef);
60+
const maybeSchema = await this.protocolHandlerMap[protocol](hashlessRef, root);
6161

6262
if (maybeSchema !== undefined) {
6363
let schema: JSONSchema = maybeSchema;

0 commit comments

Comments
 (0)