diff --git a/docs/options.md b/docs/options.md index f3c89f1a..1424a831 100644 --- a/docs/options.md +++ b/docs/options.md @@ -26,7 +26,8 @@ $RefParser.dereference("my-schema.yaml", { http: { timeout: 2000, // 2 second timeout withCredentials: true, // Include auth credentials when resolving HTTP references - } + }, + skipInternal: false // Skip internal/local references while parsing the document }, dereference: { circular: false // Don't allow circular $refs diff --git a/lib/bundle.js b/lib/bundle.js index d5578bf1..8f5c22c0 100644 --- a/lib/bundle.js +++ b/lib/bundle.js @@ -40,7 +40,7 @@ function crawl (parent, key, path, pathFromRoot, indirections, inventory, $refs, let obj = key === null ? parent : parent[key]; if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) { - if ($Ref.isAllowed$Ref(obj)) { + if ($Ref.isAllowed$Ref(obj, options)) { inventory$Ref(parent, key, path, pathFromRoot, indirections, inventory, $refs, options); } else { @@ -70,7 +70,7 @@ function crawl (parent, key, path, pathFromRoot, indirections, inventory, $refs, let keyPathFromRoot = Pointer.join(pathFromRoot, key); let value = obj[key]; - if ($Ref.isAllowed$Ref(value)) { + if ($Ref.isAllowed$Ref(value, options)) { inventory$Ref(obj, key, path, keyPathFromRoot, indirections, inventory, $refs, options); } else { diff --git a/lib/ref.js b/lib/ref.js index b6693795..c5cb0e58 100644 --- a/lib/ref.js +++ b/lib/ref.js @@ -185,7 +185,7 @@ $Ref.isExternal$Ref = function (value) { */ $Ref.isAllowed$Ref = function (value, options) { if ($Ref.is$Ref(value)) { - if (value.$ref.substr(0, 2) === "#/" || value.$ref === "#") { + if ((value.$ref.substr(0, 2) === "#/" || value.$ref === "#") && (!options || !options.resolve.skipInternal)) { // It's a JSON Pointer reference, which is always allowed return true; } diff --git a/test/specs/skip-internal/bundled.js b/test/specs/skip-internal/bundled.js new file mode 100644 index 00000000..320f291b --- /dev/null +++ b/test/specs/skip-internal/bundled.js @@ -0,0 +1,44 @@ +"use strict"; + +module.exports = +{ + title: "Person", + type: "object", + required: [ + "name" + ], + properties: { + name: { + title: "name", + type: "object", + required: [ + "first", + "last" + ], + properties: { + first: { + $ref: "#/properties/requiredString" + }, + last: { + $ref: "#/properties/requiredString" + } + } + }, + age: { + type: "integer", + minimum: 0 + }, + gender: { + type: "string", + enum: [ + "male", + "female" + ] + }, + requiredString: { + minLength: 1, + title: "required string", + type: "string" + } + } +}; diff --git a/test/specs/skip-internal/definitions/definitions.json b/test/specs/skip-internal/definitions/definitions.json new file mode 100644 index 00000000..6eb8bb7c --- /dev/null +++ b/test/specs/skip-internal/definitions/definitions.json @@ -0,0 +1,13 @@ +{ + "name": { + "$ref": "./name.yaml" + }, + "age": { + "type": "integer", + "minimum": 0 + }, + "gender": { + "type": "string", + "enum": ["male", "female"] + } +} diff --git a/test/specs/skip-internal/definitions/name.yaml b/test/specs/skip-internal/definitions/name.yaml new file mode 100644 index 00000000..423951eb --- /dev/null +++ b/test/specs/skip-internal/definitions/name.yaml @@ -0,0 +1,10 @@ +title: name +type: object +required: + - first + - last +properties: + first: + $ref: "#/properties/requiredString" + last: + $ref: "#/properties/requiredString" diff --git a/test/specs/skip-internal/definitions/required-string.yaml b/test/specs/skip-internal/definitions/required-string.yaml new file mode 100644 index 00000000..7e538a3c --- /dev/null +++ b/test/specs/skip-internal/definitions/required-string.yaml @@ -0,0 +1,3 @@ +title: required string +type: string +minLength: 1 diff --git a/test/specs/skip-internal/dereferenced.js b/test/specs/skip-internal/dereferenced.js new file mode 100644 index 00000000..320f291b --- /dev/null +++ b/test/specs/skip-internal/dereferenced.js @@ -0,0 +1,44 @@ +"use strict"; + +module.exports = +{ + title: "Person", + type: "object", + required: [ + "name" + ], + properties: { + name: { + title: "name", + type: "object", + required: [ + "first", + "last" + ], + properties: { + first: { + $ref: "#/properties/requiredString" + }, + last: { + $ref: "#/properties/requiredString" + } + } + }, + age: { + type: "integer", + minimum: 0 + }, + gender: { + type: "string", + enum: [ + "male", + "female" + ] + }, + requiredString: { + minLength: 1, + title: "required string", + type: "string" + } + } +}; diff --git a/test/specs/skip-internal/parsed.js b/test/specs/skip-internal/parsed.js new file mode 100644 index 00000000..abaaed2f --- /dev/null +++ b/test/specs/skip-internal/parsed.js @@ -0,0 +1,63 @@ +"use strict"; + +module.exports = +{ + schema: { + required: [ + "name" + ], + type: "object", + properties: { + gender: { + $ref: "definitions/definitions.json#/gender" + }, + age: { + $ref: "definitions/definitions.json#/age" + }, + name: { + $ref: "definitions/definitions.json#/name" + }, + requiredString: { + $ref: "definitions/required-string.yaml" + } + }, + title: "Person" + }, + + definitions: { + name: { + $ref: "./name.yaml" + }, + age: { + type: "integer", + minimum: 0 + }, + gender: { + type: "string", + enum: ["male", "female"] + } + }, + + name: { + required: [ + "first", + "last" + ], + type: "object", + properties: { + last: { + $ref: "#/properties/requiredString" + }, + first: { + $ref: "#/properties/requiredString" + } + }, + title: "name" + }, + + requiredString: { + minLength: 1, + type: "string", + title: "required string" + } +}; diff --git a/test/specs/skip-internal/skip-internal.spec.js b/test/specs/skip-internal/skip-internal.spec.js new file mode 100644 index 00000000..16c9a04c --- /dev/null +++ b/test/specs/skip-internal/skip-internal.spec.js @@ -0,0 +1,43 @@ +"use strict"; + +const { expect } = require("chai"); +const $RefParser = require("../../.."); +const helper = require("../../utils/helper"); +const path = require("../../utils/path"); +const parsedSchema = require("./parsed"); +const dereferencedSchema = require("./dereferenced"); +const bundledSchema = require("./bundled"); + +describe("Schema with $refs to parts of external files", () => { + it("should parse successfully", async () => { + let parser = new $RefParser(); + const schema = await parser.parse(path.rel("specs/skip-internal/skip-internal.yaml"), { resolve: { skipInternal: true }}); + expect(schema).to.equal(parser.schema); + expect(schema).to.deep.equal(parsedSchema.schema); + expect(parser.$refs.paths()).to.deep.equal([path.abs("specs/skip-internal/skip-internal.yaml")]); + }); + + it("should resolve successfully", helper.testResolve( + path.rel("specs/skip-internal/skip-internal.yaml"), + path.abs("specs/skip-internal/skip-internal.yaml"), parsedSchema.schema, + path.abs("specs/skip-internal/definitions/definitions.json"), parsedSchema.definitions, + path.abs("specs/skip-internal/definitions/name.yaml"), parsedSchema.name, + path.abs("specs/skip-internal/definitions/required-string.yaml"), parsedSchema.requiredString + )); + + it("should dereference successfully", async () => { + let parser = new $RefParser(); + const schema = await parser.dereference(path.rel("specs/skip-internal/skip-internal.yaml"), { resolve: { skipInternal: true }}); + expect(schema).to.equal(parser.schema); + expect(schema).to.deep.equal(dereferencedSchema); + // The "circular" flag should NOT be set + expect(parser.$refs.circular).to.equal(false); + }); + + it("should bundle successfully", async () => { + let parser = new $RefParser(); + const schema = await parser.bundle(path.rel("specs/skip-internal/skip-internal.yaml"), { resolve: { skipInternal: true }}); + expect(schema).to.equal(parser.schema); + expect(schema).to.deep.equal(bundledSchema); + }); +}); diff --git a/test/specs/skip-internal/skip-internal.yaml b/test/specs/skip-internal/skip-internal.yaml new file mode 100644 index 00000000..bee55cb5 --- /dev/null +++ b/test/specs/skip-internal/skip-internal.yaml @@ -0,0 +1,13 @@ +title: Person +type: object +required: + - name +properties: + name: + $ref: "definitions/definitions.json#/name" + age: + $ref: "definitions/definitions.json#/age" + gender: + $ref: "definitions/definitions.json#/gender" + requiredString: + $ref: "definitions/required-string.yaml" \ No newline at end of file