111 lines
3.1 KiB
JavaScript
111 lines
3.1 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
|
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
* Code distributed by Google as part of the polymer project is also
|
|
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
*/
|
|
|
|
// jshint node:true
|
|
'use strict';
|
|
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
var pathIsAbsolute = require('path-is-absolute');
|
|
var url = require('url');
|
|
|
|
function getFile(filePath, deferred, secondPath) {
|
|
fs.readFile(filePath, 'utf-8', function(err, content) {
|
|
if (err) {
|
|
if (secondPath) {
|
|
getFile(secondPath, deferred);
|
|
} else {
|
|
console.log("ERROR finding " + filePath);
|
|
deferred.reject(err);
|
|
}
|
|
} else {
|
|
deferred.resolve(content);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns true if `patha` is a sibling or aunt of `pathb`.
|
|
* @return {boolean}
|
|
*/
|
|
function isSiblingOrAunt(patha, pathb) {
|
|
var parent = path.dirname(patha);
|
|
if (pathb.indexOf(patha) === -1 && pathb.indexOf(parent) === 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Change `localPath` from a sibling of `basePath` to be a child of
|
|
* `basePath` joined with `redirect`.
|
|
* @return {string}
|
|
*/
|
|
function redirectSibling(basePath, localPath, redirect) {
|
|
var parent = path.dirname(basePath);
|
|
var redirected = path.join(basePath, redirect, localPath.slice(parent.length));
|
|
return redirected;
|
|
}
|
|
|
|
/**
|
|
* Resolves requests via the file system.
|
|
* @constructor
|
|
* @memberof hydrolysis
|
|
* @param {Object} config configuration options.
|
|
* @param {string} config.host Hostname to match for absolute urls.
|
|
* Matches "/" by default
|
|
* @param {string} config.basePath Prefix directory for components in url.
|
|
* Defaults to "/".
|
|
* @param {string} config.root Filesystem root to search. Defaults to the
|
|
* current working directory.
|
|
* @param {string} config.redirect Where to redirect lookups to siblings.
|
|
*/
|
|
function FSResolver(config) {
|
|
this.config = config || {};
|
|
}
|
|
FSResolver.prototype = {
|
|
accept: function(uri, deferred) {
|
|
var parsed = url.parse(uri);
|
|
var host = this.config.host;
|
|
var base = this.config.basePath && decodeURIComponent(this.config.basePath);
|
|
var root = this.config.root && path.normalize(this.config.root);
|
|
var redirect = this.config.redirect;
|
|
|
|
var local;
|
|
|
|
if (!parsed.hostname || parsed.hostname === host) {
|
|
local = parsed.pathname;
|
|
}
|
|
if (local) {
|
|
// un-escape HTML escapes
|
|
local = decodeURIComponent(local);
|
|
|
|
if (base) {
|
|
local = path.relative(base, local);
|
|
}
|
|
if (root) {
|
|
local = path.join(root, local);
|
|
}
|
|
|
|
var backup;
|
|
if (redirect && isSiblingOrAunt(root, local)) {
|
|
backup = redirectSibling(root, local, redirect);
|
|
}
|
|
|
|
getFile(local, deferred, backup);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
module.exports = FSResolver;
|