UNPKG

templatizer

Version:

Simple solution for compiling jade templates into vanilla JS functions for blazin' fast client-side use.

183 lines (153 loc) 5.54 kB
var escodegen = require('escodegen'); var falafel = require('falafel'); var namedTemplateFn = require('./namedTemplateFn'); var bracketedName = require('./bracketedName'); var templateName = require('./templateName'); function bufDeclartion(name) { return { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": name || "buf" }, "init": { "type": "ArrayExpression", "elements": [] } }; } function jadeInterpDeclaration() { return { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "jade_interp" } }; } function returnBuf(name) { return { "type": "ReturnStatement", "argument": { "type": "CallExpression", "callee": { "type": "MemberExpression", "computed": false, "object": { "type": "Identifier", "name": name || "buf" }, "property": { "type": "Identifier", "name": "join" } }, "arguments": [ { "type": "Literal", "value": "", "raw": "\"\"" } ] } }; } function transformMixinCalls(node, options) { var mixinName; var mixinInvocation; var newCall; // Check all fn calls to see if they are mixins if ( node.type === 'ExpressionStatement' && node.expression.type === 'CallExpression' && node.expression.callee && node.expression.callee.object && ( node.expression.callee.object.name === 'jade_mixins' || ( node.expression.callee.object.object && node.expression.callee.object.object.name === 'jade_mixins' ) ) ) { var callee = node.expression.callee; var calleeProp = callee.property; var calleeObject = callee.object; mixinName = (calleeProp && calleeProp.value) || (calleeObject && calleeObject.property && calleeObject.property.value); mixinInvocation = options.rootName + bracketedName(options.dir.split('.')); if (mixinName) { mixinInvocation += bracketedName([mixinName]); } else { mixinInvocation += "[" + escodegen.generate(calleeProp) + "]"; } // Call the function from templatizer and its path // Also send the func return val to the buffer array newCall = 'buf.push(' + mixinInvocation; // TODO: makde this use falafel/escodegen instead of regex replacement newCall = node.source().replace(/^jade_mixins\[.*?\]([\s\S]*);$/gm, newCall + '$1);'); // TODO: use codegen to add buf to block // Use the buf that is scoped to the mixin for the block newCall = newCall.replace('block: function () {', 'block: function (buf) {'); node.update(newCall); } } function findAndReplaceMixin(node, options) { var mixinName; var mixinStatements; var mixin = ''; // Check all assignments to see if they are mixins if ( node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression' && node.expression.left && node.expression.left.object && node.expression.left.object.name === 'jade_mixins' ) { mixinName = node.expression.left.property.value; mixinStatements = node.expression.right.right.body.body; // Add buffer array to variable declarations mixinStatements[0].declarations.push(bufDeclartion()); // Add jade_interp declaration for use in 'strict mode' mixinStatements[0].declarations.push(jadeInterpDeclaration()); // Return the buffer joined as a string from the function mixinStatements.push(returnBuf()); // Update the node node.expression.update(escodegen.generate(node.expression)); // Make the mixin a named function declaration node.expression.right.right.type = 'FunctionDeclaration'; node.expression.right.right.id = { "type": "Identifier", "name": templateName(options.dir + '_' + mixinName) }; // Traverse newly updated mixin functions for calls to other mixins mixin = falafel(escodegen.generate(node.expression.right.right), function (node) { transformMixinCalls(node, options); }).toString(); // TODO: use codegen to add buf to block // Use the buf scoped to the mixin for each block mixin = mixin.replace(/block && block\(\);/g, 'block && block(buf);'); // Add a commented and named function to be returned mixin = namedTemplateFn({ fn: mixin, rootName: options.rootName, dir: options.dir, mixinName: mixinName }); // Remove the previous creation of the mixin function node.update(''); } return mixin; } module.exports = function (options) { var mixins = []; var template = falafel(options.template, function (node) { var mixin = findAndReplaceMixin(node, options); if (mixin) mixins.push(mixin); transformMixinCalls(node, options); }); return { template: template, mixins: mixins }; };