Skip to content

Commit a7e03e8

Browse files
RomanHotsiyJamesMessinger
authored andcommitted
Added optional metadata to the dereference() method (#103)
* Created a `saveOriginalRefs` option * Added logic to the dereference() method to save metadata for all references * Added tests * Documented new functionality
1 parent 9db2e2b commit a7e03e8

9 files changed

Lines changed: 106 additions & 2 deletions

File tree

.eslintrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extends:
1313

1414
globals:
1515
Promise: false
16+
Symbol: false
1617

1718
rules:
1819
# This rule erroneously flags functions that use the `arguments` object

docs/options.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,6 @@ The `dereference` options control how JSON Schema $Ref Parser will dereference `
7474
|Option(s) |Type |Description
7575
|:---------------------|:-------------------|:------------
7676
|`circular`|`boolean` or `"ignore"`|Determines whether [circular `$ref` pointers](README.md#circular-refs) are handled.<br><br>If set to `false`, then a `ReferenceError` will be thrown if the schema contains any circular references.<br><br> If set to `"ignore"`, then circular references will simply be ignored. No error will be thrown, but the [`$Refs.circular`](refs.md#circular) property will still be set to `true`.
77+
|`saveOriginalRefs` | `boolean` | If set to true `dereference` will preserve information about original
78+
`$ref` in the object metadata which can be later retrieved using [`$RefParser.getMetadata`](ref-parser.md#getmetadata)
79+

docs/ref-parser.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ This is the default export of JSON Schema $Ref Parser. You can creates instance
77
- [`schema`](#schema)
88
- [`$refs`](#refs)
99

10+
##### Static Methods
11+
- [`getMetadata()`](#getmetadata)
12+
1013
##### Methods
1114
- [`dereference()`](#dereferenceschema-options-callback)
1215
- [`bundle()`](#bundleschema-options-callback)
1316
- [`parse()`](#parseschema-options-callback)
1417
- [`resolve()`](#resolveschema-options-callback)
1518

16-
1719
### `schema`
1820
The `schema` property is the parsed/bundled/dereferenced JSON Schema object. This is the same value that is passed to the callback function (or Promise) when calling the [`parse`](#parseschema-options-callback), [`bundle`](#bundleschema-options-callback), or [`dereference`](#dereferenceschema-options-callback) methods.
1921

@@ -47,6 +49,24 @@ parser.dereference("my-schema.json")
4749
});
4850
```
4951

52+
### `getMetadata()`
53+
54+
Extracts metadata saved by [`dereference`](#dereferenceschema-options-callback).
55+
56+
When using [`dereference`](#dereferenceschema-options-callback) information about original `$ref` is lost. To preserve it [`dereference.saveOriginalRefs`](options.md#dereference-options) option can be used.
57+
58+
```js
59+
// var obj = dereferenced value
60+
var meta = $RefParser.getMetadata(obj.properties.a)
61+
```
62+
63+
Metadata object contains the following information:
64+
65+
- `$ref` - original `$ref`
66+
- `pathFromRoot` - path from the root of the document
67+
- `path` - absolute path
68+
69+
5070

5171
### `dereference(schema, [options], [callback])`
5272

lib/dereference.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
var $Ref = require('./ref'),
44
Pointer = require('./pointer'),
55
ono = require('ono'),
6-
url = require('./util/url');
6+
url = require('./util/url'),
7+
setMetadata = require('./util/meta').setMetadata;
78

89
module.exports = dereference;
910

@@ -125,6 +126,14 @@ function dereference$Ref ($ref, path, pathFromRoot, parents, $refs, options) {
125126
dereferencedValue.$ref = pathFromRoot;
126127
}
127128

129+
if (options.dereference.saveOriginalRefs) {
130+
setMetadata(dereferencedValue, {
131+
$ref: $ref.$ref,
132+
path: path,
133+
pathFromRoot: pathFromRoot,
134+
});
135+
}
136+
128137
return {
129138
circular: circular,
130139
value: dereferencedValue

lib/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ var Options = require('./options'),
88
bundle = require('./bundle'),
99
dereference = require('./dereference'),
1010
url = require('./util/url'),
11+
getMetadata = require('./util/meta').getMetadata,
12+
setMetadata = require('./util/meta').setMetadata,
1113
maybe = require('call-me-maybe'),
1214
ono = require('ono');
1315

1416
module.exports = $RefParser;
1517
module.exports.YAML = require('./util/yaml');
18+
module.exports.getMetadata = getMetadata;
19+
module.exports.setMetdata = setMetadata;
1620

1721
/**
1822
* This class parses a JSON schema, builds a map of its JSON references and their resolved values,

lib/util/meta.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
var META_SYMBOL = Symbol('json-schema-ref-parser meta');
4+
5+
/**
6+
* Safely sets meta property on the given object value
7+
*
8+
* @param {object} obj - A object to set meta info on
9+
* @param {string} prop - Name of property
10+
* @param {string} prop - Value to set
11+
*/
12+
exports.setMetadata = function (obj, value) {
13+
if (!obj) { return; }
14+
// we can't create property on primitives (throws in strict mode)
15+
if (typeof obj !== 'object') { return; }
16+
17+
obj[META_SYMBOL] = value;
18+
};
19+
20+
/**
21+
* Given the any object returns the associated meta-information or undefined
22+
*
23+
* @param {any} value - object to get the meta from
24+
* @returns {{pointer: string}}
25+
*/
26+
exports.getMetadata = function (value) {
27+
return value && value[META_SYMBOL];
28+
};

test/specs/metadata/external.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type: number
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
describe('Dereference save metadata', function () {
2+
'use strict';
3+
4+
it('should save metadata for internal refs', function () {
5+
var parser = new $RefParser();
6+
return parser
7+
.dereference(path.rel('specs/metadata/spec.yaml'), { dereference: { saveOriginalRefs: true }})
8+
.then(function (schema) {
9+
var metadata = $RefParser.getMetadata(schema.properties.a);
10+
expect(metadata).to.be.an('object');
11+
expect(metadata.$ref).to.eq('#/definitions/internal');
12+
expect(metadata.pathFromRoot).to.eq('#/properties/a');
13+
expect(metadata.path.endsWith('spec.yaml#/properties/a')).to.be.true;
14+
});
15+
});
16+
17+
it('should save metadata for external refs', function () {
18+
var parser = new $RefParser();
19+
return parser
20+
.dereference(path.rel('specs/metadata/spec.yaml'), { dereference: { saveOriginalRefs: true }})
21+
.then(function (schema) {
22+
var metadata = $RefParser.getMetadata(schema.properties.b);
23+
expect(metadata).to.be.an('object');
24+
expect(metadata.$ref).to.eq('external.yaml');
25+
expect(metadata.pathFromRoot).to.eq('#/properties/b');
26+
expect(metadata.path.endsWith('spec.yaml#/properties/b')).to.be.true;
27+
});
28+
});
29+
});

test/specs/metadata/spec.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type: object
2+
properties:
3+
a:
4+
$ref: "#/definitions/internal"
5+
b:
6+
$ref: "external.yaml"
7+
definitions:
8+
internal:
9+
type: string

0 commit comments

Comments
 (0)