condensation
Version:
Package, reuse and share particles for CloudFormation projects
164 lines (138 loc) • 5.13 kB
JavaScript
var _ = require('lodash'),
fs = require('fs'),
File = require('vinyl'),
matter = require('gray-matter');
/*
* The build_helper function.
* Returns a helper function that is able to process a particle section
*
*
* @method buildHelper
* @param {String} particleName The name of the particle section (parameter|resource|...)
* @param {Object} options A config object
* @return {Function} A function that helps compile section particles
*/
module.exports = function buildHelper(particleName,options) {
var opts = _.merge({
wrapLogicalId: true
},options);
/*
* @param {String} cModule The condensation module being processed
* @param {String} pPath The particle path
* @param {Object} hArgs Handlebars arguments
* @param {Object} hOpts Handlebars options
* @param {Object} cOpts Condensation options
* @return {String} Finalized content for the particle section
*/
var helper = function(cModule,pPath,hArgs,hOpts,cOpts) {
// If this particle is extended by another and both have content blocks, merge them
// This variable holds the extended output to be merged.
var deepMerge = {};
var engine = cOpts.handlebars;
var data = cOpts.handlebars.createFrame(hOpts.data || {});
var wrapLogicalId = _.isUndefined(data.wrapLogicalId) ? opts.wrapLogicalId : data.wrapLogicalId;
var extended = data.extended || false;
var callerFile = data._file;
// Once a section has been started any subsequent calls should not wrap a logical id.
// Allows a particle to 'extend' another particle
data.extended = true;
data.wrapLogicalId = false;
var mergeParticleTemplate = '{}';
var templateContent = '{}';
if (hOpts.fn) {
templateContent = processTemplate.call(this,hOpts.fn,hOpts,cOpts,{data:{}},data,extended,particleName);
}
if (pPath) {
var particle = cOpts.particleLoader.loadParticle(particleName,cModule,pPath,{parentFile: hOpts.data._file});
var file = new File({path: particle.path});
m = matter(fs.readFileSync(particle.fsPath,{encoding:'utf8'}));
var pData = _.cloneDeep(data);
pData._file = file;
var fn = engine.compile(m.content,{noEscape:true,data:pData});
mergeParticleTemplate = processTemplate.call(this,fn,hOpts,cOpts,m,pData,true,particleName);
}
templateContent = JSON.stringify(_.merge(JSON.parse(mergeParticleTemplate),JSON.parse(templateContent)));
var finalContent = templateContent;
if (wrapLogicalId === true) {
var logicalId = hOpts.hash.logicalId;
if (hOpts.hash.scope !== false) {
var logicalIdPrefix = [hOpts.hash.logicalIdPrefix,this.logicalIdPrefix].join('');
var logicalIdSuffix = [this.logicalIdSuffix,hOpts.hash.logicalIdSuffix].join('');
logicalId = [logicalIdPrefix,logicalId,logicalIdSuffix].join('');
}
finalContent = ['"',logicalId,'":',finalContent].join('');
if (!logicalId) {
var message = [
"LogicalId undefined for ",
particleName,
" ",
(cModule ? cModule + ":" : ""),
pPath,
" called from ",
callerFile.path,
"\n\n",
finalContent
].join('');
throw new Error(message);
}
}
/* Check to see if this is being added to a layout.
* If so, add to the respective section.
*
* If not, return the string
*/
if (data._layoutContentPusher && data._layoutContentPusher[particleName] && !extended) {
data._layoutContentPusher[particleName](finalContent);
}
else {
return finalContent;
}
};
return helper;
};
var processTemplate = function(fn,hOpts,cOpts,m,data,extended,particleName) {
var engine = cOpts.handlebars;
var templateContent = '';
try {
if (extended) {
// If extending another particle of the same type merge `hOpts.hash` before `this`
templateContent = new engine.SafeString(fn(_.merge(m.data,hOpts.hash,this),{data:data}));
}
else {
templateContent = new engine.SafeString(fn(_.merge(m.data,this,hOpts.hash),{data:data}));
}
}
catch(e) {
if (e.name !== "SyntaxError") {
e.message = [data._file.path,"\n",e.message,"\n\n",m.orig].join('');
}
throw(e);
}
/* For backwards compatiblity with older partials check to see if the
* content is a valid JSON object. If it is, don't wrap the content in braces
*
*/
try {
var testContent = JSON.parse(templateContent);
if (!_.isObject(testContent)) {
throw new Error("Must be an Object");
}
}
catch(e) {
/* If the try block does not work, no need to catch the error.
* Wrap the string in braces and move on to the next try
*/
templateContent = '{'+templateContent+'}';
}
/* Ensure the manufactured string is JSON compliant.
* If not, trow an error for this inclusion.
*/
try {
JSON.parse(templateContent);
}
catch(e) {
e.message = ["Section parse error: ",particleName," in file ",hOpts.data._file.path,"\n",templateContent,"\n\n",e.message].join('');
throw(e);
}
return templateContent;
}