191 lines
4.4 KiB
JavaScript
191 lines
4.4 KiB
JavaScript
var estraverse = require("estraverse");
|
|
var traverse = require("./traverse");
|
|
var esprima = require("esprima");
|
|
var path = require("path");
|
|
var fs = require("fs");
|
|
var _ = require("lodash");
|
|
|
|
_.each(esprima.Syntax, function (name) {
|
|
estraverse.VisitorKeys[name] = estraverse.VisitorKeys[name] || [];
|
|
});
|
|
|
|
exports.parse = function (code, opts) {
|
|
opts = _.defaults(opts || {}, {
|
|
comment: true,
|
|
tokens: true,
|
|
range: true,
|
|
loc: true
|
|
});
|
|
|
|
code = [].concat(code).join("");
|
|
|
|
try {
|
|
var tree = esprima.parse(code, opts);
|
|
|
|
if (tree.tokens && tree.comments) {
|
|
estraverse.attachComments(tree, tree.comments, tree.tokens);
|
|
}
|
|
|
|
return tree;
|
|
} catch (err) {
|
|
if (err.lineNumber) {
|
|
var frame = exports.codeFrame(code, err.lineNumber, err.column);
|
|
err.message = err.message + frame;
|
|
}
|
|
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 new 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, {
|
|
comment: false,
|
|
tokens: false,
|
|
range: false,
|
|
loc: false
|
|
});
|
|
});
|
|
}
|