Skip to content

Commit 3406a25

Browse files
committed
fix(file): support trailing slashes in file resolver #389
1 parent 171e30f commit 3406a25

File tree

6 files changed

+107
-6
lines changed

6 files changed

+107
-6
lines changed

lib/resolvers/file.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ export default {
3131
e.message = `Malformed URI: ${file.url}: ${e.message}`;
3232
throw new ResolverError(e, file.url);
3333
}
34+
// strip trailing slashes
35+
if (path.endsWith("/") || path.endsWith("\\")) {
36+
path = path.slice(0, -1);
37+
}
3438
try {
3539
return await fs.promises.readFile(path);
3640
} catch (err: any) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
title: Person
2+
type: object
3+
required:
4+
- name
5+
properties:
6+
name:
7+
$ref: "definitions/definitions.json/#/name"
8+
age:
9+
$ref: "definitions/definitions.json/#/age"
10+
gender:
11+
$ref: "definitions/definitions.json/#/gender"

test/specs/external-partial/external-partial.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import $RefParser from "../../../lib/index.js";
33
import helper from "../../utils/helper.js";
44
import path from "../../utils/path.js";
55
import parsedSchema from "./parsed.js";
6+
import parsedSchemaTrailing from "./parsed-trailing.js";
67
import dereferencedSchema from "./dereferenced.js";
78
import bundledSchema from "./bundled.js";
89

@@ -17,6 +18,16 @@ describe("Schema with $refs to parts of external files", () => {
1718
expect(parser.$refs.paths()).to.deep.equal([path.abs("test/specs/external-partial/external-partial.yaml")]);
1819
});
1920

21+
it("should parse successfully with files with trailing slashes", async () => {
22+
const parser = new $RefParser();
23+
const schema = await parser.parse(path.rel("test/specs/external-partial/external-partial-trailing-slash.yaml"));
24+
expect(schema).to.equal(parser.schema);
25+
expect(schema).to.deep.equal(parsedSchemaTrailing.schema);
26+
expect(parser.$refs.paths()).to.deep.equal([
27+
path.abs("test/specs/external-partial/external-partial-trailing-slash.yaml"),
28+
]);
29+
});
30+
2031
it(
2132
"should resolve successfully",
2233
helper.testResolve(
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export default {
2+
schema: {
3+
required: ["name"],
4+
type: "object",
5+
properties: {
6+
gender: {
7+
$ref: "definitions/definitions.json/#/gender",
8+
},
9+
age: {
10+
$ref: "definitions/definitions.json/#/age",
11+
},
12+
name: {
13+
$ref: "definitions/definitions.json/#/name",
14+
},
15+
},
16+
title: "Person",
17+
},
18+
19+
definitions: {
20+
"required string": {
21+
$ref: "required-string.yaml",
22+
},
23+
string: {
24+
$ref: "#/required%20string/type",
25+
},
26+
name: {
27+
$ref: "../definitions/name.yaml",
28+
},
29+
age: {
30+
type: "integer",
31+
minimum: 0,
32+
},
33+
gender: {
34+
type: "string",
35+
enum: ["male", "female"],
36+
},
37+
},
38+
39+
name: {
40+
required: ["first", "last"],
41+
type: "object",
42+
properties: {
43+
middle: {
44+
minLength: {
45+
$ref: "definitions.json#/name/properties/first/minLength",
46+
},
47+
type: {
48+
$ref: "definitions.json#/name/properties/first/type",
49+
},
50+
},
51+
prefix: {
52+
minLength: 3,
53+
$ref: "../definitions/definitions.json#/name/properties/last",
54+
},
55+
last: {
56+
$ref: "./required-string.yaml",
57+
},
58+
suffix: {
59+
$ref: "definitions.json#/name/properties/prefix",
60+
type: "string",
61+
maxLength: 3,
62+
},
63+
first: {
64+
$ref: "../definitions/definitions.json#/required string",
65+
},
66+
},
67+
title: "name",
68+
},
69+
70+
requiredString: {
71+
minLength: 1,
72+
type: "string",
73+
title: "required string",
74+
},
75+
};

test/utils/helper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const helper = {
1818
* @param {...*} [params] - The expected resolved file paths and values
1919
* @returns {Function}
2020
*/
21-
testResolve(filePath: string) {
21+
testResolve(filePath: string, ..._args: any[]) {
2222
const parsedSchema = arguments[2];
2323
const expectedFiles: any = [];
2424
const messages: any = [];

test/utils/path.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,27 +138,27 @@ function urlPathHelpers() {
138138
}
139139

140140
export default {
141-
rel() {
141+
rel(..._args: any[]) {
142142
// @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
143143
return !isDom ? pathHelpers.filesystem.rel(...arguments) : pathHelpers.url.rel(...arguments);
144144
},
145145

146-
abs() {
146+
abs(..._args: any[]) {
147147
// @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
148148
return !isDom ? pathHelpers.filesystem.abs(...arguments) : pathHelpers.url.abs(...arguments);
149149
},
150150

151-
unixify() {
151+
unixify(..._args: any[]) {
152152
// @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
153153
return !isDom ? pathHelpers.filesystem.unixify(...arguments) : pathHelpers.url.unixify(...arguments);
154154
},
155155

156-
url() {
156+
url(..._args: any[]) {
157157
// @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
158158
return !isDom ? pathHelpers.filesystem.url(...arguments) : pathHelpers.url.url(...arguments);
159159
},
160160

161-
cwd() {
161+
cwd(..._args: any[]) {
162162
// @ts-expect-error TS(2556): A spread argument must either have a tuple type or... Remove this comment to see the full error message
163163
return !isDom ? pathHelpers.filesystem.cwd(...arguments) : pathHelpers.url.cwd(...arguments);
164164
},

0 commit comments

Comments
 (0)