Socket
Socket
Sign inDemoInstall

shortstop

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

shortstop - npm Package Compare versions

Comparing version 0.0.1 to 1.0.0

.jshintrc

67

index.js

@@ -1,4 +0,3 @@

/***@@@ BEGIN LICENSE @@@***/
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2013 eBay Software Foundation │
│ Copyright (C) 2014 eBay Software Foundation │
│ │

@@ -19,32 +18,27 @@ │hh ,'""`. │

\*───────────────────────────────────────────────────────────────────────────*/
/***@@@ END LICENSE @@@***/
'use strict';
var fs = require('fs'),
path = require('path'),
resolver = require('./lib/resolver');
var fs = require('fs');
var path = require('path');
var resolver = require('./lib/resolver');
exports.create = function (parent) {
function isModule(file) {
// require.resolve will locate a file without a known extension (e.g. txt)
// and try to load it as javascript. That won't work for this case.
var ext = path.extname(file);
return ext === '' || require.extensions.hasOwnProperty(ext);
}
exports.create = function create(parent) {
return Object.create(resolver.create(parent), {
resolveFile: {
value: function (file, callback) {
var self, ext;
value: function resolveFile(file, callback) {
var resolve = this.resolve.bind(this);
self = this;
function done(err, data) {
if (err) {
callback(err);
return;
}
callback(null, self.resolve(data));
}
// Short circuit file types node can handle natively.
ext = path.extname(file);
if (ext === '' || require.extensions.hasOwnProperty(ext)) {
process.nextTick(done.bind(undefined, null, require(file)));
if (isModule(file)) {
resolve(require(file), callback);
return;

@@ -54,6 +48,4 @@ }

fs.readFile(file, 'utf8', function (err, data) {
var json, error;
if (err) {
done(err);
callback(err);
return;

@@ -63,28 +55,9 @@ }

try {
json = JSON.parse(data);
error = null;
data = JSON.parse(data);
resolve(data, callback);
} catch (err) {
json = undefined;
error = err;
} finally {
done(error, json);
callback(err);
}
});
}
},
resolveFileSync: {
value: function (file) {
var data, ext;
ext = path.extname(file);
if (ext === '' || require.extensions.hasOwnProperty(ext)) {
return this.resolve(require(file));
}
data = fs.readFileSync(file, 'utf8');
data = JSON.parse(data);
return this.resolve(data);
}
}

@@ -91,0 +64,0 @@

@@ -1,4 +0,3 @@

/***@@@ BEGIN LICENSE @@@***/
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2013 eBay Software Foundation │
│ Copyright (C) 2014 eBay Software Foundation │
│ │

@@ -19,22 +18,88 @@ │hh ,'""`. │

\*───────────────────────────────────────────────────────────────────────────*/
/***@@@ END LICENSE @@@***/
'use strict';
var async = require('async');
var thing = require('core-util-is');
exports.create = function (parent) {
exports.create = function create(parent) {
return {
_parent: parent,
parent: parent,
_handlers: Object.create(null),
use: function (protocol, impl) {
var handlers, handler, index, removed;
/**
* Locates a handler for the provided value, searching the parent, if necessary
* @param value the value to match
* @returns {Object} the handler, if found, otherwise undefined.
*/
getHandler: function getHandler(value) {
var resolver, handler;
resolver = this;
handler = undefined;
while (!handler && resolver && resolver._handlers) {
Object.keys(resolver._handlers).some(function (protocol) {
var current = resolver._handlers[protocol];
// Test the value to see if this is the appropriate handler.
if (current.predicate(value)) {
handler = current;
return true;
}
return false;
});
// Move to the parent
resolver = resolver.parent;
}
return handler;
},
/**
* Returns the handler stack for a given protocol, including parent handlers
* @param protocol
* @returns []
*/
getStack: function getStack(protocol) {
var currentStack, parentStack, hasParent;
currentStack = this._handlers[protocol] && this._handlers[protocol].stack;
parentStack = this.parent && this.parent.getStack(protocol);
hasParent = parentStack && parentStack.length;
if (currentStack && hasParent) {
return currentStack.concat(parentStack);
}
if (hasParent) {
return parentStack;
}
return currentStack;
},
/**
* Register a given handler for the provided protocol.
* @param protocol the protocol for which the handler should be registered.
* @param impl the handler function with the signature `function (input, [fn])`
* @returns {Function} invoke to remove the registered handler from the stack
*/
use: function use(protocol, impl) {
var handlers, handler, removed;
handlers = this._handlers;
handler = handlers[protocol];
if(!handler) {
if (!handler) {
handler = handlers[protocol] = {

@@ -55,66 +120,93 @@

index = handler.stack.push(impl);
handler.stack.push(impl);
removed = false;
// Unuse
return function () {
return function unuse() {
var idx;
if (!removed) {
removed = true;
return handler.stack.splice(index - 1, 1)[0];
idx = handler.stack.indexOf(impl);
return handler.stack.splice(idx, 1)[0];
}
return undefined;
}
};
},
getStack: function (protocol) {
var current, parent, hasParent;
current = this._handlers[protocol] && this._handlers[protocol].stack;
parent = this._parent && this._parent.getStack(protocol);
hasParent = parent && parent.length;
/**
* Resolves all the protocols contained in the provided object.
* @param data The data structure to scan
* @param callback the callback to invoke when processing is complete with the signature `function (err, data)`
*/
resolve: function resolve(data, callback) {
var self, tasks, handler;
if (current && hasParent) {
return current.concat(parent);
}
self = this;
if (hasParent) {
return parent;
}
if (thing.isObject(data)) {
return current;
},
if (thing.isArray(data)) {
tasks = data.map(function (val) {
return resolve.bind(self, val);
});
} else {
tasks = {};
Object.keys(data).forEach(function (key) {
tasks[key] = resolve.bind(self, data[key]);
});
}
resolve: function resolve(src) {
var dest, handlers;
async.parallel(tasks, function (err, data) {
err ? callback(err) : callback(null, data);
});
dest = src;
} else if (thing.isString(data)) {
if (typeof src === 'object' && src !== null) {
tasks = [];
dest = (Array.isArray(src) ? [] : Object.create(Object.getPrototypeOf(src)));
Object.keys(src).forEach(function (key) {
dest[key] = this.resolve(src[key]);
}, this);
handler = this.getHandler(data);
if (!handler) {
setImmediate(callback.bind(null, null, data));
return;
}
} else if (typeof src === 'string') {
// Remove protocol prefix
data = data.slice(handler.protocol.length + 1);
handlers = this._handlers;
Object.keys(handlers).forEach(function (protocol) {
var handler = handlers[protocol];
tasks = self.getStack(handler.protocol).map(function (handler) {
if (handler.length < 2) {
return function wrapper(input, done) {
var data, error;
if (handler.predicate(src)) {
// run through stack and mutate
dest = src.slice(protocol.length + 1);
this.getStack(protocol).forEach(function (handler) {
dest = handler(dest);
});
try {
data = handler(input);
} catch (err) {
error = err;
}
done(error, data);
};
}
}, this);
return handler;
});
tasks.unshift(function init(done) {
done(null, data);
});
// Waterfall will *always* resolve asynchronously
async.waterfall(tasks, callback);
} else {
// Non-protocol-able value
callback(null, data);
}
return dest;
}
};
};
};

@@ -1,4 +0,3 @@

/***@@@ BEGIN LICENSE @@@***/
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2013 eBay Software Foundation │
│ Copyright (C) 2014 eBay Software Foundation │
│ │

@@ -18,3 +17,2 @@ │hh ,'""`. │

│ limitations under the License. │
\*───────────────────────────────────────────────────────────────────────────*/
/***@@@ END LICENSE @@@***/
\*───────────────────────────────────────────────────────────────────────────*/
{
"name": "shortstop",
"version": "0.0.1",
"version": "1.0.0",
"description": "Enable use of protocols (such as file:, buffer:, or method:) in configuration files.",
"main": "index.js",
"scripts": {
"test": "make test"
"test": "tape test/*.js",
"cover": "istanbul cover tape -- test/*.js",
"lint": "jshint -c .jshintrc index.js"
},

@@ -29,5 +31,10 @@ "repository": {

"devDependencies": {
"mocha": "~1.13.0",
"chai": "~1.8.0"
"tape": "~2.5.0",
"istanbul": "~0.2.4",
"jshint": "~2.4.4"
},
"dependencies": {
"core-util-is": "~1.0.1",
"async": "~0.2.10"
}
}

@@ -1,5 +0,3 @@

shortstop
=========
# shortstop
Sometimes JSON just isn't enough for configuration needs. Occasionally it would be nice to use arbitrary types as values,

@@ -9,6 +7,19 @@ but JSON is necessarily a subset of all available JS types. `shortstop` enables the use of protocols and handlers to

#### The Basics
[![Build Status](https://travis-ci.org/paypal/shortstop-handlers.png?branch=master)](https://travis-ci.org/paypal/shortstop-handlers)
```json
{
```javascript
var fs = require('fs');
var shortstop = require('shortstop');
function buffer(value) {
return new Buffer(value);
}
var resolver, json;
resolver = shortstop.create();
resolver.use('buffer', buffer);
resolver.use('file', fs.readFile);
json = {
"secret": "buffer:SGVsbG8sIHdvcmxkIQ==",

@@ -19,56 +30,52 @@ "ssl": {

}
}
};
resolver.resolve(json, function (err, data) {
console.log(data);
// {
// "secret": <Buffer ... >,
// "ssl" {
// "pfx": <Buffer ... >,
// "key": <Buffer ... >
// }
// }
});
```
```javascript
var fs = require('fs'),
shortstop = require('shortstop');
## API
### shortstop.create([parent]);
* `parent` (*Object*, optional) - An optional shortstop resolver. Returns a resolver instance.
function buffer(value) {
return new Buffer(value);
}
### resolver.use(protocol, handler);
function file(value) {
return fs.readFileSync(value);
}
* `protocol` (*String*) - The protocol used to identify a property to be processed, e.g. "file"
* `handler` (*Function*) - The implementation of the given protocol with signature `function (value, [callback])`
This method returns a function when invoked will remove the handler from the stack for this protocol.
var resolver, data;
resolver = shortstop.create();
resolver.use('buffer', buffer);
resolver.use('file', file);
data = resolver.resolve(json);
### resolver.resolve(data, callback);
// {
// "secret": <Buffer ... >,
// "ssl" {
// "pfx": <Buffer ... >,
// "key": <Buffer ... >
// }
// }
* `data` (*Object*) - The object, containing protocols in values, to be processed.
* `callback` (*Function*) - The callback invoked when the processing is complete with signature `function (err, result)`.
```
### resolver.resolveFile(path, callback);
#### Multiple handlers
* `path` (*String*) - The path to a file which is, or exports, JSON or a javascript object.
* `callback` (*Function*) - The callback invoked when the processing is complete with signature `function (err, result)`.
## Multiple handlers
Multiple handlers can be registered for a given protocol. They will be executed in the order registered and the output
of one handler will be the input of the next handler in the chain.
```json
{
"key": "file:foo/baz.key",
"certs": "path:certs/myapp"
}
```
```javascript
var fs = require('fs'),
path = require('path'),
shortstop = require('shortstop');
var path = require('path'),
var shortstop = require('shortstop');
function path(value) {
function resolve(value) {
if (path.resolve(value) === value) {

@@ -78,54 +85,37 @@ // Is absolute path already

}
return path.join(process.cwd(), value;
return path.join(process.cwd(), value);
}
function file(value) {
return fs.readFileSync(value);
}
var resolver, data;
var resolver, json;
resolver = shortstop.create();
resolver.use('path', path);
resolver.use('path', resolve);
resolver.use('file', resolve);
resolver.use('file', fs.readFile);
resolver.use('file', path);
resolver.use('file', file);
json = {
"key": "file:foo/baz.key",
"certs": "path:certs/myapp"
};
data = resolver.resolve(json);
// {
// "key": <Buffer ... >,
// "certs": "/path/to/my/certs/myapp"
// }
resolver.resolve(json, function (err, data) {
console.log(data);
// {
// "key": <Buffer ... >,
// "certs": "/path/to/my/certs/myapp"
// }
});
```
#### Removing Handlers
## Removing Handlers
When registered, handlers return an `unregister` function you can call when you no longer want a handler in the chain.
```js
// json1
{
"key": "path:foo/baz.key"
}
```
```js
// json2
{
"key": "path:foo/bar.key"
}
```
```javascript
var fs = require('fs'),
path = require('path'),
shortstop = require('shortstop');
var path = require('path');
var shortstop = require('shortstop');
function path(value) {
function resolve(value) {
if (path.resolve(value) === value) {

@@ -135,23 +125,25 @@ // Is absolute path already

}
return path.join(process.cwd(), value;
return path.join(process.cwd(), value);
}
var resolver, unuse, data;
var resolver, unuse, json;
resolver = shortstop.create();
unuse = resolver.use('path', path);
data = resolver.resolve(json1);
unuse = resolver.use('path', resolve);
json = { "key": "path:foo/baz.key" };
// {
// "key": "/path/to/my/foo/baz.key"
// }
resolver.resolve(json, function (err, data) {
console.log(data);
// {
// "key": "/path/to/my/foo/baz.key"
// }
unuse();
unuse();
data = resolver.resolve(json2);
// {
// "key": "path:foo/bar.key"
// }
resolver.resolve(json, function (err, data) {
console.log(data);
// {
// "key": "path:foo/baz.key"
// }
});
});
```

Sorry, the diff of this file is not supported yet

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