Cleanup template-literals transform (#5748)

Avoid `Array#shift`s and prefer `const`s when possible.
This commit is contained in:
Justin Ridgewell 2017-05-19 14:57:15 -04:00 committed by Henry Zhu
parent a52d34023c
commit 09229db794

View File

@ -1,82 +1,70 @@
export default function ({ types: t }) { export default function ({ types: t }) {
function isString(node) {
return t.isLiteral(node) && typeof node.value === "string";
}
function buildBinaryExpression(left, right) {
return t.binaryExpression("+", left, right);
}
return { return {
visitor: { visitor: {
TaggedTemplateExpression(path, state) { TaggedTemplateExpression(path, state) {
const { node } = path; const { node } = path;
const quasi = node.quasi; const { quasi } = node;
let args = [];
let strings = []; const strings = [];
let raw = []; const raws = [];
for (const elem of (quasi.quasis: Array)) { for (const elem of (quasi.quasis: Array)) {
const value = elem.value.cooked == null const { raw, cooked } = elem.value;
const value = cooked == null
? path.scope.buildUndefinedNode() ? path.scope.buildUndefinedNode()
: t.stringLiteral(elem.value.cooked); : t.stringLiteral(cooked);
strings.push(value);
raw.push(t.stringLiteral(elem.value.raw));
}
strings = t.arrayExpression(strings); strings.push(value);
raw = t.arrayExpression(raw); raws.push(t.stringLiteral(raw));
}
let templateName = "taggedTemplateLiteral"; let templateName = "taggedTemplateLiteral";
if (state.opts.loose) templateName += "Loose"; if (state.opts.loose) templateName += "Loose";
const templateObject = state.file.addTemplateObject(templateName, strings, raw); const templateObject = state.file.addTemplateObject(
args.push(templateObject); templateName,
t.arrayExpression(strings),
t.arrayExpression(raws)
);
args = args.concat(quasi.expressions); const args = [templateObject].concat(quasi.expressions);
path.replaceWith(t.callExpression(node.tag, args)); path.replaceWith(t.callExpression(node.tag, args));
}, },
TemplateLiteral(path, state) { TemplateLiteral(path, state) {
let nodes: Array<Object> = []; const nodes = [];
const expressions = path.get("expressions"); const expressions = path.get("expressions");
let index = 0;
for (const elem of (path.node.quasis: Array)) { for (const elem of (path.node.quasis: Array)) {
if (elem.value.cooked) {
nodes.push(t.stringLiteral(elem.value.cooked)); nodes.push(t.stringLiteral(elem.value.cooked));
}
const expr = expressions.shift(); if (index < expressions.length) {
if (expr) { const expr = expressions[index++];
const node = expr.node;
if (state.opts.spec && !expr.isBaseType("string") && !expr.isBaseType("number")) { if (state.opts.spec && !expr.isBaseType("string") && !expr.isBaseType("number")) {
nodes.push(t.callExpression(t.identifier("String"), [expr.node])); nodes.push(t.callExpression(t.identifier("String"), [node]));
} else { } else if (!t.isStringLiteral(node, { value: "" })) {
nodes.push(expr.node); nodes.push(node);
} }
} }
} }
// filter out empty string literals
nodes = nodes.filter((n) => !t.isLiteral(n, { value: "" }));
// since `+` is left-to-right associative // since `+` is left-to-right associative
// ensure the first node is a string if first/second isn't // ensure the first node is a string if first/second isn't
if (!isString(nodes[0]) && !isString(nodes[1])) { if (!t.isStringLiteral(nodes[0]) && !t.isStringLiteral(nodes[1])) {
nodes.unshift(t.stringLiteral("")); nodes.unshift(t.stringLiteral(""));
} }
if (nodes.length > 1) { let root = nodes[0];
let root = buildBinaryExpression(nodes.shift(), nodes.shift()); for (let i = 1; i < nodes.length; i++) {
root = t.binaryExpression("+", root, nodes[i]);
for (const node of nodes) {
root = buildBinaryExpression(root, node);
} }
path.replaceWith(root); path.replaceWith(root);
} else {
path.replaceWith(nodes[0]);
}
}, },
}, },
}; };