Skip to content

Commit 433268a

Browse files
Added support for "file://" urls (fixes APIDevTools/swagger-parser#25)
1 parent 9cbde99 commit 433268a

File tree

19 files changed

+171
-70
lines changed

19 files changed

+171
-70
lines changed

dist/ref-parser.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,7 +1652,7 @@ function getPaths($refs, types) {
16521652
return paths.map(function(path) {
16531653
return {
16541654
encoded: path,
1655-
decoded: $refs[path].pathType === 'fs' ? util.path.urlToLocalPath(path) : path
1655+
decoded: $refs[path].pathType === 'fs' ? util.path.urlToLocalPath(path, true) : path
16561656
};
16571657
});
16581658
}
@@ -1791,7 +1791,7 @@ function crawl$Ref(path, pathFromRoot, $refs, options) {
17911791
var debug = require('debug'),
17921792
isWindows = /^win/.test(process.platform),
17931793
forwardSlashPattern = /\//g,
1794-
protocolPattern = /^[a-z0-9.+-]+:\/\//i;
1794+
protocolPattern = /^([a-z0-9.+-]+):\/\//i;
17951795

17961796
// RegExp patterns to URL-encode special characters in local filesystem paths
17971797
var urlEncodePatterns = [
@@ -1837,7 +1837,12 @@ exports.path.cwd = function cwd() {
18371837
* @returns {boolean}
18381838
*/
18391839
exports.path.isUrl = function isUrl(path) {
1840-
return protocolPattern.test(path);
1840+
var protocol = protocolPattern.exec(path);
1841+
if (protocol) {
1842+
protocol = protocol[1].toLowerCase();
1843+
return protocol !== 'file';
1844+
}
1845+
return false;
18411846
};
18421847

18431848
/**
@@ -1861,14 +1866,18 @@ exports.path.localPathToUrl = function localPathToUrl(path) {
18611866
* Converts a URL to a local filesystem path
18621867
*
18631868
* @param {string} url
1869+
* @param {boolean} [keepFileProtocol] - If true, then "file://" will NOT be stripped
18641870
* @returns {string}
18651871
*/
1866-
exports.path.urlToLocalPath = function urlToLocalPath(url) {
1872+
exports.path.urlToLocalPath = function urlToLocalPath(url, keepFileProtocol) {
18671873
url = decodeURI(url);
18681874
// Manually decode characters that are not decoded by `decodeURI`
18691875
for (var i = 0; i < urlDecodePatterns.length; i += 2) {
18701876
url = url.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
18711877
}
1878+
if (!keepFileProtocol && url.substr(0, 7).toLowerCase() === 'file://') {
1879+
url = url.substr(7);
1880+
}
18721881
if (isWindows) {
18731882
url = url.replace(forwardSlashPattern, '\\');
18741883
}

dist/ref-parser.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ref-parser.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ref-parser.min.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/refs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function getPaths($refs, types) {
188188
return paths.map(function(path) {
189189
return {
190190
encoded: path,
191-
decoded: $refs[path].pathType === 'fs' ? util.path.urlToLocalPath(path) : path
191+
decoded: $refs[path].pathType === 'fs' ? util.path.urlToLocalPath(path, true) : path
192192
};
193193
});
194194
}

lib/util.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
var debug = require('debug'),
44
isWindows = /^win/.test(process.platform),
55
forwardSlashPattern = /\//g,
6-
protocolPattern = /^[a-z0-9.+-]+:\/\//i;
6+
protocolPattern = /^([a-z0-9.+-]+):\/\//i;
77

88
// RegExp patterns to URL-encode special characters in local filesystem paths
99
var urlEncodePatterns = [
@@ -49,7 +49,12 @@ exports.path.cwd = function cwd() {
4949
* @returns {boolean}
5050
*/
5151
exports.path.isUrl = function isUrl(path) {
52-
return protocolPattern.test(path);
52+
var protocol = protocolPattern.exec(path);
53+
if (protocol) {
54+
protocol = protocol[1].toLowerCase();
55+
return protocol !== 'file';
56+
}
57+
return false;
5358
};
5459

5560
/**
@@ -73,14 +78,18 @@ exports.path.localPathToUrl = function localPathToUrl(path) {
7378
* Converts a URL to a local filesystem path
7479
*
7580
* @param {string} url
81+
* @param {boolean} [keepFileProtocol] - If true, then "file://" will NOT be stripped
7682
* @returns {string}
7783
*/
78-
exports.path.urlToLocalPath = function urlToLocalPath(url) {
84+
exports.path.urlToLocalPath = function urlToLocalPath(url, keepFileProtocol) {
7985
url = decodeURI(url);
8086
// Manually decode characters that are not decoded by `decodeURI`
8187
for (var i = 0; i < urlDecodePatterns.length; i += 2) {
8288
url = url.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
8389
}
90+
if (!keepFileProtocol && url.substr(0, 7).toLowerCase() === 'file://') {
91+
url = url.substr(7);
92+
}
8493
if (isWindows) {
8594
url = url.replace(forwardSlashPattern, '\\');
8695
}

tests/fixtures/helper.js

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,36 +43,41 @@
4343
* and asserts that the given file paths resolve to the given values.
4444
*
4545
* @param {string} filePath - The file path that should be resolved
46-
* @param {*} resolvedValue - The resolved value of the file
47-
* @param {...*} [params] - Additional file paths and resolved values
46+
* @param {...*} [params] - The expected resolved file paths and values
4847
* @returns {Function}
4948
*/
50-
helper.testResolve = function testResolve(filePath, resolvedValue, params) {
51-
var schemaFile = path.rel(arguments[0]);
52-
var parsedSchema = arguments[1];
53-
var expectedFiles = [], expectedValues = [];
54-
for (var i = 0; i < arguments.length; i++) {
55-
expectedFiles.push(path.abs(arguments[i]));
56-
expectedValues.push(arguments[++i]);
49+
helper.testResolve = function testResolve(filePath, params) {
50+
var parsedSchema = arguments[2];
51+
var expectedFiles = [], expectedValues = [], actualFiles;
52+
for (var i = 1; i < arguments.length; i += 2) {
53+
expectedFiles.push(arguments[i]);
54+
expectedValues.push(arguments[i + 1]);
5755
}
5856

5957
return function(done) {
6058
var parser = new $RefParser();
6159
parser
62-
.resolve(schemaFile)
60+
.resolve(filePath)
6361
.then(function($refs) {
6462
expect(parser.schema).to.deep.equal(parsedSchema);
6563
expect(parser.$refs).to.equal($refs);
6664

6765
// Resolved file paths
68-
expect($refs.paths()).to.have.same.members(expectedFiles);
69-
if (userAgent.isNode) {
70-
expect($refs.paths(['fs'])).to.have.same.members(expectedFiles);
71-
expect($refs.paths('http', 'https')).to.be.an('array').with.lengthOf(0);
66+
try {
67+
expect((actualFiles = $refs.paths())).to.have.same.members(expectedFiles);
68+
if (userAgent.isNode) {
69+
expect((actualFiles = $refs.paths(['fs']))).to.have.same.members(expectedFiles);
70+
expect($refs.paths('http', 'https')).to.be.an('array').with.lengthOf(0);
71+
}
72+
else {
73+
expect((actualFiles = $refs.paths(['http', 'https']))).to.have.same.members(expectedFiles);
74+
expect($refs.paths('fs')).to.be.an('array').with.lengthOf(0);
75+
}
7276
}
73-
else {
74-
expect($refs.paths(['http', 'https'])).to.have.same.members(expectedFiles);
75-
expect($refs.paths('fs')).to.be.an('array').with.lengthOf(0);
77+
catch (e) {
78+
console.log('Expected Files:', JSON.stringify(expectedFiles, null, 2));
79+
console.log('Actual Files:', JSON.stringify(actualFiles, null, 2));
80+
throw e;
7681
}
7782

7883
// Resolved values

tests/fixtures/path.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
var path = global.path = {};
55
var _path = userAgent.isNode ? require('path') : null;
6+
var _url = userAgent.isNode ? require('url') : null;
67
var _testsDir = getTestsDir();
78

89
if (userAgent.isNode) {
@@ -51,6 +52,28 @@
5152
return file;
5253
};
5354

55+
/**
56+
* Returns the path of a file in the "tests" directory as a URL.
57+
*/
58+
path.url = function(file) {
59+
if (userAgent.isBrowser) {
60+
// In browsers, just return the absolute URL (e.g. "http://localhost/tests/files/...")
61+
return path.abs(file);
62+
}
63+
64+
// In Node, return the absolute path as a URL (e.g. "file://path/to/json-schema-ref-parser/tests/files...")
65+
var pathname = path.abs(file);
66+
if (/^win/.test(process.platform)) {
67+
pathname = pathname.replace(/\\/g, '/'); // Convert Windows separators to URL separators
68+
}
69+
var url = _url.format({
70+
protocol: 'file:',
71+
slashes: true,
72+
pathname: pathname
73+
});
74+
return url;
75+
};
76+
5477
/**
5578
* Returns the path of the "tests" directory
5679
*/
@@ -59,8 +82,8 @@
5982
return _path.resolve(__dirname, '..');
6083
}
6184
else {
62-
var filename = document.querySelector('script[src*="fixtures/helper.js"]').src;
63-
return filename.substr(0, filename.indexOf('fixtures/helper.js'));
85+
var filename = document.querySelector('script[src*="fixtures/path.js"]').src;
86+
return filename.substr(0, filename.indexOf('fixtures/path.js'));
6487
}
6588
}
6689

tests/specs/__({[ ! % & $ # @ ` ~ ,)}]__/special-characters.spec.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ describe('File names with special characters', function() {
1313
});
1414

1515
it('should resolve successfully', helper.testResolve(
16-
'specs/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__.yaml', helper.parsed.specialCharacters.schema,
17-
'specs/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__.json', helper.parsed.specialCharacters.file
16+
path.rel('specs/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__.yaml'),
17+
path.abs('specs/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__.yaml'), helper.parsed.specialCharacters.schema,
18+
path.abs('specs/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__/__({[ ! % & $ # @ ` ~ ,)}]__.json'), helper.parsed.specialCharacters.file
1819
));
1920

2021
it('should dereference successfully', function() {

tests/specs/circular-extended/circular-extended.spec.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ describe('Schema with circular $refs that extend each other', function() {
1818
});
1919

2020
it('should resolve successfully', helper.testResolve(
21-
'specs/circular-extended/circular-extended-self.yaml', helper.parsed.circularExtended.self
21+
path.rel('specs/circular-extended/circular-extended-self.yaml'),
22+
path.abs('specs/circular-extended/circular-extended-self.yaml'), helper.parsed.circularExtended.self
2223
));
2324

2425
it('should dereference successfully', function() {
@@ -95,7 +96,8 @@ describe('Schema with circular $refs that extend each other', function() {
9596
});
9697

9798
it('should resolve successfully', helper.testResolve(
98-
'specs/circular-extended/circular-extended-ancestor.yaml', helper.parsed.circularExtended.ancestor
99+
path.rel('specs/circular-extended/circular-extended-ancestor.yaml'),
100+
path.abs('specs/circular-extended/circular-extended-ancestor.yaml'), helper.parsed.circularExtended.ancestor
99101
));
100102

101103
it('should dereference successfully', function() {
@@ -181,7 +183,8 @@ describe('Schema with circular $refs that extend each other', function() {
181183
});
182184

183185
it('should resolve successfully', helper.testResolve(
184-
'specs/circular-extended/circular-extended-indirect.yaml', helper.parsed.circularExtended.indirect
186+
path.rel('specs/circular-extended/circular-extended-indirect.yaml'),
187+
path.abs('specs/circular-extended/circular-extended-indirect.yaml'), helper.parsed.circularExtended.indirect
185188
));
186189

187190
it('should dereference successfully', function() {
@@ -269,7 +272,8 @@ describe('Schema with circular $refs that extend each other', function() {
269272
});
270273

271274
it('should resolve successfully', helper.testResolve(
272-
'specs/circular-extended/circular-extended-indirect-ancestor.yaml', helper.parsed.circularExtended.indirectAncestor
275+
path.rel('specs/circular-extended/circular-extended-indirect-ancestor.yaml'),
276+
path.abs('specs/circular-extended/circular-extended-indirect-ancestor.yaml'), helper.parsed.circularExtended.indirectAncestor
273277
));
274278

275279
it('should dereference successfully', function() {

0 commit comments

Comments
 (0)