Add support for evaluating String.raw expressions (#5681)

* Add support for evaluating `String.raw` expressions

* Dedupe evaluation code for template literal quasis

* Check scoping in `String.raw` evaluation
  This addresses https://github.com/babel/babel/pull/5681#discussion_r114203497

* Ensure that `tag` is a MemberExpression in `String.raw` evaluation
  This addresses https://github.com/babel/babel/pull/5681#discussion_r114203555

* babel-traverse: Move evaluateQuasis() outside _evaluate()
This commit is contained in:
Joseph Frazier 2017-06-24 16:00:42 -04:00 committed by Henry Zhu
parent b6b69c615a
commit a330cf2b09
2 changed files with 45 additions and 16 deletions

View File

@ -89,25 +89,20 @@ function _evaluate(path, state) {
}
if (path.isTemplateLiteral()) {
let str = "";
let i = 0;
const exprs = path.get("expressions");
for (const elem of (node.quasis: Array<Object>)) {
// not confident, evaluated an expression we don't like
if (!state.confident) break;
// add on cooked element
str += elem.value.cooked;
// add on interpolated expression if it's present
const expr = exprs[i++];
if (expr) str += String(evaluateCached(expr, state));
return evaluateQuasis(path, node.quasis, state);
}
if (!state.confident) return;
return str;
if (path.isTaggedTemplateExpression() && path.get("tag").isMemberExpression()) {
const object = path.get("tag.object");
const { node: { name } } = object;
const property = path.get("tag.property");
if (
object.isIdentifier() && name === "String" && !path.scope.getBinding(name, true) &&
property.isIdentifier && property.node.name === "raw"
) {
return evaluateQuasis(path, node.quasi.quasis, state, true);
}
}
if (path.isConditionalExpression()) {
@ -349,6 +344,28 @@ function _evaluate(path, state) {
deopt(path, state);
}
function evaluateQuasis (path, quasis: Array<Object>, state, raw = false) {
let str = "";
let i = 0;
const exprs = path.get("expressions");
for (const elem of quasis) {
// not confident, evaluated an expression we don't like
if (!state.confident) break;
// add on element
str += raw ? elem.value.raw : elem.value.cooked;
// add on interpolated expression if it's present
const expr = exprs[i++];
if (expr) str += String(evaluateCached(expr, state));
}
if (!state.confident) return;
return str;
}
/**
* Walk the input `node` and statically evaluate it.
*

View File

@ -119,4 +119,16 @@ describe("evaluation", function () {
assert.strictEqual(eval_undef.deopt.type, "VariableDeclarator");
assert.strictEqual(eval_undef.deopt.parentPath.node.kind, "let");
});
it("should work with String.raw", function () {
assert.strictEqual(
getPath("String.raw`\\d`").get("body")[0].evaluate().value,
"\\d"
);
assert.strictEqual(
getPath("`${String.raw`\\d`}`").get("body")[0].evaluate().value,
"\\d"
);
});
});