UNPKG

5.21 kBJavaScriptView Raw
1var escodegen = require('escodegen');
2var falafel = require('falafel');
3var namedTemplateFn = require('./namedTemplateFn');
4var bracketedName = require('./bracketedName');
5var templateName = require('./templateName');
6
7
8function bufDeclartion(name) {
9 return {
10 "type": "VariableDeclarator",
11 "id": {
12 "type": "Identifier",
13 "name": name || "buf"
14 },
15 "init": {
16 "type": "ArrayExpression",
17 "elements": []
18 }
19 };
20}
21
22function returnBuf(name) {
23 return {
24 "type": "ReturnStatement",
25 "argument": {
26 "type": "CallExpression",
27 "callee": {
28 "type": "MemberExpression",
29 "computed": false,
30 "object": {
31 "type": "Identifier",
32 "name": name || "buf"
33 },
34 "property": {
35 "type": "Identifier",
36 "name": "join"
37 }
38 },
39 "arguments": [
40 {
41 "type": "Literal",
42 "value": "",
43 "raw": "\"\""
44 }
45 ]
46 }
47 };
48}
49
50function transformMixinCalls(node, options) {
51 var mixinName;
52 var mixinInvocation;
53 var newCall;
54
55 // Check all fn calls to see if they are mixins
56 if (
57 node.type === 'ExpressionStatement' &&
58 node.expression.type === 'CallExpression' &&
59 node.expression.callee &&
60 node.expression.callee.object &&
61 (
62 node.expression.callee.object.name === 'jade_mixins' ||
63 (
64 node.expression.callee.object.object &&
65 node.expression.callee.object.object.name === 'jade_mixins'
66 )
67 )
68 ) {
69
70 var callee = node.expression.callee;
71 var calleeProp = callee.property;
72 var calleeObject = callee.object;
73
74 mixinName = (calleeProp && calleeProp.value) ||
75 (calleeObject && calleeObject.property && calleeObject.property.value);
76
77 mixinInvocation = options.rootName + bracketedName(options.dir.split('.'));
78
79 if (mixinName) {
80 mixinInvocation += bracketedName([mixinName]);
81 } else {
82 mixinInvocation += "[" + escodegen.generate(calleeProp) + "]";
83 }
84
85 // Call the function from templatizer and its path
86 // Also send the func return val to the buffer array
87 newCall = 'buf.push(' + mixinInvocation;
88 // TODO: makde this use falafel/escodegen instead of regex replacement
89 newCall = node.source().replace(/^jade_mixins\[.*?\]([\s\S]*);$/gm, newCall + '$1);');
90
91 // TODO: use codegen to add buf to block
92 // Use the buf that is scoped to the mixin for the block
93 newCall = newCall.replace('block: function () {', 'block: function (buf) {');
94
95 node.update(newCall);
96 }
97}
98
99function findAndReplaceMixin(node, options) {
100 var mixinName;
101 var mixinStatements;
102 var mixin = '';
103
104 // Check all assignments to see if they are mixins
105 if (
106 node.type === 'ExpressionStatement' &&
107 node.expression.type === 'AssignmentExpression' &&
108 node.expression.left &&
109 node.expression.left.object &&
110 node.expression.left.object.name === 'jade_mixins'
111 ) {
112 mixinName = node.expression.left.property.value;
113 mixinStatements = node.expression.right.right.body.body;
114
115 // Add buffer array to variable declarations
116 mixinStatements[0].declarations.push(bufDeclartion());
117
118 // Return the buffer joined as a string from the function
119 mixinStatements.push(returnBuf());
120
121 // Update the node
122 node.expression.update(escodegen.generate(node.expression));
123
124 // Make the mixin a named function declaration
125 node.expression.right.right.type = 'FunctionDeclaration';
126 node.expression.right.right.id = {
127 "type": "Identifier",
128 "name": templateName(options.dir + '_' + mixinName)
129 };
130
131 // Traverse newly updated mixin functions for calls to other mixins
132 mixin = falafel(escodegen.generate(node.expression.right.right), function (node) {
133 transformMixinCalls(node, options);
134 }).toString();
135
136 // TODO: use codegen to add buf to block
137 // Use the buf scoped to the mixin for each block
138 mixin = mixin.replace(/block && block\(\);/g, 'block && block(buf);');
139
140 // Add a commented and named function to be returned
141 mixin = namedTemplateFn({
142 fn: mixin,
143 rootName: options.rootName,
144 dir: options.dir,
145 mixinName: mixinName
146 });
147
148 // Remove the previous creation of the mixin function
149 node.update('');
150 }
151
152 return mixin;
153}
154
155module.exports = function (options) {
156 var mixins = [];
157
158 var template = falafel(options.template, function (node) {
159 var mixin = findAndReplaceMixin(node, options);
160 if (mixin) mixins.push(mixin);
161 transformMixinCalls(node, options);
162 });
163
164 return {
165 template: template,
166 mixins: mixins
167 };
168};
169