Skip to content

Instantly share code, notes, and snippets.

@steevhise
Last active October 26, 2017 21:48
Show Gist options
  • Save steevhise/2ddac162d43c3a6112d3e983c73b4e32 to your computer and use it in GitHub Desktop.
Save steevhise/2ddac162d43c3a6112d3e983c73b4e32 to your computer and use it in GitHub Desktop.
custom swig-templates template loader
/**
* fc-filestystem-loader
* This custom Swig template loader does 2 things differently from the regular Swig filesystem loader:
* 1. missing template files return an error string rather than throwing an error
* 2. if file isn't found in default place, looks in the "IncludeDir" (for common partials)
*
*/
let target;
/**
* Loads templates from the file system but looks in 2nd directory, and fails gracefully.
* @alias swig.loaders.fcfs
* @example
* swig.setDefaults({ loader: swig.loaders.fs() });
* @example
* // Load Templates from a specific directory (does not require using relative paths in your templates)
* Example: swig.setDefaults({ loader: FCLoader(basepath, __dirname + '/templates' )});
* @param {string} [basepath=''] Path to the templates as string. Assigning this value allows you to use semi-absolute paths to templates instead of relative paths.
* @param {string} [includeDir=''] Path to alternate directory where common template partials live - should be absolute path
* @param {string} [encoding='utf8'] Template encoding
*/
const FCLoader = function (basepath, includeDir, encoding) {
const ret = {};
encoding = encoding || 'utf8';
basepath = basepath ? Path.normalize(basepath) : null;
includeDir = includeDir ? Path.normalize(includeDir) : null;
/**
* Resolves <var>to</var> to an absolute path or unique identifier. This is used for building correct, normalized, and absolute paths to a given template.
* @alias resolve
* @param {string} to Non-absolute identifier or pathname to a file.
* @param {string} [from] If given, should attempt to find the <var>to</var> path in relation to this given, known path.
* @return {string}
*/
ret.resolve = function (to, from) {
if (basepath) {
from = basepath;
}
else {
from = from ? Path.dirname(from) : process.cwd();
}
return Path.resolve(from, to);
};
/**
* Loads a single template. Given a unique <var>identifier</var> found by the <var>resolve</var> method this should return the given template.
* @alias load
* @param {string} identifier Unique identifier of a template (possibly an absolute path).
* @param {function} [cb] Asynchronous callback function. If not provided, this method should run synchronously.
* @return {string} Template source string.
*/
ret.load = function (identifier, cb) {
if (!Fs || (cb && !Fs.readFile) || !Fs.readFileSync) {
throw new Error('Unable to find file ' + identifier + ' because there is no filesystem to read from.');
}
identifier = ret.resolve(identifier);
// we should make sure the file exists first. if it doesn't, look in our "common" area.
// at this point we don't know what the relative path is that was passed in from the tag.
// so we need to grab the basename and then search the whole includeDir, i guess...
if (!Fs.existsSync(identifier)) {
Debug('#could not find template file ' + identifier + ' in basepath#');
const files = Find.fileSync(Path.basename(identifier), includeDir);
Debug('looking for ' + Path.basename(identifier) + ' in ' + includeDir);
if (files[0]) {
target = files[0];
Debug('found ' + target);
return _loadIt(target, encoding, cb);
}
console.err('Template Loader: "' + identifier + '" not found anywhere, even in ' + includeDir);
return '<!-- could not find "' + identifier + '" anywhere, even in "' + includeDir + '" -->';
}
return _loadIt(identifier, encoding, cb); // else we found it first thing, so load it
};
return ret;
};
/**
* This is just a little function that conditionally wraps readFile or readFileSync
* @param id
* @param encoding
* @param cb
* @returns {*}
* @private
*/
const _loadIt = (id, encoding, cb) => {
// if still can't read file, catch the error and return an error string
if (cb) {
try {
Fs.readFile(id, encoding, cb);
}
catch (e) {
return 'error loading "' + id + '": ' + e;
}
return;
}
let output;
try {
output = Fs.readFileSync(id, encoding);
return output;
}
catch (e) {
output = 'Error loading "' + id + '": ' + e;
return output;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment