Skip to content

Commit 044b4ac

Browse files
Refactoring
1 parent bd51161 commit 044b4ac

16 files changed

Lines changed: 1684 additions & 3480 deletions

dist/ref-parser.js

Lines changed: 975 additions & 2034 deletions
Large diffs are not rendered by default.

dist/ref-parser.js.map

Lines changed: 18 additions & 64 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: 0 additions & 553 deletions
Large diffs are not rendered by default.

dist/ref-parser.min.js.map

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

lib/dereference.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,54 @@
11
'use strict';
22

3-
var PathOrUrl = require('./path-or-url'),
4-
$Ref = require('./ref'),
3+
var $Ref = require('./ref'),
54
util = require('./util'),
5+
url = require('url'),
66
_forEach = require('lodash/collection/forEach'),
77
_isArray = require('lodash/lang/isArray'),
88
_isObject = require('lodash/lang/isObject');
99

1010
module.exports = dereference;
1111

1212
/**
13+
* Crawls the JSON schema, finds all JSON references, and dereferences them.
14+
* This method mutates the JSON schema object, replacing JSON references with their resolved value.
15+
*
1316
* @param {$RefParser} parser
14-
* @param {Options} options
17+
* @param {ParserOptions} options
1518
*/
1619
function dereference(parser, options) {
17-
util.debug('Dereferencing $ref pointers in %s', parser._base);
18-
crawl(parser.schema, parser._base, [], parser.$refs, options);
20+
util.debug('Dereferencing $ref pointers in %s', parser._basePath);
21+
crawl(parser.schema, parser._basePath + '#', [], parser.$refs, options);
1922
}
2023

2124
/**
22-
* @param {object} obj
23-
* @param {PathOrUrl} pathOrUrl
24-
* @param {object[]} parents
25-
* @param {$Refs} $refs
26-
* @param {Options} options
25+
* Recursively crawls the given value, and dereferences any JSON references.
26+
*
27+
* @param {*} obj - The value to crawl. If it's not an object or array, it will be ignored.
28+
* @param {string} path - The path to use for resolving relative JSON references
29+
* @param {object[]} parents - An array of the parent objects that have already been dereferenced
30+
* @param {$Refs} $refs - The resolved JSON references
31+
* @param {ParserOptions} options
2732
*/
28-
function crawl(obj, pathOrUrl, parents, $refs, options) {
33+
function crawl(obj, path, parents, $refs, options) {
2934
if (_isObject(obj) || _isArray(obj)) {
3035
parents.push(obj);
3136

3237
_forEach(obj, function(value, key) {
33-
var keyPath = new PathOrUrl(pathOrUrl);
34-
keyPath.hash += '/' + key;
38+
var keyPath = path + '/' + key;
3539

3640
if ($Ref.isAllowed(value, options)) {
37-
// We found a $ref pointer.
41+
// We found a $ref, so resolve it
3842
util.debug('Dereferencing $ref pointer "%s" at %s', value.$ref, keyPath);
39-
var $refString = pathOrUrl.resolve(value.$ref, {allowFileHash: true});
40-
var $refPathOrUrl = new PathOrUrl($refString, {allowFileHash: true});
43+
var $refPath = url.resolve(path, value.$ref);
44+
var resolved$Ref = $refs._resolve($refPath, options);
4145

42-
// Dereference the $ref pointer
43-
var resolved$Ref = $refs._resolve($refPathOrUrl, options);
46+
// Dereference the JSON reference
4447
obj[key] = value = resolved$Ref.value;
4548

4649
// Crawl the dereferenced value (unless it's circular)
4750
if (parents.indexOf(value) === -1) {
48-
crawl(resolved$Ref.value, resolved$Ref.pathOrUrl, parents, $refs, options);
51+
crawl(resolved$Ref.value, resolved$Ref.path + '#', parents, $refs, options);
4952
}
5053
}
5154
else if (parents.indexOf(value) === -1) {

lib/index.js

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88

99
var Promise = require('./promise'),
1010
Options = require('./options'),
11-
PathOrUrl = require('./path-or-url'),
1211
$Refs = require('./refs'),
1312
read = require('./read'),
1413
resolve = require('./resolve'),
1514
dereference = require('./dereference'),
1615
util = require('./util'),
16+
url = require('url'),
17+
ono = require('ono'),
1718
_cloneDeep = require('lodash/lang/cloneDeep'),
1819
_isFunction = require('lodash/lang/isFunction'),
1920
_isObject = require('lodash/lang/isObject'),
@@ -22,6 +23,12 @@ var Promise = require('./promise'),
2223

2324
module.exports = $RefParser;
2425

26+
/**
27+
* This class parses a JSON schema, builds a map of its JSON references and their resolved values,
28+
* and provides methods for traversing, manipulating, and dereferencing those references.
29+
*
30+
* @constructor
31+
*/
2532
function $RefParser() {
2633
/**
2734
* The parsed (and possibly dereferenced) JSON schema object
@@ -32,23 +39,43 @@ function $RefParser() {
3239
this.schema = null;
3340

3441
/**
35-
* The resolved $ref pointers
42+
* The resolved JSON references
3643
*
3744
* @type {$Refs}
3845
*/
3946
this.$refs = new $Refs();
4047

4148
/**
42-
* @type {PathOrUrl}
49+
* @type {string}
4350
* @protected
4451
*/
45-
this._base = null;
52+
this._basePath = '';
4653
}
4754

55+
/**
56+
* Parses the given JSON schema.
57+
* This method does not resolve any JSON references.
58+
* It just reads a single file in JSON or YAML format, and parse it as a JavaScript object.
59+
*
60+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
61+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed
62+
* @param {function} [callback] - An error-first callback. The second parameter is the parsed JSON schema object.
63+
* @returns {Promise} - The returned promise resolves with the parsed JSON schema object.
64+
*/
4865
$RefParser.parse = function(schema, options, callback) {
4966
return new $RefParser().parse(schema, options, callback);
5067
};
5168

69+
/**
70+
* Parses the given JSON schema.
71+
* This method does not resolve any JSON references.
72+
* It just reads a single file in JSON or YAML format, and parse it as a JavaScript object.
73+
*
74+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
75+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed
76+
* @param {function} [callback] - An error-first callback. The second parameter is the parsed JSON schema object.
77+
* @returns {Promise} - The returned promise resolves with the parsed JSON schema object.
78+
*/
5279
$RefParser.prototype.parse = function(schema, options, callback) {
5380
if (_isFunction(options)) {
5481
callback = options;
@@ -58,26 +85,27 @@ $RefParser.prototype.parse = function(schema, options, callback) {
5885
if (schema && _isObject(schema)) {
5986
// The schema is an object, not a path/url
6087
this.schema = _cloneDeep(schema);
61-
this._base = PathOrUrl.cwd();
88+
this._basePath = '';
6289

6390
util.doCallback(callback, null, this.schema);
6491
return Promise.resolve(this.schema);
6592
}
6693

6794
if (!schema || !_isString(schema)) {
68-
var err = util.newError('Expected a file path, URL, or object. Got %s', schema);
95+
var err = ono('Expected a file path, URL, or object. Got %s', schema);
6996
util.doCallback(callback, err, schema);
7097
return Promise.reject(err);
7198
}
7299

73100
options = new Options(options);
74101
var me = this;
75102

76-
// Resolve the full URL of the schema
77-
this._base = new PathOrUrl(schema, {allowFileHash: true});
103+
// Resolve the absolute path of the schema
104+
schema = url.resolve(util.cwd(), schema);
105+
this._basePath = util.stripHash(schema);
78106

79107
// Read the schema file/url
80-
return read(this._base, this, options)
108+
return read(schema, this, options)
81109
.then(function($ref) {
82110
// Make sure the file was a POJO (in JSON or YAML format), NOT a Buffer or string
83111
if ($ref.value && _isPlainObject($ref.value)) {
@@ -86,7 +114,7 @@ $RefParser.prototype.parse = function(schema, options, callback) {
86114
return me.schema;
87115
}
88116
else {
89-
throw util.newError(SyntaxError, '"%s" is not a valid JSON Schema', me._base);
117+
throw ono.syntax('"%s" is not a valid JSON Schema', me._basePath);
90118
}
91119
})
92120
.catch(function(err) {
@@ -95,10 +123,34 @@ $RefParser.prototype.parse = function(schema, options, callback) {
95123
});
96124
};
97125

126+
/**
127+
* Parses the given JSON schema and resolves any JSON references, including references in
128+
* externally-referenced files.
129+
*
130+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
131+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed and resolved
132+
* @param {function} [callback]
133+
* - An error-first callback. The second parameter is a {@link $Refs} object containing the resolved JSON references
134+
*
135+
* @returns {Promise}
136+
* The returned promise resolves with a {@link $Refs} object containing the resolved JSON references
137+
*/
98138
$RefParser.resolve = function(schema, options, callback) {
99139
return new $RefParser().resolve(schema, options, callback);
100140
};
101141

142+
/**
143+
* Parses the given JSON schema and resolves any JSON references, including references in
144+
* externally-referenced files.
145+
*
146+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
147+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed and resolved
148+
* @param {function} [callback]
149+
* - An error-first callback. The second parameter is a {@link $Refs} object containing the resolved JSON references
150+
*
151+
* @returns {Promise}
152+
* The returned promise resolves with a {@link $Refs} object containing the resolved JSON references
153+
*/
102154
$RefParser.prototype.resolve = function(schema, options, callback) {
103155
if (_isFunction(options)) {
104156
callback = options;
@@ -122,10 +174,28 @@ $RefParser.prototype.resolve = function(schema, options, callback) {
122174
});
123175
};
124176

177+
/**
178+
* Parses the given JSON schema, resolves any JSON references, and dereferences the JSON schema.
179+
* That is, all JSON references are replaced with their resolved values.
180+
*
181+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
182+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed, resolved, and dereferenced
183+
* @param {function} [callback] - An error-first callback. The second parameter is the dereferenced JSON schema object
184+
* @returns {Promise} - The returned promise resolves with the dereferenced JSON schema object.
185+
*/
125186
$RefParser.dereference = function(schema, options, callback) {
126187
return new $RefParser().dereference(schema, options, callback);
127188
};
128189

190+
/**
191+
* Parses the given JSON schema, resolves any JSON references, and dereferences the JSON schema.
192+
* That is, all JSON references are replaced with their resolved values.
193+
*
194+
* @param {string|object} schema - The file path or URL of the JSON schema. Or a JSON schema object.
195+
* @param {ParserOptions} [options] - Options that determine how the schema is parsed, resolved, and dereferenced
196+
* @param {function} [callback] - An error-first callback. The second parameter is the dereferenced JSON schema object
197+
* @returns {Promise} - The returned promise resolves with the dereferenced JSON schema object.
198+
*/
129199
$RefParser.prototype.dereference = function(schema, options, callback) {
130200
if (_isFunction(options)) {
131201
callback = options;

lib/options.js

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,84 @@
22

33
var _merge = require('lodash/object/merge');
44

5-
module.exports = Options;
5+
module.exports = ParserOptions;
66

7-
function Options(options) {
7+
/**
8+
* Options that determine how JSON schemas are parsed, dereferenced, and cached.
9+
*
10+
* @param {object|ParserOptions} [options] - Overridden options
11+
* @constructor
12+
*/
13+
function ParserOptions(options) {
14+
/**
15+
* Determines what types of files can be parsed
16+
*/
817
this.allow = {
18+
/**
19+
* Are JSON files allowed? If false, then all schemas must be in YAML format.
20+
* @type {boolean}
21+
*/
922
json: true,
23+
24+
/**
25+
* Are YAML files allowed? If false, then all schemas must be in JSON format.
26+
* @type {boolean}
27+
*/
1028
yaml: true,
29+
30+
/**
31+
* Are zero-byte files allowed? If false, then an error will be thrown if a file is empty.
32+
* @type {boolean}
33+
*/
1134
empty: true,
35+
36+
/**
37+
* Can unknown file types be $referenced?
38+
* If true, then they will be parsed as Buffers (byte arrays).
39+
* If false, then an error will be thrown.
40+
* @type {boolean}
41+
*/
1242
unknown: true
1343
};
1444

45+
/**
46+
* Determines the types of JSON references that are allowed.
47+
*/
1548
this.$refs = {
49+
/**
50+
* Allow JSON references to other parts of the same file?
51+
* @type {boolean}
52+
*/
1653
internal: true,
54+
55+
/**
56+
* Allow JSON references to external files/URLs?
57+
* @type {boolean}
58+
*/
1759
external: true
1860
};
1961

62+
/**
63+
* How long to cache files (in seconds).
64+
*/
2065
this.cache = {
21-
fs: 60,
22-
http: 5 * 60,
23-
https: 5 * 60
66+
/**
67+
* How long to cache local files, in seconds.
68+
* @type {number}
69+
*/
70+
fs: 60, // 1 minute
71+
72+
/**
73+
* How long to cache files downloaded via HTTP, in seconds.
74+
* @type {number}
75+
*/
76+
http: 5 * 60, // 5 minutes
77+
78+
/**
79+
* How long to cache files downloaded via HTTPS, in seconds.
80+
* @type {number}
81+
*/
82+
https: 5 * 60 // 5 minutes
2483
};
2584

2685
_merge(this, options);

0 commit comments

Comments
 (0)