|  | /* eslint-disable no-console */ | 
|  | import Async from 'neo-async'; | 
|  | import fs from 'fs'; | 
|  | import * as Handlebars from './handlebars'; | 
|  | import {basename} from 'path'; | 
|  | import {SourceMapConsumer, SourceNode} from 'source-map'; | 
|  |  | 
|  |  | 
|  | module.exports.loadTemplates = function(opts, callback) { | 
|  | loadStrings(opts, function(err, strings) { | 
|  | if (err) { | 
|  | callback(err); | 
|  | } else { | 
|  | loadFiles(opts, function(err, files) { | 
|  | if (err) { | 
|  | callback(err); | 
|  | } else { | 
|  | opts.templates = strings.concat(files); | 
|  | callback(undefined, opts); | 
|  | } | 
|  | }); | 
|  | } | 
|  | }); | 
|  | }; | 
|  |  | 
|  | function loadStrings(opts, callback) { | 
|  | let strings = arrayCast(opts.string), | 
|  | names = arrayCast(opts.name); | 
|  |  | 
|  | if (names.length !== strings.length | 
|  | && strings.length > 1) { | 
|  | return callback(new Handlebars.Exception('Number of names did not match the number of string inputs')); | 
|  | } | 
|  |  | 
|  | Async.map(strings, function(string, callback) { | 
|  | if (string !== '-') { | 
|  | callback(undefined, string); | 
|  | } else { | 
|  | // Load from stdin | 
|  | let buffer = ''; | 
|  | process.stdin.setEncoding('utf8'); | 
|  |  | 
|  | process.stdin.on('data', function(chunk) { | 
|  | buffer += chunk; | 
|  | }); | 
|  | process.stdin.on('end', function() { | 
|  | callback(undefined, buffer); | 
|  | }); | 
|  | } | 
|  | }, | 
|  | function(err, strings) { | 
|  | strings = strings.map((string, index) => ({ | 
|  | name: names[index], | 
|  | path: names[index], | 
|  | source: string | 
|  | })); | 
|  | callback(err, strings); | 
|  | }); | 
|  | } | 
|  |  | 
|  | function loadFiles(opts, callback) { | 
|  | // Build file extension pattern | 
|  | let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-[\]]/g, function(arg) { return '\\' + arg; }); | 
|  | extension = new RegExp('\\.' + extension + '$'); | 
|  |  | 
|  | let ret = [], | 
|  | queue = (opts.files || []).map((template) => ({template, root: opts.root})); | 
|  | Async.whilst(() => queue.length, function(callback) { | 
|  | let {template: path, root} = queue.shift(); | 
|  |  | 
|  | fs.stat(path, function(err, stat) { | 
|  | if (err) { | 
|  | return callback(new Handlebars.Exception(`Unable to open template file "${path}"`)); | 
|  | } | 
|  |  | 
|  | if (stat.isDirectory()) { | 
|  | opts.hasDirectory = true; | 
|  |  | 
|  | fs.readdir(path, function(err, children) { | 
|  | /* istanbul ignore next : Race condition that being too lazy to test */ | 
|  | if (err) { | 
|  | return callback(err); | 
|  | } | 
|  | children.forEach(function(file) { | 
|  | let childPath = path + '/' + file; | 
|  |  | 
|  | if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) { | 
|  | queue.push({template: childPath, root: root || path}); | 
|  | } | 
|  | }); | 
|  |  | 
|  | callback(); | 
|  | }); | 
|  | } else { | 
|  | fs.readFile(path, 'utf8', function(err, data) { | 
|  | /* istanbul ignore next : Race condition that being too lazy to test */ | 
|  | if (err) { | 
|  | return callback(err); | 
|  | } | 
|  |  | 
|  | if (opts.bom && data.indexOf('\uFEFF') === 0) { | 
|  | data = data.substring(1); | 
|  | } | 
|  |  | 
|  | // Clean the template name | 
|  | let name = path; | 
|  | if (!root) { | 
|  | name = basename(name); | 
|  | } else if (name.indexOf(root) === 0) { | 
|  | name = name.substring(root.length + 1); | 
|  | } | 
|  | name = name.replace(extension, ''); | 
|  |  | 
|  | ret.push({ | 
|  | path: path, | 
|  | name: name, | 
|  | source: data | 
|  | }); | 
|  |  | 
|  | callback(); | 
|  | }); | 
|  | } | 
|  | }); | 
|  | }, | 
|  | function(err) { | 
|  | if (err) { | 
|  | callback(err); | 
|  | } else { | 
|  | callback(undefined, ret); | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | module.exports.cli = function(opts) { | 
|  | if (opts.version) { | 
|  | console.log(Handlebars.VERSION); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!opts.templates.length && !opts.hasDirectory) { | 
|  | throw new Handlebars.Exception('Must define at least one template or directory.'); | 
|  | } | 
|  |  | 
|  | if (opts.simple && opts.min) { | 
|  | throw new Handlebars.Exception('Unable to minimize simple output'); | 
|  | } | 
|  |  | 
|  | const multiple = opts.templates.length !== 1 || opts.hasDirectory; | 
|  | if (opts.simple && multiple) { | 
|  | throw new Handlebars.Exception('Unable to output multiple templates in simple mode'); | 
|  | } | 
|  |  | 
|  | // Force simple mode if we have only one template and it's unnamed. | 
|  | if (!opts.amd && !opts.commonjs && opts.templates.length === 1 | 
|  | && !opts.templates[0].name) { | 
|  | opts.simple = true; | 
|  | } | 
|  |  | 
|  | // Convert the known list into a hash | 
|  | let known = {}; | 
|  | if (opts.known && !Array.isArray(opts.known)) { | 
|  | opts.known = [opts.known]; | 
|  | } | 
|  | if (opts.known) { | 
|  | for (let i = 0, len = opts.known.length; i < len; i++) { | 
|  | known[opts.known[i]] = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | const objectName = opts.partial ? 'Handlebars.partials' : 'templates'; | 
|  |  | 
|  | let output = new SourceNode(); | 
|  | if (!opts.simple) { | 
|  | if (opts.amd) { | 
|  | output.add('define([\'' + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n  Handlebars = Handlebars["default"];'); | 
|  | } else if (opts.commonjs) { | 
|  | output.add('var Handlebars = require("' + opts.commonjs + '");'); | 
|  | } else { | 
|  | output.add('(function() {\n'); | 
|  | } | 
|  | output.add('  var template = Handlebars.template, templates = '); | 
|  | if (opts.namespace) { | 
|  | output.add(opts.namespace); | 
|  | output.add(' = '); | 
|  | output.add(opts.namespace); | 
|  | output.add(' || '); | 
|  | } | 
|  | output.add('{};\n'); | 
|  | } | 
|  |  | 
|  | opts.templates.forEach(function(template) { | 
|  | let options = { | 
|  | knownHelpers: known, | 
|  | knownHelpersOnly: opts.o | 
|  | }; | 
|  |  | 
|  | if (opts.map) { | 
|  | options.srcName = template.path; | 
|  | } | 
|  | if (opts.data) { | 
|  | options.data = true; | 
|  | } | 
|  |  | 
|  | let precompiled = Handlebars.precompile(template.source, options); | 
|  |  | 
|  | // If we are generating a source map, we have to reconstruct the SourceNode object | 
|  | if (opts.map) { | 
|  | let consumer = new SourceMapConsumer(precompiled.map); | 
|  | precompiled = SourceNode.fromStringWithSourceMap(precompiled.code, consumer); | 
|  | } | 
|  |  | 
|  | if (opts.simple) { | 
|  | output.add([precompiled, '\n']); | 
|  | } else { | 
|  | if (!template.name) { | 
|  | throw new Handlebars.Exception('Name missing for template'); | 
|  | } | 
|  |  | 
|  | if (opts.amd && !multiple) { | 
|  | output.add('return '); | 
|  | } | 
|  | output.add([objectName, '[\'', template.name, '\'] = template(', precompiled, ');\n']); | 
|  | } | 
|  | }); | 
|  |  | 
|  | // Output the content | 
|  | if (!opts.simple) { | 
|  | if (opts.amd) { | 
|  | if (multiple) { | 
|  | output.add(['return ', objectName, ';\n']); | 
|  | } | 
|  | output.add('});'); | 
|  | } else if (!opts.commonjs) { | 
|  | output.add('})();'); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (opts.map) { | 
|  | output.add('\n//# sourceMappingURL=' + opts.map + '\n'); | 
|  | } | 
|  |  | 
|  | output = output.toStringWithSourceMap(); | 
|  | output.map = output.map + ''; | 
|  |  | 
|  | if (opts.min) { | 
|  | output = minify(output, opts.map); | 
|  | } | 
|  |  | 
|  | if (opts.map) { | 
|  | fs.writeFileSync(opts.map, output.map, 'utf8'); | 
|  | } | 
|  | output = output.code; | 
|  |  | 
|  | if (opts.output) { | 
|  | fs.writeFileSync(opts.output, output, 'utf8'); | 
|  | } else { | 
|  | console.log(output); | 
|  | } | 
|  | }; | 
|  |  | 
|  | function arrayCast(value) { | 
|  | value = value != null ? value : []; | 
|  | if (!Array.isArray(value)) { | 
|  | value = [value]; | 
|  | } | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Run uglify to minify the compiled template, if uglify exists in the dependencies. | 
|  | * | 
|  | * We are using `require` instead of `import` here, because es6-modules do not allow | 
|  | * dynamic imports and uglify-js is an optional dependency. Since we are inside NodeJS here, this | 
|  | * should not be a problem. | 
|  | * | 
|  | * @param {string} output the compiled template | 
|  | * @param {string} sourceMapFile the file to write the source map to. | 
|  | */ | 
|  | function minify(output, sourceMapFile) { | 
|  | try { | 
|  | // Try to resolve uglify-js in order to see if it does exist | 
|  | require.resolve('uglify-js'); | 
|  | } catch (e) { | 
|  | if (e.code !== 'MODULE_NOT_FOUND') { | 
|  | // Something else seems to be wrong | 
|  | throw e; | 
|  | } | 
|  | // it does not exist! | 
|  | console.error('Code minimization is disabled due to missing uglify-js dependency'); | 
|  | return output; | 
|  | } | 
|  | return require('uglify-js').minify(output.code, { | 
|  | sourceMap: { | 
|  | content: output.map, | 
|  | url: sourceMapFile | 
|  | } | 
|  | }); | 
|  | } |