Skip to content

Commit fe529ca

Browse files
Checking in my current progress on #8
Not fully done yet, but pretty close.
1 parent 7cb26c4 commit fe529ca

29 files changed

+1797
-1353
lines changed

dist/ref-parser.js

Lines changed: 989 additions & 724 deletions
Large diffs are not rendered by default.

dist/ref-parser.js.map

Lines changed: 31 additions & 21 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: 130 additions & 115 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: 31 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The difference is that in the second example you now have a reference to `parser
5454

5555

5656
### Callbacks vs. Promises
57-
Many people prefer [ES6 Promise syntax](http://javascriptplayground.com/blog/2015/02/promises/) instead of callbacks. JSON Schema $Ref Parser allows you to use whichever one you prefer.
57+
Many people prefer [ES6 Promise syntax](http://javascriptplayground.com/blog/2015/02/promises/) instead of callbacks. JSON Schema $Ref Parser allows you to use whichever one you prefer.
5858

5959
If you pass a callback function to any method, then the method will call the callback using the Node.js error-first convention. If you do _not_ pass a callback function, then the method will return an ES6 Promise.
6060

@@ -87,7 +87,7 @@ $RefParser.dereference(mySchema)
8787
### Circular $Refs
8888
JSON Schema files can contain [circular $ref pointers](https://gist.github.com/BigstickCarpet/d18278935fc73e3a0ee1), and JSON Schema $Ref Parser fully supports them. Circular references can be resolved and dereferenced just like any other reference. However, if you intend to serialize the dereferenced schema as JSON, then you should be aware that [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) does not support circular references by default, so you will need to [use a custom replacer function](https://stackoverflow.com/questions/11616630/json-stringify-avoid-typeerror-converting-circular-structure-to-json).
8989

90-
You can disable circular references by setting the [`$refs.circular`](options.md) option to `false`. Then, if a circular reference is found, a `ReferenceError` will be thrown.
90+
You can disable circular references by setting the [`dereference.circular`](options.md) option to `false`. Then, if a circular reference is found, a `ReferenceError` will be thrown.
9191

9292
Another option is to use the [`bundle`](ref-parser.md#bundleschema-options-callback) method rather than the [`dereference`](ref-parser.md#dereferenceschema-options-callback) method. Bundling does _not_ result in circular references, because it simply converts _external_ `$ref` pointers to _internal_ ones.
9393

docs/refs.md

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ This object is a map of JSON References and their resolved values. It also has
1515
- [`isExpired()`](#isexpiredref)
1616
- [`expire()`](#expireref)
1717
- [`exists()`](#existsref)
18-
- [`get()`](#getref-options)
19-
- [`set()`](#setref-value-options)
18+
- [`get()`](#getref)
19+
- [`set()`](#setref-value)
2020

2121

2222
### `circular`
@@ -138,14 +138,11 @@ $RefParser.resolve("my-schema.json")
138138
```
139139

140140

141-
### `get($ref, [options])`
141+
### `get($ref)`
142142

143143
- **$ref** (_required_) - `string`<br>
144144
The JSON Reference path, optionally with a JSON Pointer in the hash
145145

146-
- **options** (_optional_) - `object`<br>
147-
See [options](options.md) for the full list of options
148-
149146
- **Return Value:** `boolean`<br>
150147
Gets the value at the given path in the schema. Throws an error if the path does not exist.
151148

@@ -157,17 +154,14 @@ $RefParser.resolve("my-schema.json")
157154
```
158155

159156

160-
### `set($ref, value, [options])`
157+
### `set($ref, value)`
161158

162159
- **$ref** (_required_) - `string`<br>
163160
The JSON Reference path, optionally with a JSON Pointer in the hash
164161

165162
- **value** (_required_)<br>
166163
The value to assign. Can be anything (object, string, number, etc.)
167164

168-
- **options** (_optional_) - `object`<br>
169-
See [options](options.md) for the full list of options
170-
171165
Sets the value at the given path in the schema. If the property, or any of its parents, don't exist, they will be created.
172166

173167
```javascript

lib/bundle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function crawl(obj, path, pathFromRoot, inventory, $refs, options) {
8686
function inventory$Ref($refParent, $refKey, path, pathFromRoot, inventory, $refs, options) {
8787
var $ref = $refParent[$refKey];
8888
var $refPath = url.resolve(path, $ref.$ref);
89-
var pointer = $refs._resolve($refPath, options);
89+
var pointer = $refs._resolve($refPath);
9090
var depth = Pointer.parse(pathFromRoot).length;
9191
var file = util.path.stripHash(pointer.path);
9292
var hash = util.path.getHash(pointer.path);

lib/dereference.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function crawl(obj, path, pathFromRoot, parents, $refs, options) {
4444
var value = obj[key];
4545
var circular = false;
4646

47-
if ($Ref.isAllowed$Ref(value, options)) {
47+
if ($Ref.is$Ref(value, options)) {
4848
var dereferenced = dereference$Ref(value, keyPath, keyPathFromRoot, parents, $refs, options);
4949
circular = dereferenced.circular;
5050
obj[key] = dereferenced.value;
@@ -82,7 +82,7 @@ function dereference$Ref($ref, path, pathFromRoot, parents, $refs, options) {
8282
util.debug('Dereferencing $ref pointer "%s" at %s', $ref.$ref, path);
8383

8484
var $refPath = url.resolve(path, $ref.$ref);
85-
var pointer = $refs._resolve($refPath, options);
85+
var pointer = $refs._resolve($refPath);
8686

8787
// Check for circular references
8888
var directCircular = pointer.circular;
@@ -98,7 +98,7 @@ function dereference$Ref($ref, path, pathFromRoot, parents, $refs, options) {
9898
circular = crawl(dereferencedValue, pointer.path, pathFromRoot, parents, $refs, options);
9999
}
100100

101-
if (circular && !directCircular && options.$refs.circular === 'ignore') {
101+
if (circular && !directCircular && options.dereference.circular === 'ignore') {
102102
// The user has chosen to "ignore" circular references, so don't change the value
103103
dereferencedValue = $ref;
104104
}
@@ -117,7 +117,7 @@ function dereference$Ref($ref, path, pathFromRoot, parents, $refs, options) {
117117

118118
/**
119119
* Called when a circular reference is found.
120-
* It sets the {@link $Refs#circular} flag, and throws an error if options.$refs.circular is false.
120+
* It sets the {@link $Refs#circular} flag, and throws an error if options.dereference.circular is false.
121121
*
122122
* @param {string} keyPath - The JSON Reference path of the circular reference
123123
* @param {$Refs} $refs
@@ -126,7 +126,7 @@ function dereference$Ref($ref, path, pathFromRoot, parents, $refs, options) {
126126
*/
127127
function foundCircularReference(keyPath, $refs, options) {
128128
$refs.circular = true;
129-
if (!options.$refs.circular) {
129+
if (!options.dereference.circular) {
130130
throw ono.reference('Circular $ref pointer found at %s', keyPath);
131131
}
132132
return true;

lib/index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
var Promise = require('./promise'),
3+
var Promise = require('./util/promise'),
44
Options = require('./options'),
55
$Refs = require('./refs'),
66
$Ref = require('./ref'),
@@ -14,7 +14,7 @@ var Promise = require('./promise'),
1414
ono = require('ono');
1515

1616
module.exports = $RefParser;
17-
module.exports.YAML = require('./yaml');
17+
module.exports.YAML = require('./util/yaml');
1818

1919
/**
2020
* This class parses a JSON schema, builds a map of its JSON references and their resolved values,
@@ -72,7 +72,8 @@ $RefParser.prototype.parse = function(schema, options, callback) {
7272
this.schema = args.schema;
7373
this.$refs._basePath = '';
7474
var $ref = new $Ref(this.$refs, this.$refs._basePath);
75-
$ref.setValue(this.schema, args.options);
75+
$ref.value = this.schema;
76+
$ref.setExpiration(options);
7677

7778
return maybe(args.callback, Promise.resolve(this.schema));
7879
}
@@ -93,7 +94,7 @@ $RefParser.prototype.parse = function(schema, options, callback) {
9394
return read(args.schema, this.$refs, args.options)
9495
.then(function(result) {
9596
var value = result.$ref.value;
96-
if (!value || typeof value !== 'object' || value instanceof Buffer) {
97+
if (!value || typeof value !== 'object' || Buffer.isBuffer(value)) {
9798
throw ono.syntax('"%s" is not a valid JSON Schema', me.$refs._basePath);
9899
}
99100
else {

lib/options.js

Lines changed: 68 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
/* eslint lines-around-comment: [2, {beforeBlockComment: false}] */
22
'use strict';
33

4+
var parseJSON = require('./parse/json'),
5+
parseYAML = require('./parse/yaml'),
6+
parseText = require('./parse/text'),
7+
parseBinary = require('./parse/binary'),
8+
readFile = require('./read/file'),
9+
readHttp = require('./read/http');
10+
411
module.exports = $RefParserOptions;
512

613
/**
@@ -11,143 +18,91 @@ module.exports = $RefParserOptions;
1118
*/
1219
function $RefParserOptions(options) {
1320
/**
14-
* Determines what types of files can be parsed
21+
* Determines how different types of files will be parsed.
22+
*
23+
* You can add additional parsers of your own, replace an existing one with
24+
* your own implemenation, or disable any parser by setting it to false.
25+
*
26+
* Each of the built-in parsers has the following options:
27+
*
28+
* order {number} - The order in which the parsers will run
29+
*
30+
* ext {string[]} - An array of file extensions and/or RegExp patterns.
31+
* Only matching files will be parsed by this parser.
32+
*
33+
* empty {boolean} - Whether to allow "empty" files. Enabled by default.
34+
* "Empty" includes zero-byte files, as well as JSON/YAML files that
35+
* don't contain any keys.
1536
*/
16-
this.allow = {
17-
/**
18-
* Are JSON files allowed?
19-
* If false, then all schemas must be in YAML format.
20-
* @type {boolean}
21-
*/
22-
json: true,
23-
24-
/**
25-
* Are YAML files allowed?
26-
* If false, then all schemas must be in JSON format.
27-
* @type {boolean}
28-
*/
29-
yaml: true,
30-
31-
/**
32-
* Are zero-byte files allowed?
33-
* If false, then an error will be thrown if a file is empty.
34-
* @type {boolean}
35-
*/
36-
empty: true,
37+
this.parse = {
38+
json: parseJSON,
39+
yaml: parseYAML,
40+
text: parseText,
41+
binary: parseBinary,
42+
};
3743

38-
/**
39-
* Can unknown file types be $referenced?
40-
* If true, then they will be parsed as Buffers (byte arrays).
41-
* If false, then an error will be thrown.
42-
* @type {boolean}
43-
*/
44-
unknown: true
44+
/**
45+
* Determines how external JSON References will be resolved.
46+
*
47+
* You can add additional readers of your own, replace an existing one with
48+
* your own implemenation, or disable any reader by setting it to false.
49+
*
50+
* Each of the built-in readers has the following options:
51+
*
52+
* order {number} - The order in which the reader will run
53+
*
54+
* cache {number} - How long to cache files (in milliseconds)
55+
* The default cache duration is different for each reader.
56+
* Setting the cache duration to zero disables caching for that reader.
57+
*
58+
* The HTTP reader has additional options. See read/http.js for details.
59+
*/
60+
this.resolve = {
61+
file: readFile,
62+
http: readHttp,
4563
};
4664

4765
/**
4866
* Determines the types of JSON references that are allowed.
4967
*/
50-
this.$refs = {
51-
/**
52-
* Allow JSON references to other parts of the same file?
53-
* @type {boolean}
54-
*/
55-
internal: true,
56-
57-
/**
58-
* Allow JSON references to external files/URLs?
59-
* @type {boolean}
60-
*/
61-
external: true,
62-
68+
this.dereference = {
6369
/**
64-
* Allow circular (recursive) JSON references?
70+
* Dereference circular (recursive) JSON references?
6571
* If false, then a {@link ReferenceError} will be thrown if a circular reference is found.
6672
* If "ignore", then circular references will not be dereferenced.
73+
*
6774
* @type {boolean|string}
6875
*/
6976
circular: true
7077
};
7178

72-
/**
73-
* How long to cache files (in seconds).
74-
*/
75-
this.cache = {
76-
/**
77-
* How long to cache local files, in seconds.
78-
* @type {number}
79-
*/
80-
fs: 60, // 1 minute
81-
82-
/**
83-
* How long to cache files downloaded via HTTP, in seconds.
84-
* @type {number}
85-
*/
86-
http: 5 * 60, // 5 minutes
87-
88-
/**
89-
* How long to cache files downloaded via HTTPS, in seconds.
90-
* @type {number}
91-
*/
92-
https: 5 * 60 // 5 minutes
93-
};
94-
95-
/**
96-
* HTTP request options
97-
*/
98-
this.http = {
99-
/**
100-
* HTTP headers to send when downloading files.
101-
*/
102-
headers: {},
103-
104-
/**
105-
* HTTP request timeout (in milliseconds).
106-
*/
107-
timeout: 5000,
108-
109-
/**
110-
* The maximum number of HTTP redirects to follow.
111-
* To disable automatic following of redirects, set this to zero.
112-
*/
113-
redirects: 5,
114-
115-
/**
116-
* The `withCredentials` option of XMLHttpRequest.
117-
* Set this to `true` if you're downloading files from a CORS-enabled server that requires authentication
118-
*/
119-
withCredentials: false,
120-
121-
};
122-
12379
merge(options, this);
12480
}
12581

12682
/**
127-
* Fast, two-level object merge.
83+
* Merges user-specified options with default options.
12884
*
129-
* @param {?object} src - The object to merge into dest
130-
* @param {object} dest - The object to be modified
85+
* @param {?object} user - The options that were specified by the user
86+
* @param {$RefParserOptions} defaults - The {@link $RefParserOptions} object that we're populating
87+
* @returns {*}
13188
*/
132-
function merge(src, dest) {
133-
if (src) {
134-
var topKeys = Object.keys(src);
135-
for (var i = 0; i < topKeys.length; i++) {
136-
var topKey = topKeys[i];
137-
var srcChild = src[topKey];
138-
if (dest[topKey] === undefined) {
139-
dest[topKey] = srcChild;
89+
function merge(user, defaults) {
90+
if (user) {
91+
var keys = Object.keys(user);
92+
for (var i = 0; i < keys.length; i++) {
93+
var key = keys[i];
94+
var userSetting = user[key];
95+
var defaultSetting = defaults[key];
96+
97+
if (userSetting && typeof userSetting === 'object' && !Array.isArray(userSetting)) {
98+
// An object with nested options, so merge it too
99+
defaults[key] = merge(userSetting, defaultSetting);
140100
}
141101
else {
142-
var childKeys = Object.keys(srcChild);
143-
for (var j = 0; j < childKeys.length; j++) {
144-
var childKey = childKeys[j];
145-
var srcChildValue = srcChild[childKey];
146-
if (srcChildValue !== undefined) {
147-
dest[topKey][childKey] = srcChildValue;
148-
}
149-
}
102+
// A scalar value, function, or array. So override the default value.
103+
defaults[key] = userSetting;
150104
}
151105
}
152106
}
107+
return defaults;
153108
}

0 commit comments

Comments
 (0)