Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

json-refs

Package Overview
Dependencies
Maintainers
1
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-refs - npm Package Compare versions

Comparing version 0.1.6 to 0.1.7

183

index.js

@@ -32,2 +32,3 @@ /* exported findRefs, isJsonReference, isRemotePointer, pathFromPointer, pathToPointer, resolveRefs */

each: require('lodash-compat/collection/each'),
indexOf: require('lodash-compat/array/indexOf'),
isArray: require('lodash-compat/lang/isArray'),

@@ -38,4 +39,6 @@ isFunction: require('lodash-compat/lang/isFunction'),

isUndefined: require('lodash-compat/lang/isUndefined'),
map: require('lodash-compat/collection/map'),
keys: require('lodash-compat/object/keys'),
map: require('lodash-compat/collection/map')
};
var async = require('async');
var request = require('superagent');

@@ -45,2 +48,3 @@ var traverse = require('traverse');

var remoteCache = {};
var supportedSchemes = ['http', 'https'];

@@ -56,2 +60,23 @@ /**

/**
* Callback used to provide access to altering a remote request prior to the request being made.
*
* @param {object} req - The Superagent request object
* @param {string} ref - The reference being resolved (When applicable)
*
* @callback prepareRequestCallback
*/
/**
* Callback used to process the content of a reference.
*
* @param {string} content - The content loaded from the file/URL
* @param {string} ref - The reference string (When applicable)
* @param {object} [res] - The Superagent response object (For remote URL requests only)
*
* @returns {object} The JavaScript object representation of the reference
*
* @callback processContentCallback
*/
/* Internal Functions */

@@ -63,2 +88,3 @@

* @param {string} url - The URL to retrieve
* @param {object} options - The options passed to resolveRefs
* @param {resultCallback} done - The result callback

@@ -68,16 +94,31 @@ *

*/
var getRemoteJson = function getRemoteJson (url, done) {
var getRemoteJson = function getRemoteJson (url, options, done) {
var realUrl = url.split('#')[0];
var json = remoteCache[realUrl];
var err;
var userErr;
var realRequest;
if (!_.isUndefined(json)) {
done(err, json);
done(userErr, json);
} else {
request.get(url)
.set('user-agent', 'whitlockjc/json-refs')
.set('Accept', 'application/json')
.end(function (res) {
if (_.isPlainObject(res.body)) {
json = res.body;
realRequest = request.get(url)
.set('user-agent', 'whitlockjc/json-refs');
if (!_.isUndefined(options.prepareRequest)) {
options.prepareRequest(realRequest, url);
}
realRequest
.buffer()
.end(function (err, res) {
if (err) {
userErr = err;
} else if (res.error) {
userErr = res.error;
} else if (!_.isUndefined(options.processContent)) {
try {
json = options.processContent(res.text, url, res);
} catch (e) {
userErr = e;
}
} else {

@@ -87,3 +128,3 @@ try {

} catch (e) {
err = e;
userErr = e;
}

@@ -94,3 +135,3 @@ }

done(err, json);
done(userErr, json);
});

@@ -103,2 +144,9 @@ }

/**
* Clears the internal cache of url -> JavaScript object mappings based on previously resolved references.
*/
module.exports.clearCache = function clearCache () {
remoteCache = {};
};
/**
* Returns whether or not the object represents a JSON Reference.

@@ -189,5 +237,3 @@ *

// TODO: Update to work with relative file/path references
return /^https?:\/\//.test(ptr);
return ptr.charAt(0) !== '#';
};

@@ -240,2 +286,5 @@

* @param {object} json - The JSON document having zero or more JSON References
* @param {object} [options] - The options
* @param {prepareRequestCallback} [options.prepareRequest] - The callback used to prepare a request
* @param {processContentCallback} [options.processContent] - The callback used to process a reference's content
* @param {resultCallback} done - The result callback

@@ -245,3 +294,8 @@ *

*/
var resolveRefs = module.exports.resolveRefs = function resolveRefs (json, done) {
var resolveRefs = module.exports.resolveRefs = function resolveRefs (json, options, done) {
if (arguments.length < 3) {
done = arguments[1];
options = {};
}
if (_.isUndefined(json)) {

@@ -251,2 +305,4 @@ throw new Error('json is required');

throw new Error('json must be an object');
} else if (!_.isPlainObject(options)) {
throw new Error('options must be an object');
} else if (_.isUndefined(done)) {

@@ -258,3 +314,9 @@ throw new Error('done is required');

var isAsync = false;
// Validate the options
if (!_.isUndefined(options.prepareRequest) && !_.isFunction(options.prepareRequest)) {
throw new Error('options.prepareRequest must be a function');
} else if (!_.isUndefined(options.processContent) && !_.isFunction(options.processContent)) {
throw new Error('options.processContent must be a function');
}
var refs = findRefs(json);

@@ -274,2 +336,3 @@ var removeCircular = function removeCircular (jsonT) {

};
var metadata = {};
var cJsonT;

@@ -280,26 +343,64 @@

var replaceReference = function (to, from, ref, refPtr) {
var refMetadata = {
ref: ref
};
var missing = false;
var parentPath;
var refPath;
var value;
ref = ref.indexOf('#') === -1 ?
'#' :
ref.substring(ref.indexOf('#'));
refPath = pathFromPointer(refPtr);
parentPath = refPath.slice(0, refPath.length - 1);
if (parentPath.length === 0) {
missing = !_.isUndefined(from.value);
value = from.value;
to.value = value;
} else {
missing = !from.has(pathFromPointer(ref));
value = from.get(pathFromPointer(ref));
to.set(parentPath, value);
}
if (!missing) {
refMetadata.value = value;
}
metadata[refPtr] = refMetadata;
};
var remoteRefs = {};
_.each(refs, function (ref, refPtr) {
var refPath = pathFromPointer(refPtr);
var parentPath = refPath.slice(0, refPath.length - 1);
if (isRemotePointer(ref)) {
isAsync = true;
remoteRefs[refPtr] = ref;
} else {
replaceReference(cJsonT, cJsonT, ref, refPtr);
}
});
getRemoteJson(ref, function (err, json) {
async.map(_.keys(remoteRefs), function (refPtr, callback) {
var ref = remoteRefs[refPtr];
var scheme = ref.split(':')[0];
// Do not process relative references or references to unsupported resources
if (ref.charAt(0) === '.' || _.indexOf(supportedSchemes, scheme) === -1) {
callback();
} else {
getRemoteJson(ref, options, function (err, json) {
if (err) {
done(err);
callback(err);
} else {
resolveRefs(json, function (err, json) {
resolveRefs(json, options, function (err, json) {
delete remoteRefs[refPtr];
if (err) {
done(err);
callback(err);
} else {
if (parentPath.length === 0) {
cJsonT.value = json;
} else {
cJsonT.set(parentPath, traverse(json).get(pathFromPointer(ref.indexOf('#') === -1 ?
'#' :
ref.substring(ref.indexOf('#')))));
}
replaceReference(cJsonT, traverse(json), ref, refPtr);
done(undefined, removeCircular(cJsonT));
callback();
}

@@ -309,17 +410,13 @@ });

});
}
}, function (err) {
if (err) {
done(err);
} else {
if (parentPath.length === 0) {
cJsonT.value = json;
} else {
cJsonT.set(parentPath, cJsonT.get(pathFromPointer(ref)));
}
done(undefined, removeCircular(cJsonT), metadata);
}
});
if (!isAsync) {
done(undefined, removeCircular(cJsonT));
}
} else {
done(undefined, json);
done(undefined, json, metadata);
}
};
{
"name": "json-refs",
"version": "0.1.6",
"version": "0.1.7",
"description": "Various utilities for JSON References (http://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03).",

@@ -40,5 +40,7 @@ "main": "index.js",

"uglifyify": "~3.0.1",
"vinyl-source-stream": "~1.0.0"
"vinyl-source-stream": "~1.0.0",
"yamljs": "^0.2.1"
},
"dependencies": {
"async": "^0.9.0",
"lodash-compat": "^3.5.0",

@@ -45,0 +47,0 @@ "superagent": "~0.21.0",

@@ -117,3 +117,3 @@ # json-refs

## `resolveRefs (json, done)`
## `resolveRefs (json, options, done)`

@@ -123,3 +123,7 @@ **Arguments**

* `json {object}`: The JavaScript object containing zero or more JSON References
* `done {function}`: An error-first callback to be called with the fully-resolved object
* `[options] {object}`: The options
* `[options.prepareRequest] {function}`: The callback used to prepare a request
* `[options.processContent] {function}`: The callback used to process the remote request content
* `done {function}`: An error-first callback to be called with the fully-resolved object and metadata for the reference
resolution

@@ -130,8 +134,68 @@ **Response**

argument. If there is no `Error`, the first argument is `undefined` and the second argument is an `object` whose value
is the fully resolved document.
is the fully resolved document. The third argument is an `object` whose value is the reference resolution metadata.
Its keys are the location of the reference and it's values are as follows:
* `ref {string}`: The reference value as it existed in the original document
* `[value] {*}`: The resolved value of the reference, if there is one. If this property was set, this means that the
reference was resolvable and it resolved to an explicit value. If this property is not set, that means the reference
was unresolvable. A value of `undefined` means that the reference was resolvable to an actual value of `undefined` and
is not indicative of an unresolvable reference.
* `
##Usage
**Note:** If you need to alter your request in any way, for example to add specific headers to the request or to add
authentication to the request or any other situation in which the request might need to be altered, you will need to use
the `options.prepareRequest` callback. Here is a simple example that uses `options.prepareRequest` to make a secure
request using an Basic Authentication _(The example is written for Node.js but the actual business logic in how
`resolveRefs` is called sould be the same in the browser)_:
```js
var jsonRefs = require('json-refs');
var json = {
name: 'json-refs',
owner: {
$ref: 'https://api.github.com/repos/whitlockjc/json-refs#/owner'
}
};
jsonRefs.resolveRefs(json, {
prepareRequest: function (req) {
// Add the 'Basic Authentication' credentials
req.auth('whitlockjc', 'MY_GITHUB_PASSWORD');
// Add the 'X-API-Key' header for an API Key based authentication
// req.set('X-API-Key', 'MY_API_KEY');
}
}, function (err, rJson, metadata) {
if (err) throw err;
console.log(JSON.stringify(rJson)); // {name: 'json-refs', owner: {/* GitHub Repository Owner Information */}}
console.log(JSON.stringify(metadata)); // {'#/owner/$ref': {ref: 'https://api.github.com/repos/whitlockjc/json-refs#/owner', value: {/*GitHub Repository Onwer Information */}}}
});
```
**Note:** If you need to pre-process the content of your remote requets, like to support data not explicitly supported
by Superagent, you can use the `options.processContent` callback. Here is a simple example that uses
`options.processContent` to retrieve a YAML resource:
```js
var jsonRefs = require('json-resf');
var YAML = require('yamljs');
jsonRefs.resolveRefs({
$ref: 'http://somehost/somefile.yaml'
}, {
processContent: function (content) {
return YAML.parse(content);
}
}, function (err, rJson, metadata) {
if (err) throw err;
console.log(JSON.stringify(rJson)); // Document should be JSON equivalent of your YAML document
});
```
###Node.js
```js
var jsonRefs = require('json-refs');
var json = {

@@ -143,6 +207,7 @@ name: 'json-refs',

};
jsonRefs.resolveRefs(json, function (err, rJson) {
jsonRefs.resolveRefs(json, function (err, rJson, metadata) {
if (err) throw err;
console.log(JSON.stringify(rJson)); // {name: 'json-refs', owner: {/* GitHub Repository Owner Information */}}
console.log(JSON.stringify(metadata)); // {'#/owner/$ref': {ref: 'https://api.github.com/repos/whitlockjc/json-refs#/owner', value: {/*GitHub Repository Onwer Information */}}}
});

@@ -149,0 +214,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc