path-loader
Version:
Utility that provides a single API for loading the content of a path/URL.
204 lines (185 loc) • 6.4 kB
JavaScript
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Jeremy Whitlock
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
;
var supportedLoaders = {
file: require('./lib/loaders/file'),
http: require('./lib/loaders/http'),
https: require('./lib/loaders/http')
};
var defaultLoader = typeof window === 'object' || typeof importScripts === 'function' ?
supportedLoaders.http :
supportedLoaders.file;
// Load promises polyfill if necessary
/* istanbul ignore if */
if (typeof Promise === 'undefined') {
require('native-promise-only');
}
function getScheme (location) {
if (typeof location !== 'undefined') {
location = location.indexOf('://') === -1 ? '' : location.split('://')[0];
}
return location;
}
/**
* Utility that provides a single API for loading the content of a path/URL.
*
* @module path-loader
*/
function getLoader (location) {
var scheme = getScheme(location);
var loader = supportedLoaders[scheme];
if (typeof loader === 'undefined') {
if (scheme === '') {
loader = defaultLoader;
} else {
throw new Error('Unsupported scheme: ' + scheme);
}
}
return loader;
}
/**
* Loads a document at the provided location and returns a JavaScript object representation.
*
* @param {string} location - The location to the document
* @param {module:path-loader.LoadOptions} [options] - The loader options
*
* @returns {Promise<*>} Always returns a promise even if there is a callback provided
*
* @example
* // Example using Promises
*
* PathLoader
* .load('./package.json')
* .then(JSON.parse)
* .then(function (document) {
* console.log(document.name + ' (' + document.version + '): ' + document.description);
* }, function (err) {
* console.error(err.stack);
* });
*
* @example
* // Example using options.prepareRequest to provide authentication details for a remotely secure URL
*
* PathLoader
* .load('https://api.github.com/repos/whitlockjc/path-loader', {
* prepareRequest: function (req, callback) {
* req.auth('my-username', 'my-password');
* callback(undefined, req);
* }
* })
* .then(JSON.parse)
* .then(function (document) {
* console.log(document.full_name + ': ' + document.description);
* }, function (err) {
* console.error(err.stack);
* });
*
* @example
* // Example loading a YAML file
*
* PathLoader
* .load('/Users/not-you/projects/path-loader/.travis.yml')
* .then(YAML.safeLoad)
* .then(function (document) {
* console.log('path-loader uses the', document.language, 'language.');
* }, function (err) {
* console.error(err.stack);
* });
*
* @example
* // Example loading a YAML file with options.processContent (Useful if you need information in the raw response)
*
* PathLoader
* .load('/Users/not-you/projects/path-loader/.travis.yml', {
* processContent: function (res, callback) {
* callback(YAML.safeLoad(res.text));
* }
* })
* .then(function (document) {
* console.log('path-loader uses the', document.language, 'language.');
* }, function (err) {
* console.error(err.stack);
* });
*/
module.exports.load = function (location, options) {
var allTasks = Promise.resolve();
// Default options to empty object
if (typeof options === 'undefined') {
options = {};
}
// Validate arguments
allTasks = allTasks.then(function () {
if (typeof location === 'undefined') {
throw new TypeError('location is required');
} else if (typeof location !== 'string') {
throw new TypeError('location must be a string');
}
if (typeof options !== 'undefined') {
if (typeof options !== 'object') {
throw new TypeError('options must be an object');
} else if (typeof options.processContent !== 'undefined' && typeof options.processContent !== 'function') {
throw new TypeError('options.processContent must be a function');
}
}
});
// Load the document from the provided location and process it
allTasks = allTasks
.then(function () {
return new Promise(function (resolve, reject) {
var loader = getLoader(location);
loader.load(location, options || {}, function (err, document) {
if (err) {
reject(err);
} else {
resolve(document);
}
});
});
})
.then(function (res) {
if (options.processContent) {
return new Promise(function (resolve, reject) {
// For consistency between file and http, always send an object with a 'text' property containing the raw
// string value being processed.
if (typeof res !== 'object') {
res = {text: res};
}
// Pass the path being loaded
res.location = location;
options.processContent(res, function (err, processed) {
if (err) {
reject(err);
} else {
resolve(processed);
}
});
});
} else {
// If there was no content processor, we will assume that for all objects that it is a Superagent response
// and will return its `text` property value. Otherwise, we will return the raw response.
return typeof res === 'object' ? res.text : res;
}
});
return allTasks;
};