UNPKG

5.52 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3/**
4 * Module dependencies.
5 */
6
7var fs = require('fs')
8 , program = require('commander')
9 , path = require('path')
10 , basename = path.basename
11 , dirname = path.dirname
12 , resolve = path.resolve
13 , exists = fs.existsSync || path.existsSync
14 , join = path.join
15 , monocle = require('monocle')()
16 , mkdirp = require('mkdirp')
17 , jade = require('../');
18
19// jade options
20
21var options = {};
22
23// options
24
25program
26 .version(require('../package.json').version)
27 .usage('[options] [dir|file ...]')
28 .option('-O, --obj <str>', 'javascript options object')
29 .option('-o, --out <dir>', 'output the compiled html to <dir>')
30 .option('-p, --path <path>', 'filename used to resolve includes')
31 .option('-P, --pretty', 'compile pretty html output')
32 .option('-c, --client', 'compile function for client-side runtime.js')
33 .option('-n, --name <str>', 'The name of the compiled template (requires --client)')
34 .option('-D, --no-debug', 'compile without debugging (smaller functions)')
35 .option('-w, --watch', 'watch files for changes and automatically re-render')
36 .option('--name-after-file', 'Name the template after the last section of the file path (requires --client and overriden by --name)')
37
38
39program.on('--help', function(){
40 console.log(' Examples:');
41 console.log('');
42 console.log(' # translate jade the templates dir');
43 console.log(' $ jade templates');
44 console.log('');
45 console.log(' # create {foo,bar}.html');
46 console.log(' $ jade {foo,bar}.jade');
47 console.log('');
48 console.log(' # jade over stdio');
49 console.log(' $ jade < my.jade > my.html');
50 console.log('');
51 console.log(' # jade over stdio');
52 console.log(' $ echo \'h1 Jade!\' | jade');
53 console.log('');
54 console.log(' # foo, bar dirs rendering to /tmp');
55 console.log(' $ jade foo bar --out /tmp ');
56 console.log('');
57});
58
59program.parse(process.argv);
60
61// options given, parse them
62
63if (program.obj) {
64 if (exists(program.obj)) {
65 options = JSON.parse(fs.readFileSync(program.obj));
66 } else {
67 options = eval('(' + program.obj + ')');
68 }
69}
70
71// --filename
72
73if (program.path) options.filename = program.path;
74
75// --no-debug
76
77options.compileDebug = program.debug;
78
79// --client
80
81options.client = program.client;
82
83// --pretty
84
85options.pretty = program.pretty;
86
87// --watch
88
89options.watch = program.watch;
90
91// --name
92
93options.name = program.name;
94
95// left-over args are file paths
96
97var files = program.args;
98
99// compile files
100
101if (files.length) {
102 console.log();
103 if (options.watch) {
104 // keep watching when error occured.
105 process.on('uncaughtException', function(err) {
106 console.error(err);
107 });
108 files.forEach(renderFile);
109 monocle.watchFiles({
110 files: files,
111 listener: function(file) {
112 renderFile(file.absolutePath);
113 }
114 });
115 } else {
116 files.forEach(renderFile);
117 }
118 process.on('exit', function () {
119 console.log();
120 });
121// stdio
122} else {
123 stdin();
124}
125
126/**
127 * Compile from stdin.
128 */
129
130function stdin() {
131 var buf = '';
132 process.stdin.setEncoding('utf8');
133 process.stdin.on('data', function(chunk){ buf += chunk; });
134 process.stdin.on('end', function(){
135 var output;
136 if (options.client) {
137 output = jade.compileClient(buf, options);
138 } else {
139 var fn = jade.compile(buf, options);
140 var output = fn(options);
141 }
142 process.stdout.write(output);
143 }).resume();
144
145 process.on('SIGINT', function() {
146 process.stdout.write('\n');
147 process.stdin.emit('end');
148 process.stdout.write('\n');
149 process.exit();
150 })
151}
152
153/**
154 * Process the given path, compiling the jade files found.
155 * Always walk the subdirectories.
156 */
157
158function renderFile(path) {
159 var re = /\.jade$/;
160 fs.lstat(path, function(err, stat) {
161 if (err) throw err;
162 // Found jade file
163 if (stat.isFile() && re.test(path)) {
164 fs.readFile(path, 'utf8', function(err, str){
165 if (err) throw err;
166 options.filename = path;
167 if (program.nameAfterFile) {
168 options.name = getNameFromFileName(path);
169 }
170 var fn = options.client ? jade.compileClient(str, options) : jade.compile(str, options);
171 var extname = options.client ? '.js' : '.html';
172 path = path.replace(re, extname);
173 if (program.out) path = join(program.out, basename(path));
174 var dir = resolve(dirname(path));
175 mkdirp(dir, 0755, function(err){
176 if (err) throw err;
177 try {
178 var output = options.client ? fn : fn(options);
179 fs.writeFile(path, output, function(err){
180 if (err) throw err;
181 console.log(' \033[90mrendered \033[36m%s\033[0m', path);
182 });
183 } catch (e) {
184 if (options.watch) {
185 console.error(e.stack || e.message || e);
186 } else {
187 throw e
188 }
189 }
190 });
191 });
192 // Found directory
193 } else if (stat.isDirectory()) {
194 fs.readdir(path, function(err, files) {
195 if (err) throw err;
196 files.map(function(filename) {
197 return path + '/' + filename;
198 }).forEach(renderFile);
199 });
200 }
201 });
202}
203
204/**
205 * Get a sensible name for a template function from a file path
206 *
207 * @param {String} filename
208 * @returns {String}
209 */
210function getNameFromFileName(filename) {
211 var file = path.basename(filename, '.jade');
212 return file.toLowerCase().replace(/[^a-z0-9]+([a-z])/g, function (_, character) {
213 return character.toUpperCase();
214 }) + 'Template';
215}