Last active
October 26, 2017 21:48
-
-
Save steevhise/2ddac162d43c3a6112d3e983c73b4e32 to your computer and use it in GitHub Desktop.
custom swig-templates template loader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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