Convert precompiler template loading to async

This commit is contained in:
kpdecker
2015-08-04 10:55:51 -05:00
parent a62cbad95a
commit 00f74420f9
4 changed files with 113 additions and 75 deletions
+11 -7
View File
@@ -100,14 +100,18 @@ var optimist = require('optimist')
var argv = optimist.argv; var argv = optimist.argv;
argv.templates = argv._; argv.files = argv._;
delete argv._; delete argv._;
var Precompiler = require('../dist/cjs/precompiler'); 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)) { if (opts.help || (!opts.templates.length && !opts.version)) {
optimist.showHelp(); optimist.showHelp();
} else { } else {
Precompiler.cli(argv); Precompiler.cli(opts);
} }
});
+64 -41
View File
@@ -1,62 +1,85 @@
/*eslint-disable no-console */ /*eslint-disable no-console */
import Async from 'async';
import fs from 'fs'; import fs from 'fs';
import * as Handlebars from './handlebars'; import * as Handlebars from './handlebars';
import {basename} from 'path'; import {basename} from 'path';
import {SourceMapConsumer, SourceNode} from 'source-map'; import {SourceMapConsumer, SourceNode} from 'source-map';
import uglify from 'uglify-js'; import uglify from 'uglify-js';
module.exports.loadTemplates = function(opts) { module.exports.loadTemplates = function(opts, callback) {
// Build file extension pattern // Build file extension pattern
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; }); let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; });
extension = new RegExp('\\.' + extension + '$'); extension = new RegExp('\\.' + extension + '$');
let ret = []; let ret = [],
function processTemplate(template, root) { queue = opts.files.map((template) => ({template, root: opts.root}));
let path = template, Async.whilst(() => queue.length, function(callback) {
stat; let {template: path, root} = queue.shift();
try {
stat = fs.statSync(template);
} catch (err) {
throw new Handlebars.Exception(`Unable to open template file "${template}"`);
}
if (stat.isDirectory()) { fs.stat(path, function(err, stat) {
opts.hasDirectory = true; if (err) {
return callback(new Handlebars.Exception(`Unable to open template file "${path}"`));
}
fs.readdirSync(template).map(function(file) { if (stat.isDirectory()) {
let childPath = template + '/' + file; opts.hasDirectory = true;
if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) { fs.readdir(path, function(err, children) {
processTemplate(childPath, root || template); /* 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 { } else {
let data = fs.readFileSync(path, 'utf8'); opts.templates = ret;
if (opts.bom && data.indexOf('\uFEFF') === 0) { callback(undefined, opts);
data = data.substring(1);
}
// Clean the template name
if (!root) {
template = basename(template);
} else if (template.indexOf(root) === 0) {
template = template.substring(root.length + 1);
}
template = template.replace(extension, '');
ret.push({
path: path,
name: template,
source: data
});
} }
}
opts.templates.forEach(function(template) {
processTemplate(template, opts.root);
}); });
opts.templates = ret; }
};
module.exports.cli = function(opts) { module.exports.cli = function(opts) {
if (opts.version) { if (opts.version) {
+1
View File
@@ -21,6 +21,7 @@
"node": ">=0.4.7" "node": ">=0.4.7"
}, },
"dependencies": { "dependencies": {
"async": "^1.4.0",
"optimist": "^0.6.1", "optimist": "^0.6.1",
"source-map": "^0.1.40" "source-map": "^0.1.40"
}, },
+37 -27
View File
@@ -153,38 +153,48 @@ describe('precompiler', function() {
}); });
describe('#loadTemplates', function() { describe('#loadTemplates', function() {
it('should throw on missing template', function() { it('should throw on missing template', function(done) {
shouldThrow(function() { Precompiler.loadTemplates({files: ['foo']}, function(err) {
Precompiler.loadTemplates({templates: ['foo']}); equal(err.message, 'Unable to open template file "foo"');
}, Handlebars.Exception, 'Unable to open template file "foo"'); done();
});
}); });
it('should enumerate directories by extension', function() { it('should enumerate directories by extension', function(done) {
var opts = {templates: [__dirname + '/artifacts'], extension: 'hbs'}; Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hbs'}, function(err, opts) {
Precompiler.loadTemplates(opts); equal(opts.templates.length, 1);
equal(opts.templates.length, 1); equal(opts.templates[0].name, 'example_2');
equal(opts.templates[0].name, 'example_2'); done(err);
});
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 handle regular expression characters in extensions', function() { it('should enumerate all templates by extension', function(done) {
Precompiler.loadTemplates({templates: [__dirname + '/artifacts'], extension: 'hb(s'}); Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'handlebars'}, function(err, opts) {
// Success is not throwing 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() { it('should handle regular expression characters in extensions', function(done) {
var opts = {templates: [__dirname + '/artifacts/bom.handlebars'], extension: 'handlebars', bom: true}; Precompiler.loadTemplates({files: [__dirname + '/artifacts'], extension: 'hb(s'}, function(err) {
Precompiler.loadTemplates(opts); // Success is not throwing
equal(opts.templates[0].source, 'a'); 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() { it('should handle different root', function(done) {
var opts = {templates: [__dirname + '/artifacts/empty.handlebars'], simple: true, root: 'foo/'}; var opts = {files: [__dirname + '/artifacts/empty.handlebars'], simple: true, root: 'foo/'};
Precompiler.loadTemplates(opts); Precompiler.loadTemplates(opts, function(err, opts) {
equal(opts.templates[0].name, __dirname + '/artifacts/empty'); equal(opts.templates[0].name, __dirname + '/artifacts/empty');
done(err);
});
}); });
}); });
}); });