UNPKG

6.13 kBJavaScriptView Raw
1var jade = require('jade');
2var beautify = require('./lib/beautify');
3var simplifyTemplate = require('./lib/simplifyTemplate');
4var transformMixins = require('./lib/transformMixins');
5var renameJadeFn = require('./lib/renameJadeFn');
6var walkdir = require('walkdir');
7var path = require('path');
8var util = require('util');
9var _ = require('lodash');
10var fs = require('fs');
11var uglifyjs = require('uglify-js');
12var namedTemplateFn = require('./lib/namedTemplateFn');
13var bracketedName = require('./lib/bracketedName');
14var glob = require('glob');
15
16// Setting dynamicMixins to true will result in
17// all mixins being written to the file
18function DynamicMixinsCompiler () {
19 jade.Compiler.apply(this, arguments);
20 this.dynamicMixins = true;
21}
22util.inherits(DynamicMixinsCompiler, jade.Compiler);
23
24module.exports = function (templateDirectories, outputFile, options) {
25 options || (options = {});
26
27 var internalNamespace = 'templatizer';
28
29 _.defaults(options, {
30 dontTransformMixins: false,
31 dontRemoveMixins: false,
32 jade: {},
33 namespace: '' // No namespace means 'window'
34 });
35
36 if (typeof templateDirectories === "string") {
37 templateDirectories = glob.sync(templateDirectories);
38 }
39
40 var namespace = _.isString(options.namespace) ? options.namespace : '';
41 var folders = [];
42 var templates = [];
43 var _readTemplates = [];
44 var isWindows = process.platform === 'win32';
45 var pathSep = path.sep || (isWindows ? '\\' : '/');
46 var pathSepRegExp = /\/|\\/g;
47
48 // Split our namespace on '.' and use bracket syntax
49 if (namespace) {
50 namespace = bracketedName(namespace.split('.'));
51 }
52
53 // Find jade runtime and create minified code
54 // where it is assigned to the variable jade
55 var placesToLook = [
56 __dirname + '/node_modules/jade/lib/runtime.js',
57 __dirname + '/jaderuntime.js'
58 ];
59 var jadeRuntime = fs.readFileSync(_.find(placesToLook, fs.existsSync)).toString();
60 var wrappedJade = uglifyjs.minify('var jade = (function(){var exports={};' + jadeRuntime + 'return exports;})();', {fromString: true}).code;
61
62 var outputTemplate = fs.readFileSync(__dirname + '/output_template.js').toString();
63 var output = '';
64
65 var jadeCompileOptions = {
66 client: true,
67 compileDebug: false,
68 pretty: false
69 };
70 _.extend(jadeCompileOptions, options.jade);
71
72 templateDirectories = _.chain(templateDirectories)
73 .map(function (templateDirectory) {
74 if(path.extname(templateDirectory).length > 1) {
75 // Remove filename and ext
76 return path.dirname(templateDirectory).replace(pathSepRegExp, pathSep);
77 }
78 return templateDirectory.replace(pathSepRegExp, pathSep);
79 })
80 .uniq()
81 .each(function (templateDirectory) {
82 if (!fs.existsSync(templateDirectory)) {
83 throw new Error('Template directory ' + templateDirectory + ' does not exist.');
84 }
85
86 walkdir.sync(templateDirectory).forEach(function (file) {
87 var item = file.replace(path.resolve(templateDirectory), '').slice(1);
88 // Skip hidden files
89 if (item.charAt(0) === '.' || item.indexOf(pathSep + '.') !== -1) {
90 return;
91 }
92 if (path.extname(item) === '' && path.basename(item).charAt(0) !== '.') {
93 if (folders.indexOf(item) === -1) folders.push(item);
94 } else if (path.extname(item) === '.jade') {
95 // Throw an err if we are about to override a template
96 if (_readTemplates.indexOf(item) > -1) {
97 throw new Error(item + ' from ' + templateDirectory + pathSep + item + ' already exists in ' + templates[_readTemplates.indexOf(item)]);
98 }
99 _readTemplates.push(item);
100 templates.push(templateDirectory + pathSep + item);
101 }
102 });
103 })
104 .value();
105
106 folders = _.sortBy(folders, function (folder) {
107 var arr = folder.split(pathSep);
108 return arr.length;
109 });
110
111 output += folders.map(function (folder) {
112 return internalNamespace + bracketedName(folder.split(pathSep)) + ' = {};';
113 }).join('\n') + '\n';
114
115 templates.forEach(function (item) {
116 var name = path.basename(item, '.jade');
117 var dirString = function () {
118 var itemTemplateDir = _.find(templateDirectories, function (templateDirectory) {
119 return item.indexOf(templateDirectory + pathSep) === 0;
120 });
121 var dirname = path.dirname(item).replace(itemTemplateDir, '');
122 if (dirname === '.') return name;
123 dirname += '.' + name;
124 return dirname.substring(1).replace(pathSepRegExp, '.');
125 }();
126
127 if (options.dontRemoveMixins) {
128 jadeCompileOptions.compiler = DynamicMixinsCompiler;
129 }
130
131 jadeCompileOptions.filename = item;
132 var template = beautify(jade.compileClient(fs.readFileSync(item, 'utf-8'), jadeCompileOptions).toString());
133
134 template = renameJadeFn(template, dirString);
135 template = simplifyTemplate(template);
136
137 var mixins = [];
138 if (!options.dontTransformMixins) {
139 var astResult = transformMixins({
140 template: template,
141 name: name,
142 dir: dirString,
143 rootName: internalNamespace
144 });
145 mixins = astResult.mixins;
146 template = astResult.template;
147 }
148
149 output += namedTemplateFn({
150 dir: dirString,
151 rootName: internalNamespace,
152 fn: template
153 });
154
155 output += mixins.join('\n');
156 });
157
158 var indentOutput = output.split('\n').map(function (l) { return l ? ' ' + l : l; }).join('\n');
159 var finalOutput = outputTemplate
160 .replace(/\{\{namespace\}\}/g, namespace)
161 .replace(/\{\{internalNamespace\}\}/g, internalNamespace)
162 .replace('{{jade}}', wrappedJade)
163 .replace('{{code}}', indentOutput);
164
165 if (outputFile) fs.writeFileSync(outputFile, finalOutput);
166
167 return finalOutput;
168};