1 | var jade = require('jade');
|
2 | var beautify = require('./lib/beautify');
|
3 | var simplifyTemplate = require('./lib/simplifyTemplate');
|
4 | var transformMixins = require('./lib/transformMixins');
|
5 | var renameJadeFn = require('./lib/renameJadeFn');
|
6 | var walkdir = require('walkdir');
|
7 | var path = require('path');
|
8 | var util = require('util');
|
9 | var _ = require('lodash');
|
10 | var fs = require('fs');
|
11 | var uglifyjs = require('uglify-js');
|
12 | var namedTemplateFn = require('./lib/namedTemplateFn');
|
13 | var bracketedName = require('./lib/bracketedName');
|
14 | var glob = require('glob');
|
15 |
|
16 |
|
17 |
|
18 | function DynamicMixinsCompiler () {
|
19 | jade.Compiler.apply(this, arguments);
|
20 | this.dynamicMixins = true;
|
21 | }
|
22 | util.inherits(DynamicMixinsCompiler, jade.Compiler);
|
23 |
|
24 | module.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: ''
|
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 |
|
49 | if (namespace) {
|
50 | namespace = bracketedName(namespace.split('.'));
|
51 | }
|
52 |
|
53 |
|
54 |
|
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 |
|
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 |
|
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 |
|
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 | };
|