1 | #!/usr/bin/env node
|
2 |
|
3 | var fs = require('fs')
|
4 | ,path = require('path')
|
5 | ,uglify = require('uglify-js')
|
6 | ,cli = require('commander')
|
7 | ,vash = require('../index')
|
8 |
|
9 | function prefix(tplStr, options){
|
10 |
|
11 | if( options.targetNamespace ){
|
12 |
|
13 | tplStr = options.targetNamespace
|
14 | + '["'
|
15 | + ( options.propertyName || options.file.replace(/\/|\\/g, options.separator) )
|
16 | + '"]=' + tplStr;
|
17 |
|
18 | // ensure the simple namespace exists
|
19 | var accum = '';
|
20 | options.targetNamespace.split('.').reduce(function(all, prop, i){
|
21 |
|
22 | accum += all + prop + ' = ' + all + prop + ' || {};\n';
|
23 | all += prop;
|
24 | return all + '.';
|
25 |
|
26 | }, '')
|
27 |
|
28 | tplStr = accum + tplStr;
|
29 | }
|
30 |
|
31 | return tplStr;
|
32 | }
|
33 |
|
34 | function ugly(tplStr, options){
|
35 |
|
36 | var ast
|
37 | ,jsp = uglify.parser
|
38 | ,pro = uglify.uglify;
|
39 |
|
40 | if( options.uglify ){
|
41 | ast = jsp.parse(tplStr);
|
42 | ast = pro.ast_mangle(ast);
|
43 | ast = pro.ast_squeeze(ast);
|
44 | tplStr = pro.gen_code(ast);
|
45 | }
|
46 |
|
47 | return tplStr;
|
48 | }
|
49 |
|
50 | function render(tpl, options){
|
51 | var model = {};
|
52 |
|
53 | if( options.render ){
|
54 |
|
55 | try {
|
56 | model = JSON.parse( options.render );
|
57 | } catch(e) {
|
58 | try {
|
59 | model = JSON.parse(fs.readFileSync(options.render));
|
60 | } catch(e) {
|
61 |
|
62 | }
|
63 | }
|
64 |
|
65 | return tpl(model);
|
66 | }
|
67 |
|
68 | return tpl;
|
69 | }
|
70 |
|
71 | function stdin(options){
|
72 | var buffer = ''
|
73 | process.stdin.resume();
|
74 | process.stdin.setEncoding('utf8');
|
75 |
|
76 | process.stdin.on('data', function(chunk){
|
77 | buffer += chunk;
|
78 | })
|
79 |
|
80 | process.stdin.on('end', function(){
|
81 | var tpl = vash[options.helper ? 'compileHelper' : 'compile'](buffer, options.vopts);
|
82 |
|
83 | if( options.render ){
|
84 | tpl = render(tpl, options);
|
85 | } else {
|
86 | tpl = prefix( options.autolink
|
87 | ? tpl.toClientString()
|
88 | : tpl.toString(), options);
|
89 | tpl = ugly(tpl, options);
|
90 | }
|
91 |
|
92 | process.stdout.write(tpl);
|
93 | })
|
94 | }
|
95 |
|
96 | function file(filepath, options){
|
97 | var contents = fs.readFileSync( filepath, 'utf8' )
|
98 | ,tpl = vash[options.helper ? 'compileHelper' : 'compile'](contents, options.vopts)
|
99 | ,outpath = path.join(
|
100 | options.out
|
101 | ,path.join(
|
102 | path.dirname(filepath)
|
103 | ,path.basename(filepath) + '.js'
|
104 | ).replace(/\/|\\/g, options.separator)
|
105 | )
|
106 |
|
107 | if( options.render ){
|
108 | tpl = render(tpl, options);
|
109 | } else {
|
110 | tpl = prefix( options.autolink
|
111 | ? tpl.toClientString()
|
112 | : tpl.toString(), options);
|
113 | tpl = ugly(tpl, options);
|
114 | }
|
115 |
|
116 | if( options.out ) {
|
117 | fs.writeFile( outpath, tpl.toString(), 'utf8', function(err){
|
118 | if(err){ process.stderr.write( err ) }
|
119 | } )
|
120 | } else {
|
121 | process.stdout.write(tpl.toString());
|
122 | }
|
123 | }
|
124 |
|
125 | // TODO: if passed a directory, recursively traverse
|
126 |
|
127 | cli.on('--help', function(){
|
128 | console.log(' Examples:');
|
129 | console.log('');
|
130 | console.log(' $ echo \'<p>Hello!</p>\' | vash --json \'{ "debug": false }\' -t myapp.tplcache -p hello');
|
131 | console.log('');
|
132 | console.log(' > myapp = myapp || {};');
|
133 | console.log(' > myapp.tplcache = myapp.tplcache || {};');
|
134 | console.log(' > myapp.tplcache["hello"]=vash.link( function anonymous(model,html) {');
|
135 | console.log(' > html.buffer.push(\'<p></p>\\n\'); ');
|
136 | console.log(' > return html.buffer.flush(); ');
|
137 | console.log(' > } )');
|
138 | console.log('');
|
139 | console.log(' Remember to include vash-runtime.js if precompiling for client-side usage.')
|
140 | console.log('');
|
141 | });
|
142 |
|
143 | cli
|
144 | .option('-t, --target-namespace <namespace>', 'Assign template to a <namespace>. Recommended is `vash.helpers.tplcache` for view engine compatibility')
|
145 | .option('-p, --property-name [name]', 'Assign template to property named <name>. Defaults to filename, and requires --target-namespace.')
|
146 | .option('-f, --file <file>', 'Compile the template in <file>')
|
147 | .option('-j, --json <json>', 'Pass options to the Vash compiler. See docs for valid options.')
|
148 | .option('-o, --out <path>', 'Write template into <path> directory')
|
149 | .option('-u, --uglify', 'Uglify the template, safely')
|
150 | .option('-a, --no-autolink', 'Do not wrap each template in `vash.link`.')
|
151 | //.option('-d, --prepend-runtime', 'Include the required Vash runtime')
|
152 | .option('-r, --render [json]', 'Render the template using <json> as the model. If <json> is not valid json, assume a filename and load those contents as json.')
|
153 | .option('-s, --separator [separator]', 'Templates are auto-named by concatenating the file path with [separator]', '/')
|
154 | .option('--helper', 'Assume the input is a to-be-compiled helper')
|
155 | .option('--helpers <file>', 'Execute these compiled helpers')
|
156 | .parse(process.argv)
|
157 |
|
158 | if( cli.json ){
|
159 | cli.vopts = JSON.parse(cli.json);
|
160 | }
|
161 |
|
162 | // helpers via .toClientString, therefore vash.link
|
163 | if( cli.helpers ){
|
164 | eval(fs.readFileSync(cli.helpers, 'utf8'));
|
165 | }
|
166 |
|
167 | if(cli.file){
|
168 | cli.file = path.normalize( cli.file )
|
169 | // assume file input
|
170 | file( cli.file, cli )
|
171 | } else {
|
172 | // assume stdin
|
173 | stdin( cli );
|
174 | }
|
175 |
|