shortstop-handlers
Version:
Common protocol handlers for use with the shortstop node module.
216 lines (180 loc) • 6.61 kB
JavaScript
/*───────────────────────────────────────────────────────────────────────────*\
│ Copyright (C) 2014 eBay Software Foundation │
│ │
│ Licensed under the Apache License, Version 2.0 (the "License"); │
│ you may not use this file except in compliance with the License. │
│ You may obtain a copy of the License at │
│ │
│ http://www.apache.org/licenses/LICENSE-2.0 │
│ │
│ Unless required by applicable law or agreed to in writing, software │
│ distributed under the License is distributed on an "AS IS" BASIS, │
│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │
│ See the License for the specific language governing permissions and │
│ limitations under the License. │
\*───────────────────────────────────────────────────────────────────────────*/
;
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var caller = require('caller');
var thing = require('core-util-is');
(function expandModulePaths() {
// If this module is deployed outside the app's node_modules, it wouldn't be
// able to resolve other modules deployed under app while evaluating this shortstops.
// Adding app's node_modules folder to the paths will help handle this case.
var paths = module.paths;
var appNodeModules = path.resolve(process.cwd(), 'node_modules');
if (paths.indexOf(appNodeModules) < 0) {
// Assuming Module._nodeModulePaths creates a new module.paths object for each module.
paths.push(appNodeModules);
}
})();
function startsWith(haystack, needle) {
return haystack.indexOf(needle) === 0;
}
/**
* Creates the protocol handler for the `path:` protocol
* @param basedir
* @returns {Function}
*/
function _path(basedir) {
basedir = basedir || path.dirname(caller());
return function pathHandler(file) {
if (path.resolve(file) === file) {
// Absolute path already, so just return it.
return file;
}
file = file.split('/');
file.unshift(basedir);
return path.resolve.apply(path, file);
};
}
/**
* Creates the protocol handler for the `file:` protocol
* @param basedir
* @param options
* @returns {Function}
*/
function _file(basedir, options) {
var pathHandler;
if (thing.isObject(basedir)) {
options = basedir;
basedir = undefined;
}
pathHandler = _path(basedir);
options = options || { encoding: null, flag: 'r' };
return function fileHandler(file, cb) {
fs.readFile(pathHandler(file), options, cb);
};
}
/**
* Creates the protocol handler for the `buffer:` protocol
* @returns {Function}
*/
function _base64() {
return function base64Handler(value) {
return new Buffer(value, 'base64');
};
}
/**
* Creates the protocol handler for the `env:` protocol
* @returns {Function}
*/
function _env() {
var filters = {
'd': function (value) {
return parseInt(value, 10);
},
'b': function (value) {
return value !== '' && value !== 'false' && value !== '0' && value !== undefined;
},
'!b': function (value) {
return value === '' || value === 'false' || value === '0' || value === undefined;
}
};
return function envHandler(value) {
var result;
Object.keys(filters).some(function (key) {
var fn, pattern, loc;
fn = filters[key];
pattern = '|' + key;
loc = value.indexOf(pattern);
if (loc > -1 && loc === value.length - pattern.length) {
value = value.slice(0, -pattern.length);
result = fn(process.env[value]);
return true;
}
return false;
});
return result === undefined ? process.env[value] : result;
};
}
/**
* Creates the protocol handler for the `require:` protocol
* @param basedir
* @returns {Function}
*/
function _require(basedir) {
var resolvePath = _path(basedir);
return function requireHandler(value) {
var module = value;
// @see http://nodejs.org/api/modules.html#modules_file_modules
if (startsWith(value, '/') || startsWith(value, './') || startsWith(value, '../')) {
// NOTE: Technically, paths with a leading '/' don't need to be resolved, but
// leaving for consistency.
module = resolvePath(module);
}
return require(module);
};
}
/**
* Creates the protocol handler for the `exec:` protocol
* @param basedir
* @returns {Function}
*/
function _exec(basedir) {
var require = _require(basedir);
return function execHandler(value) {
var tuple, module, method;
tuple = value.split('#');
module = require(tuple[0]);
method = tuple[1] ? module[tuple[1]] : module;
if (thing.isFunction(method)) {
return method();
}
throw new Error('exec: unable to locate function in ' + value);
};
}
/**
* Creates the protocol handler for the `glob:` protocol
* @param options https://github.com/isaacs/node-glob#options
* @returns {Function}
*/
function _glob(options) {
var resolvePath;
if (thing.isString(options)) {
options = { cwd: options };
}
options = options || {};
options.cwd = options.cwd || path.dirname(caller());
resolvePath = _path(options.cwd);
return function globHandler(value, cb) {
glob(value, options, function (err, data) {
if (err) {
cb(err);
return;
}
cb(null, data.map(resolvePath));
});
};
}
module.exports = {
path: _path,
file: _file,
base64: _base64,
env: _env,
require: _require,
exec: _exec,
glob: _glob
};