1 | #!/usr/bin/env node
|
2 |
|
3 | var cli = require('cli').enable('glob', 'version'),
|
4 | dust = require('../lib/server.js'),
|
5 | fs = cli.native.fs,
|
6 | path = cli.native.path,
|
7 | eol = cli.native.os.EOL;
|
8 |
|
9 | cli.setApp('dustc', require('../package.json').version);
|
10 |
|
11 | cli.setUsage(cli.app + ' [options] [path1 [path2 path3...]]\n\n' +
|
12 | ' Compile all .dust files in a directory tree:\n ' +
|
13 | cli.app + ' --output=compiled.js tmpl/**/*.dust\n' +
|
14 | ' Compile some files to AMD modules:\n ' +
|
15 | cli.app + ' -as one.dust two.dust');
|
16 |
|
17 | cli.parse({
|
18 | name: ['n', 'name to use when rendering the template (multiple inputs automatically use their paths)', 'string'],
|
19 | output: ['o', 'concatenate all output to this file', 'path'],
|
20 | split: ['s', 'create one output file per input file instead of concatenating them to --output' ],
|
21 | pwd: [false, 'generate template names starting from this directory', 'string'],
|
22 | whitespace: ['w', 'preserve whitespace in templates', ],
|
23 | amd: ['a', 'register templates as AMD modules' ]
|
24 | });
|
25 |
|
26 | /**
|
27 | * Handle input piped via stdin
|
28 | */
|
29 | if (!cli.argc) {
|
30 | if (!cli.options.name) {
|
31 | cli.getUsage();
|
32 | }
|
33 | cli.info('No files to compile. Write template code and use ^D to exit');
|
34 | cli.withStdin(function(data) {
|
35 | output(compile(data, cli.options.name), cli.options.output);
|
36 | });
|
37 | }
|
38 |
|
39 | /**
|
40 | * Handle a list of paths passed as args
|
41 | * Each path gets globbed in case the OS doesn't support it
|
42 | */
|
43 | cli.args
|
44 | .map(function(arg) { return cli.glob.sync(arg); })
|
45 | .reduce(function(a, b) { return a.concat(b); }, [])
|
46 | .forEach(function(inputFile, index, filesToProcess) {
|
47 | read(inputFile, function(err, data) {
|
48 | if (err) {
|
49 | cli.info('Couldn\'t open ' + inputFile + ' for reading');
|
50 | return;
|
51 | }
|
52 |
|
53 | var outputFile = cli.options.output,
|
54 | templateName = path.join(path.dirname(inputFile),
|
55 | path.basename(inputFile, path.extname(inputFile))),
|
56 | compiledData;
|
57 |
|
58 | // Use the template's path as the output path if split-files is turned on
|
59 | if (cli.options.split) {
|
60 | outputFile = templateName + '.js';
|
61 | }
|
62 |
|
63 | // Allow override of template name as long as there's only one template
|
64 | if (cli.options.name && filesToProcess.length === 1) {
|
65 | templateName = cli.options.name;
|
66 | }
|
67 |
|
68 | // Optionally strip leading directories from a template name
|
69 | // For example, if --pwd=tmpl, `tmpl/foo/a` becomes `foo/a`
|
70 | if (cli.options.pwd) {
|
71 | templateName = path.relative(cli.options.pwd, templateName);
|
72 | }
|
73 |
|
74 | compiledData = compile(data, templateName);
|
75 | output(compiledData, outputFile);
|
76 | });
|
77 | });
|
78 |
|
79 | /*** helper functions ***/
|
80 |
|
81 | function read(filename, cb) {
|
82 | var data = '',
|
83 | file = fs.createReadStream(filename);
|
84 |
|
85 | file.on('error', cb);
|
86 | file.on('data', function(chunk) {
|
87 | data += chunk;
|
88 | });
|
89 | file.on('end', function() {
|
90 | cb(null, data);
|
91 | });
|
92 | }
|
93 |
|
94 | function compile(data, name) {
|
95 | var compiled;
|
96 |
|
97 | dust.config.whitespace = (cli.options.whitespace === true);
|
98 | dust.config.amd = (cli.options.amd === true);
|
99 |
|
100 | try {
|
101 | compiled = dust.compile(data, name);
|
102 | } catch(e) {
|
103 | return cli.fatal('[' + name + '] ' + e);
|
104 | }
|
105 | return compiled;
|
106 | }
|
107 |
|
108 | var streams = {};
|
109 | function output(data, file) {
|
110 | var output_stream;
|
111 | try {
|
112 | if (file) {
|
113 | output_stream = streams[file] ? streams[file]
|
114 | : streams[file] = cli.native.fs.createWriteStream(file);
|
115 | } else {
|
116 | output_stream = process.stdout;
|
117 | }
|
118 | output_stream.write(data + eol);
|
119 | } catch (e) {
|
120 | cli.fatal('Could not write to output stream');
|
121 | }
|
122 | }
|