summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkpdecker <kpdecker@gmail.com>2015-08-04 10:55:51 -0500
committerkpdecker <kpdecker@gmail.com>2015-08-04 10:55:51 -0500
commit00f74420f949a42bedd99af022c20cdc5027228d (patch)
tree633639cb0fc33b0ac7cafed8d5a572c9afab21c3
parenta62cbad95acdf544dc9daae9834588453ee1f835 (diff)
downloadhandlebars.js-00f74420f949a42bedd99af022c20cdc5027228d.zip
handlebars.js-00f74420f949a42bedd99af022c20cdc5027228d.tar.gz
handlebars.js-00f74420f949a42bedd99af022c20cdc5027228d.tar.bz2
Convert precompiler template loading to async
-rwxr-xr-xbin/handlebars18
-rw-r--r--lib/precompiler.js105
-rw-r--r--package.json1
-rw-r--r--spec/precompiler.js64
4 files changed, 113 insertions, 75 deletions
diff --git a/bin/handlebars b/bin/handlebars
index 10cc6c5..bfe6680 100755
--- a/bin/handlebars
+++ b/bin/handlebars
@@ -100,14 +100,18 @@ var optimist = require('optimist')
var argv = optimist.argv;
-argv.templates = argv._;
+argv.files = argv._;
delete argv._;
var Precompiler = require('../dist/cjs/precompiler');
-Precompiler.loadTemplates(argv);
+Precompiler.loadTemplates(argv, function(err, opts) {
+ if (err) {
+ throw err;
+ }
-if (argv.help || (!argv.templates.length && !argv.version)) {
- optimist.showHelp();
-} else {
- Precompiler.cli(argv);
-}
+ if (opts.help || (!opts.templates.length && !opts.version)) {
+ optimist.showHelp();
+ } else {
+ Precompiler.cli(opts);
+ }
+});
diff --git a/lib/precompiler.js b/lib/precompiler.js
index 2809b1b..8a2019d 100644
--- a/lib/precompiler.js
+++ b/lib/precompiler.js
@@ -1,62 +1,85 @@
/*eslint-disable no-console */
+import Async from 'async';
import fs from 'fs';
import * as Handlebars from './handlebars';
import {basename} from 'path';
import {SourceMapConsumer, SourceNode} from 'source-map';
import uglify from 'uglify-js';
-module.exports.loadTemplates = function(opts) {
+module.exports.loadTemplates = function(opts, callback) {
// Build file extension pattern
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; });
extension = new RegExp('\\.' + extension + '$');
- let ret = [];
- function processTemplate(template, root) {
- let path = template,
- stat;
- try {
- stat = fs.statSync(template);
- } catch (err) {
- throw new Handlebars.Exception(`Unable to open template file "${template}"`);
- }
-
- if (stat.isDirectory()) {
- opts.hasDirectory = true;
-
- fs.readdirSync(template).map(function(file) {
- let childPath = template + '/' + file;
-
- if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
- processTemplate(childPath, root || template);
- }
- });
- } else {
- let data = fs.readFileSync(path, 'utf8');
+ let ret = [],
+ queue = opts.files.map((template) => ({template, root: opts.root}));
+ Async.whilst(() => queue.length, function(callback) {
+ let {template: path, root} = queue.shift();
- if (opts.bom && data.indexOf('\uFEFF') === 0) {
- data = data.substring(1);
+ fs.stat(path, function(err, stat) {
+ if (err) {
+ return callback(new Handlebars.Exception(`Unable to open template file "${path}"`));
}
- // Clean the template name
- if (!root) {
- template = basename(template);
- } else if (template.indexOf(root) === 0) {
- template = template.substring(root.length + 1);
+ 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();
+ });
}
- template = template.replace(extension, '');
+ });
+ },
+ function(err) {
+ if (err) {
+ callback(err);
+ } else {
+ opts.templates = ret;
- ret.push({
- path: path,
- name: template,
- source: data
- });
+ callback(undefined, opts);
}
- }
- opts.templates.forEach(function(template) {
- processTemplate(template, opts.root);
});
- opts.templates = ret;
-};
+}
module.exports.cli = function(opts) {
if (opts.version) {
diff --git a/package.json b/package.json
index 83f428d..b1cafee 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"node": ">=0.4.7"
},
"dependencies": {
+ "async": "^1.4.0",
"optimist": "^0.6.1",
"source-map": "^0.1.40"
},
diff --git a/spec/precompiler.js b/spec/precompiler.js
index f9cc8fd..72a7ce6 100644
--- a/spec/precompiler.js
+++ b/spec/precompiler.js
@@ -153,38 +153,48 @@ describe('precompiler', function() {
});
describe('#loadTemplates', function() {
- it('should throw on missing template', function() {
- shouldThrow(function() {
- Precompiler.loadTemplates({templates: ['foo']});
- }, Handlebars.Exception, 'Unable to open template file "foo"');
+ it('should throw on missing template', function(done) {
+ Precompiler.loadTemplates({files: ['foo']}, function(err) {
+ equal(err.message, 'Unable to open template file "foo"');
+ done();
+ });
});
- it('should enumerate directories by extension', function() {
- var opts = {templates: [__dirname + '/artifacts'], extension: 'hbs'};
- Precompiler.loadTemplates(opts);
- equal(opts.templates.length, 1);
- equal(opts.templates[0].name, 'example_2');
-
- opts = {templates: [__dirname + '/artifacts'], extension: 'handlebars'};
- Precompiler.loadTemplates(opts);
- equal(opts.templates.length, 3);
- equal(opts.templates[0].name, 'bom');
- equal(opts.templates[1].name, 'empty');
- equal(opts.templates[2].name, 'example_1');
+ it('should enumerate directories by extension', function(done) {
+ Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hbs'}, function(err, opts) {
+ equal(opts.templates.length, 1);
+ equal(opts.templates[0].name, 'example_2');
+ done(err);
+ });
});
- it('should handle regular expression characters in extensions', function() {
- Precompiler.loadTemplates({templates: [__dirname + '/artifacts'], extension: 'hb(s'});
- // Success is not throwing
+ it('should enumerate all templates by extension', function(done) {
+ Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'handlebars'}, function(err, opts) {
+ equal(opts.templates.length, 3);
+ equal(opts.templates[0].name, 'bom');
+ equal(opts.templates[1].name, 'empty');
+ equal(opts.templates[2].name, 'example_1');
+ done(err);
+ });
});
- it('should handle BOM', function() {
- var opts = {templates: [__dirname + '/artifacts/bom.handlebars'], extension: 'handlebars', bom: true};
- Precompiler.loadTemplates(opts);
- equal(opts.templates[0].source, 'a');
+ it('should handle regular expression characters in extensions', function(done) {
+ Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hb(s'}, function(err) {
+ // Success is not throwing
+ done(err);
+ });
+ });
+ it('should handle BOM', function(done) {
+ var opts = {files: [__dirname + '/artifacts/bom.handlebars'], extension: 'handlebars', bom: true};
+ Precompiler.loadTemplates(opts, function(err, opts) {
+ equal(opts.templates[0].source, 'a');
+ done(err);
+ });
});
- it('should handle different root', function() {
- var opts = {templates: [__dirname + '/artifacts/empty.handlebars'], simple: true, root: 'foo/'};
- Precompiler.loadTemplates(opts);
- equal(opts.templates[0].name, __dirname + '/artifacts/empty');
+ it('should handle different root', function(done) {
+ var opts = {files: [__dirname + '/artifacts/empty.handlebars'], simple: true, root: 'foo/'};
+ Precompiler.loadTemplates(opts, function(err, opts) {
+ equal(opts.templates[0].name, __dirname + '/artifacts/empty');
+ done(err);
+ });
});
});
});