first commit

This commit is contained in:
Sebastian McKenzie
2014-09-28 23:39:22 +10:00
commit c97696c224
167 changed files with 2007 additions and 0 deletions

19
lib/6to5/browserify.js Normal file
View File

@@ -0,0 +1,19 @@
var transform = require("./transform");
var through = require("through");
module.exports = function (filename) {
var data = "";
var write = function (buf) {
data += buf;
};
var end = function () {
var out = transform(data, { filename: filename });
stream.queue(out);
stream.queue(null);
};
var stream = through(write, end);
return stream;
};

66
lib/6to5/middleware.js Normal file
View File

@@ -0,0 +1,66 @@
var util = require("./util");
var path = require("path");
var api = require("./node");
var fs = require("fs");
var _ = require("lodash");
module.exports = function (opts) {
opts = _.defaults(opts || {}, {
src: "assets",
dest: "cache"
});
var cache = {};
return function (req, res, next) {
var url = req.url;
if (!util.canCompile(url)) return next();
var dest = path.join(opts.dest, url);
var src = path.join(opts.src, url);
var write = function (transformed) {
fs.writeFile(dest, transformed, function (err) {
if (err) {
next(err);
} else {
cache[url] = Date.now();
next();
}
});
};
var compile = function () {
var transformOpts = _.clone(opts.transform || {});
api.transformFile(opts.dest, transformOpts, function (err, transformed) {
if (err) return next(err);
write(transformed);
});
};
var destExists = function () {
fs.stat(dest, function (err, stat) {
if (err) return next(err);
if (cache[url] < +stat.mtime) {
compile();
} else {
next();
}
});
};
fs.exists(src, function (exists) {
if (!exists) return next();
fs.exists(dest, function (exists) {
if (exists && cache[dest]) {
destExists();
} else {
compile();
}
});
});
};
};

45
lib/6to5/node.js Normal file
View File

@@ -0,0 +1,45 @@
var transform = require("./transform");
var fs = require("fs");
var _ = require("lodash");
exports.browserify = require("./browserify");
exports.middleware = require("./middleware");
exports.register = function () {
require.extensions[".js"] = function (m, filename) {
m._compile(exports.transformFileSync(filename, {
sourceMap: true
}), filename);
};
};
exports.transform = transform;
exports.transformFile = function (filename, opts, callback) {
if (_.isFunction(opts)) {
callback = opts;
opts = {};
}
opts.filename = filename;
fs.readFile(filename, function (err, raw) {
if (err) return callback(err);
var code;
try {
code = transform(raw, opts);
} catch (err) {
return callback(err);
}
callback(null, code);
});
};
exports.transformFileSync = function (filename, opts) {
opts = opts || {};
opts.filename = filename;
return transform(fs.readFileSync(filename), opts);
};

View File

@@ -0,0 +1 @@
var VARIABLE_NAME = Array.prototype.slice.call(arguments, SLICE_ARG);

View File

@@ -0,0 +1 @@
var VARIABLE_NAME = Array.prototype.slice.call(arguments);

View File

@@ -0,0 +1 @@
Array.prototype.slice.call(arguments);

View File

@@ -0,0 +1 @@
[].concat(ARGUMENT);

View File

@@ -0,0 +1 @@
CLASS_NAME.prototype.METHOD_NAME = FUNCTION;

View File

@@ -0,0 +1,7 @@
var CLASS_NAME = (function () {
function CLASS_NAME() {
}
return CLASS_NAME;
})();

View File

@@ -0,0 +1,5 @@
Object.defineProperty(exports, STRING_KEY, {
get: function () {
return KEY;
}
});

View File

@@ -0,0 +1 @@
exports.KEY = VALUE;

View File

@@ -0,0 +1 @@
exports = module.exports = VALUE;

View File

@@ -0,0 +1 @@
exports.VARIABLE_NAME = require(MODULE_NAME).KEY;

View File

@@ -0,0 +1,5 @@
(function (obj) {
for (var i in obj) {
exports[i] = obj[i];
}
}(require(MODULE_NAME)));

View File

@@ -0,0 +1 @@
FUNCTION.bind(this);

View File

@@ -0,0 +1 @@
FUNCTION.call(this);

View File

@@ -0,0 +1 @@
FUNCTION();

View File

@@ -0,0 +1 @@
if (VARIABLE === undefined) VARIABLE = DEFAULT;

View File

@@ -0,0 +1,8 @@
CLASS_NAME.prototype = Object.create(SUPER_NAME.prototype, {
constructor: {
value: CLASS_NAME,
enumerable: false,
writable: true,
configurable: true
}
});

View File

@@ -0,0 +1,4 @@
(function (obj) {
CONTENT;
return obj;
})(OBJECT);

View File

@@ -0,0 +1 @@
Object.defineProperties(OBJECT, PROPS);

View File

@@ -0,0 +1 @@
CLASS_NAME.prototype

View File

@@ -0,0 +1 @@
var VARIABLE_NAME = require(MODULE_NAME).KEY;

View File

@@ -0,0 +1 @@
var VARIABLE_NAME = require(MODULE_NAME);

107
lib/6to5/transform.js Normal file
View File

@@ -0,0 +1,107 @@
var escodegen = require("escodegen");
var traverse = require("./traverse");
var assert = require("assert");
var util = require("./util");
var _ = require("lodash");
var transform = module.exports = function (code, opts) {
opts = opts || {};
_.defaults(opts, {
blacklist: [],
whitelist: [],
sourceMap: false,
filename: "unknown",
format: {}
});
try {
var tree = util.parse(code);
} catch (err) {
err.message = opts.filename + ": " + err.message;
throw err;
}
traverse.replace(tree, function (node) {
if (node.type === "EmptyStatement") {
return traverse.Delete;
}
});
_.each(transform.transformers, function (transformer, name) {
var blacklist = opts.blacklist;
if (blacklist.length && _.contains(blacklist, name)) return;
var whitelist = opts.whitelist;
if (whitelist.length && !_.contains(whitelist, name)) return;
transform._runTransformer(transformer, tree, opts);
});
var genOpts = {
comment: true,
format: _.merge(opts.format, {
indent: {
style: " "
}
})
};
if (opts.sourceMap) {
genOpts.sourceMap = true;
genOpts.sourceContent = code;
genOpts.sourceMapWithCode = true;
}
var result = escodegen.generate(tree, genOpts);
if (genOpts.sourceMapWithCode) {
return result.code + "\n" + util.sourceMapToComment(result.map) + "\n";
} else {
return result + "\n";
}
};
transform._runTransformer = function (transformer, tree, opts) {
if (transformer.Program) transformer.Program(tree, opts);
traverse.replace(tree, function (node, parent) {
var fn = transformer[node.type] || transformer.all;
if (!fn) return;
return fn(node, parent, opts);
});
};
transform.test = function (actual, expect, opts) {
expect = [].concat(expect).join("\n");
actual = [].concat(actual).join("\n");
opts = opts || {};
_.defaults(opts, { filename: "test" });
actual = util.parse(transform(actual, opts));
expect = util.parse(expect);
try {
assert.deepEqual(actual, expect);
} catch (err) {
actual = escodegen.generate(actual);
expect = escodegen.generate(expect);
assert.equal(actual, expect);
}
};
transform.transformers = {
arrowFunctions: require("./transformers/arrow-functions"),
classes: require("./transformers/classes"),
spread: require("./transformers/spread"),
templateLiterals: require("./transformers/template-literals"),
propertyMethodAssignment: require("./transformers/property-method-assignment"),
defaultParameters: require("./transformers/default-parameters"),
destructuringAssignment: require("./transformers/destructuring-assignment"),
generators: require("./transformers/generators"),
blockBinding: require("./transformers/block-binding"),
modules: require("./transformers/modules"),
restParameters: require("./transformers/rest-parameters")
};

View File

@@ -0,0 +1,27 @@
var traverse = require("../traverse");
var util = require("../util");
exports.ArrowFunctionExpression = function (node) {
var body = node.body;
if (body.type !== "BlockStatement") {
body = {
type: "BlockStatement",
body: [{
type: "ReturnStatement",
argument: body
}]
};
}
node.expression = false;
node.body = body;
node.type = "FunctionExpression";
if (traverse.hasType(node, "ThisExpression")) {
return util.template("function-bind-this", {
FUNCTION: node
});
} else {
return node;
}
};

View File

@@ -0,0 +1,59 @@
var transform = require("../transform");
var traverse = require("../traverse");
var util = require("../util");
var _ = require("lodash");
var isLet = function (node) {
if (node.type === "VariableDeclaration" && node.kind === "let") {
node.kind = "var";
return true;
}
};
exports.Program = function (node) {
_.each(node.body, isLet);
};
exports.BlockStatement = function (node, parent) {
var hasLet = false;
_.each(node.body, function (bodyNode) {
if (isLet(bodyNode)) hasLet = true;
});
if (!hasLet) return;
// ignore if we're direct children of a closure already
if (parent.type === "FunctionExpression") return;
node.body = [buildNode(node.body)];
};
exports.ForInStatement = function (node) {
if (isLet(node.left)) return buildNode(node);
};
exports.ForStatement = function (node) {
if (isLet(node.init)) return buildNode(node);
};
var buildNode = function (node) {
var func = {
type: "FunctionExpression",
params: [],
defaults: [],
body: {
type: "BlockStatement",
body: [].concat(node)
}
};
var templateName = "function-call";
if (traverse.hasType(node, "ThisExpression")) {
templateName = "function-call-this";
}
return util.template(templateName, {
FUNCTION: func
}, true);
};

View File

@@ -0,0 +1,132 @@
var traverse = require("../traverse");
var util = require("../util");
var _ = require("lodash");
exports.ClassDeclaration = function (node, parent, opts) {
var superName = node.superClass;
var className = node.id;
var root = util.template("class", {
CLASS_NAME: className
}, true);
var container = root.declarations[0].init;
var block = container.callee.body;
var body = block.body;
var returnStatement = body.pop();
if (superName) {
body.push(util.template("inherits", {
SUPER_NAME: superName,
CLASS_NAME: className
}, true));
container.arguments.push(superName);
container.callee.params.push(superName);
}
buildClassBody(body, className, superName, node);
body.push(returnStatement);
return root;
};
var buildClassBody = function (body, className, superName, node) {
var mutatorMap = {};
var classBody = node.body.body;
_.each(classBody, function (bodyNode) {
if (bodyNode.type !== "MethodDefinition") return;
var methodName = bodyNode.key.name;
var method = bodyNode.value;
replaceInstanceSuperReferences(superName, method);
if (methodName === "constructor") {
if (bodyNode.kind === "") {
addConstructor(body[0], method);
} else {
throw new Error("unknown kind for constructor method");
}
} else {
if (bodyNode.kind === "") {
addInstanceMethod(body, className, methodName, method);
} else {
util.pushMutatorMap(mutatorMap, methodName, bodyNode.kind, bodyNode);
}
}
});
if (!_.isEmpty(mutatorMap)) {
var protoId = util.template("prototype-identifier", {
CLASS_NAME: className
});
body.push(util.buildDefineProperties(mutatorMap, protoId));
}
};
var superIdentifier = function (superName, node, parent) {
if (parent.property === node) return;
if (!superName) return;
node.name = superName.name;
// super(); -> ClassName.call(this);
if (parent.type === "CallExpression" && parent.callee === node) {
node.name += ".call";
parent.arguments.unshift({
type: "ThisExpression"
});
}
};
var replaceInstanceSuperReferences = function (superName, method) {
traverse(method, function (node, parent) {
if (node.type === "Identifier" && node.name === "super") {
superIdentifier(superName, node, parent);
} else if (node.type === "MemberExpression") {
// no accessing of super properties
var obj = node.object;
if (parent.object === node && obj.type === "Identifier" && obj.name === "super") {
throw new Error("cannot access super properties");
} else {
return;
}
} else if (node.type === "CallExpression") {
var callee = node.callee;
if (callee.type !== "MemberExpression") return;
if (callee.object.name !== "super") return;
callee.property.name = "prototype." + callee.property.name + ".call";
node.arguments.unshift({
type: "ThisExpression"
});
} else {
return;
}
if (!superName) {
throw new Error("cannot access super as this class has none");
}
});
};
var addConstructor = function (construct, method) {
construct.defaults = method.defaults;
construct.params = method.params;
construct.body = method.body;
};
var addInstanceMethod = function (body, className, methodName, method) {
body.push(util.template("class-method", {
METHOD_NAME: methodName,
CLASS_NAME: className,
FUNCTION: method
}, true));
};

View File

@@ -0,0 +1,17 @@
var util = require("../util");
var _ = require("lodash");
exports.FunctionExpression = function (node) {
_.each(node.defaults, function (def, i) {
if (!def) return;
var param = node.params[i];
node.body.body.unshift(util.template("if-undefined-set-to", {
VARIABLE: param,
DEFAULT: def
}, true));
});
node.defaults = [];
};

View File

View File

@@ -0,0 +1,85 @@
var util = require("../util");
var _ = require("lodash");
exports.ImportDeclaration = function (node) {
var nodes = [];
_.each(node.specifiers, function (specifier) {
var variableName = specifier.name || specifier.id;
var key = specifier.id.name;
var templateName = "require-assign";
if (node.kind !== "default") templateName += "-key";
nodes.push(util.template(templateName, {
VARIABLE_NAME: variableName.name,
MODULE_NAME: node.source,
KEY: key
}));
});
return nodes;
};
exports.ModuleDeclaration = function (node) {
return util.template("require-assign", {
VARIABLE_NAME: node.id,
MODULE_NAME: node.source
});
};
exports.ExportDeclaration = function (node) {
var nodes = [];
_.each(node.specifiers, function (specifier) {
var variableName = specifier.name || specifier.id;
if (specifier.type === "ExportBatchSpecifier") {
nodes.push(util.template("exports-wildcard", {
MODULE_NAME: node.source
}, true));
} else {
nodes.push(util.template("exports-require-assign-key", {
VARIABLE_NAME: variableName.name,
MODULE_NAME: node.source,
KEY: specifier.id.name
}, true));
}
});
var declar = node.declaration;
if (declar) {
if (node.default) {
nodes.push(util.template("exports-default", {
VALUE: declar
}, true));
} else {
if (declar.type === "VariableDeclaration") {
nodes.push(declar);
_.each(declar.declarations, function (declar) {
nodes.push(util.template("exports-alias-var", {
STRING_KEY: {
type: "Literal",
value: declar.id.name
},
KEY: declar.id
}, true));
});
} else if (declar.type === "FunctionDeclaration") {
declar.type = "FunctionExpression";
nodes.push(util.template("exports-assign", {
KEY: declar.id,
VALUE: declar
}, true));
} else {
throw new Error("unsupported export declaration type " + declar.type);
}
}
}
return nodes;
};

View File

@@ -0,0 +1,32 @@
var util = require("../util");
var _ = require("lodash");
exports.Property = function (node) {
if (node.method) node.method = false;
};
exports.ObjectExpression = function (node) {
//if (node.ignorePropertyMethods) return;
//node.ignorePropertyMethods = true;
var mutatorMap = {};
node.properties = node.properties.filter(function (prop) {
if (prop.kind === "get" || prop.kind === "set") {
util.pushMutatorMap(mutatorMap, prop.key.name, prop.kind, prop.value);
return false;
} else {
return true;
}
});
if (_.isEmpty(mutatorMap)) return;
return util.template("object-define-properties-closure", {
OBJECT: node,
CONTENT: util.buildDefineProperties(mutatorMap, {
type: "Identifier",
name: "obj"
}).expression
});
};

View File

@@ -0,0 +1,19 @@
var util = require("../util");
exports.FunctionExpression = function (node, parent) {
if (!node.rest) return;
var rest = node.rest;
delete node.rest;
var templateName = "arguments-slice-assign";
if (node.params.length) templateName += "-arg";
node.body.body.unshift(util.template(templateName, {
VARIABLE_NAME: rest,
SLICE_ARG: {
type: "Literal",
value: node.params.length
}
}));
};

View File

@@ -0,0 +1,64 @@
var util = require("../util");
var _ = require("lodash");
exports.ArrayExpression = function (node, parent) {
//if (node.ignoreSpread) return;
var elements = node.elements;
if (!elements.length) return;
var spread = elements.pop();
if (spread.type !== "SpreadElement") {
elements.push(spread);
return;
}
var concat = util.template("array-concat", {
ARGUMENT: spread.argument
});
concat.callee.object.elements = elements;
return concat;
};
exports.CallExpression = function (node, parent) {
var args = node.arguments;
if (args.length && _.last(args).type === "SpreadElement") {
var spread = args.pop();
var spreadLiteral = spread.argument;
var contextLiteral = {
type: "Literal",
value: null
};
node.arguments = [];
if (args.length) {
if (spreadLiteral.name === "arguments") {
spreadLiteral = util.template("arguments-slice");
}
var concat = util.template("array-concat");
concat.arguments = [spreadLiteral];
concat.callee.object.elements = args;
node.arguments.push(concat);
} else {
node.arguments.push(spreadLiteral);
}
var callee = node.callee;
if (callee.type === "MemberExpression") {
contextLiteral = callee.object;
callee.property.name += ".apply";
} else {
node.callee.name += ".apply";
}
node.arguments.unshift(contextLiteral);
}
};

View File

@@ -0,0 +1,40 @@
var _ = require("lodash");
var buildBinaryExpression = function (left, right) {
return {
type: "BinaryExpression",
operator: "+",
left: left,
right: right
};
};
exports.TemplateLiteral = function (node) {
var nodes = [];
_.each(node.quasis, function (elem) {
nodes.push({
type: "Literal",
value: elem.value.raw
});
var expr = node.expressions.shift();
if (expr) nodes.push(expr);
});
if (nodes.length > 1) {
// remove redundant '' at the end of the expression
var last = _.last(nodes);
if (last.type === "Literal" && last.value === "") nodes.pop();
var root = buildBinaryExpression(nodes.shift(), nodes.shift());
_.each(nodes, function (node) {
root = buildBinaryExpression(root, node);
});
return root;
} else {
return nodes[0];
}
};

View File

@@ -0,0 +1,68 @@
var VISITOR_KEYS = require("./visitor-keys");
var _ = require("lodash");
var traverse = module.exports = function (parent, callback) {
if (_.isArray(parent)) {
_.each(parent, function (node) {
traverse(node, callback);
});
return;
}
var keys = VISITOR_KEYS[parent.type] || [];
_.each(keys, function (key) {
var nodes = parent[key];
if (!nodes) return;
var handle = function (obj, key) {
if (!obj[key]) return;
// strict references in case the callback modified/replaced the node
var result = callback(obj[key], parent, obj, key);
if (result === false) return;
traverse(obj[key], callback);
};
if (_.isArray(nodes)) {
_.each(nodes, function (node, i) {
handle(nodes, i);
});
parent[key] = _.flatten(nodes).filter(function (node) {
return node !== traverse.Delete;
});
} else {
handle(parent, key);
}
});
};
traverse.Delete = {};
traverse.hasType = function (tree, type) {
var has = false;
if (_.isArray(tree)) {
return !!_.find(tree, function (node) {
return traverse.hasType(node, type);
});
} else {
traverse(tree, function (node) {
if (node.type === type) {
has = true;
return false;
}
});
}
return has;
};
traverse.replace = function (node, callback) {
traverse(node, function (node, parent, obj, key) {
var result = callback(node, parent);
if (result != null) obj[key] = result;
});
};

View File

@@ -0,0 +1,46 @@
{
"AssignmentExpression": ["left", "right"],
"ArrayExpression": ["elements"],
"ArrayPattern": ["elements"],
"ArrowFunctionExpression": ["params", "defaults", "rest", "body"],
"BlockStatement": ["body"],
"BinaryExpression": ["left", "right"],
"BreakStatement": ["label"],
"CallExpression": ["callee", "arguments"],
"CatchClause": ["param", "body"],
"ClassBody": ["body"],
"ClassDeclaration": ["id", "body", "superClass"],
"ClassExpression": ["id", "body", "superClass"],
"ConditionalExpression": ["test", "consequent", "alternate"],
"ContinueStatement": ["label"],
"DoWhileStatement": ["body", "test"],
"ExpressionStatement": ["expression"],
"ForStatement": ["init", "test", "update", "body"],
"ForInStatement": ["left", "right", "body"],
"ForOfStatement": ["left", "right", "body"],
"FunctionDeclaration": ["id", "params", "defaults", "rest", "body"],
"FunctionExpression": ["id", "params", "defaults", "rest", "body"],
"IfStatement": ["test", "consequent", "alternate"],
"LabeledStatement": ["label", "body"],
"LogicalExpression": ["left", "right"],
"MemberExpression": ["object", "property"],
"MethodDefinition": ["key", "value"],
"NewExpression": ["callee", "arguments"],
"ObjectExpression": ["properties"],
"ObjectPattern": ["properties"],
"Program": ["body"],
"Property": ["key", "value"],
"ReturnStatement": ["argument"],
"SequenceExpression": ["expressions"],
"SwitchStatement": ["discriminant", "cases"],
"SwitchCase": ["test", "consequent"],
"ThrowStatement": ["argument"],
"TryStatement": ["block", "handlers", "handler", "guardedHandlers", "finalizer"],
"UnaryExpression": ["argument"],
"UpdateExpression": ["argument"],
"VariableDeclaration": ["declarations"],
"VariableDeclarator": ["id", "init"],
"WhileStatement": ["test", "body"],
"WithStatement": ["object", "body"],
"YieldExpression": ["argument"]
}

182
lib/6to5/util.js Normal file
View File

@@ -0,0 +1,182 @@
var estraverse = require("estraverse");
var traverse = require("./traverse");
var esprima = require("esprima");
var path = require("path");
var fs = require("fs");
var _ = require("lodash");
exports.parse = function (code, opts) {
opts = _.defaults(opts || {}, {
comment: true,
range: true,
loc: true
});
code = [].concat(code).join("");
try {
var tree = esprima.parse(code);
if (tree.tokens && tree.comments) {
estraverse.attachComments(tree, tree.comments, tree.tokens);
}
return tree;
} catch (err) {
if (err.lineNumber) {
err.message = err.message + exports.codeFrame(code, err.lineNumber, err.column);
}
throw err;
}
};
exports.canCompile = function (filename) {
return path.extname(filename) === ".js";
};
exports.sourceMapToComment = function (map) {
var json = JSON.stringify(map);
var base64 = new Buffer(json).toString("base64");
return "//# sourceMappingURL=data:application/json;base64," + base64;
};
exports.pushMutatorMap = function (mutatorMap, key, kind, method) {
var map = mutatorMap[key] = mutatorMap[key] || {};
if (map[kind]) {
throw new Error("a " + kind + " already exists for this property");
} else {
map[kind] = method;
}
};
exports.buildDefineProperties = function (mutatorMap, keyNode) {
var objExpr = {
type: "ObjectExpression",
properties: []
};
_.each(mutatorMap, function (map, key) {
var mapNode = {
type: "ObjectExpression",
properties: []
};
var propNode = {
type: "Property",
key: {
type: "Identifier",
name: key
},
value: mapNode,
kind: "init"
};
_.each(map, function (methodNode, type) {
if (methodNode.type === "MethodDefinition") methodNode = methodNode.value;
mapNode.properties.push({
type: "Property",
key: {
type: "Identifier",
name: type
},
value: methodNode,
kind: "init"
});
});
objExpr.properties.push(propNode);
});
return exports.template("object-define-properties", {
OBJECT: keyNode,
PROPS: objExpr
}, true);
};
exports.template = function (name, nodes, keepExpression) {
var template = _.cloneDeep(exports.templates[name]);
if (!_.isEmpty(nodes)) {
traverse.replace(template, function (node) {
if (node.type === "Identifier" && _.has(nodes, node.name)) {
var newNode = nodes[node.name];
if (_.isString(newNode)) {
node.name = newNode;
} else {
return newNode;
}
}
});
}
var normaliseNode = function (node) {
if (!keepExpression && node.type === "ExpressionStatement") {
return node.expression;
} else {
return node;
}
};
var body = template.body;
if (body.length <= 1) {
return normaliseNode(body[0]);
} else {
return body.map(normaliseNode);
}
};
exports.codeFrame = function (lines, lineNumber, colNumber) {
if (!lineNumber) return "";
colNumber = Math.max(colNumber, 0);
lines = lines.split("\n");
var start = Math.max(lineNumber - 3, 0);
var end = Math.min(lines.length, lineNumber + 3);
var width = (end + "").length;
return "\n" + lines.slice(start, end).map(function (line, i) {
var curr = i + start + 1;
var gutter = curr === lineNumber ? "> " : " ";
var sep = curr + exports.repeat(width + 1);
gutter += sep + "| ";
var str = gutter + line;
if (colNumber && curr === lineNumber) {
str += "\n";
str += exports.repeat(gutter.length - 2);
str += "|" + exports.repeat(colNumber) + "^";
}
return str;
}).join("\n");
};
exports.repeat = function (width, cha) {
cha = cha || " ";
return Array(width + 1).join(cha);
};
var templatesCacheLoc = __dirname + "/../../templates.json";
if (fs.existsSync(templatesCacheLoc)) {
exports.templates = require(templatesCacheLoc);
} else {
exports.templates = {};
var templatesLoc = __dirname + "/templates";
_.each(fs.readdirSync(templatesLoc), function (name) {
var key = path.basename(name, path.extname(name));
var code = fs.readFileSync(templatesLoc + "/" + name, "utf8");
exports.templates[key] = exports.parse(code, {
range: false,
loc: false
});
});
}