Playground Proposal: Mallet operator
The mallet operator is similar to the current memoization operator, except it can be used outside of just objects. In Ruby, it’s almost the same as `a = a || b`. Note that only `nil` and `false` are falsey in Ruby. I’ve defined it as `== null`, though that could be changed to any JS falsey value.
This commit is contained in:
parent
76b8945207
commit
616640a128
@ -46,6 +46,7 @@ _.each({
|
|||||||
specSetters: require("./transformers/spec-setters"),
|
specSetters: require("./transformers/spec-setters"),
|
||||||
|
|
||||||
// playground
|
// playground
|
||||||
|
malletOperator: require("./transformers/playground-mallet-operator"),
|
||||||
methodBinding: require("./transformers/playground-method-binding"),
|
methodBinding: require("./transformers/playground-method-binding"),
|
||||||
memoizationOperator: require("./transformers/playground-memoization-operator"),
|
memoizationOperator: require("./transformers/playground-memoization-operator"),
|
||||||
objectGetterMemoization: require("./transformers/playground-object-getter-memoization"),
|
objectGetterMemoization: require("./transformers/playground-object-getter-memoization"),
|
||||||
|
|||||||
@ -0,0 +1,86 @@
|
|||||||
|
var t = require("../../types");
|
||||||
|
|
||||||
|
var isMallet = function (node) {
|
||||||
|
var is = t.isAssignmentExpression(node) && node.operator === "||=";
|
||||||
|
if (is) {
|
||||||
|
var left = node.left;
|
||||||
|
if (!t.isMemberExpression(left) && !t.isIdentifier(left)) {
|
||||||
|
throw new Error("Expected type MemeberExpression or Identifier");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getObjRef = function (node, nodes, file, scope) {
|
||||||
|
var obj = node.object;
|
||||||
|
if (t.isIdentifier(obj)) return obj;
|
||||||
|
|
||||||
|
var temp = scope.generateUidBasedOnNode(obj, file);
|
||||||
|
nodes.push(t.variableDeclaration("var", [
|
||||||
|
t.variableDeclarator(temp, obj)
|
||||||
|
]));
|
||||||
|
return temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getPropRef = function (node, nodes, file, scope) {
|
||||||
|
var prop = node.property;
|
||||||
|
var key = t.toComputedKey(node, prop);
|
||||||
|
if (t.isLiteral(key)) return key;
|
||||||
|
|
||||||
|
var temp = scope.generateUidBasedOnNode(prop, file);
|
||||||
|
nodes.push(t.variableDeclaration("var", [
|
||||||
|
t.variableDeclarator(temp, prop)
|
||||||
|
]));
|
||||||
|
return temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
var buildAbsoluteRef = function (node, nodes, file, scope) {
|
||||||
|
if (t.isIdentifier(node)) return node;
|
||||||
|
|
||||||
|
var obj = getObjRef(node, nodes, file, scope);
|
||||||
|
var prop = getPropRef(node, nodes, file, scope);
|
||||||
|
|
||||||
|
var computed = node.computed || t.isLiteral(prop);
|
||||||
|
return t.memberExpression(obj, prop, computed);
|
||||||
|
};
|
||||||
|
|
||||||
|
var buildIsNull = function (node) {
|
||||||
|
return t.binaryExpression("==", node, t.literal(null));
|
||||||
|
};
|
||||||
|
|
||||||
|
var buildAssignment = function (left, right) {
|
||||||
|
return t.assignmentExpression("=", left, right);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.ExpressionStatement = function (node, parent, file, scope) {
|
||||||
|
var expr = node.expression;
|
||||||
|
if (!isMallet(expr)) return;
|
||||||
|
|
||||||
|
var nodes = [];
|
||||||
|
var left = buildAbsoluteRef(expr.left, nodes, file, scope);
|
||||||
|
|
||||||
|
nodes.push(t.ifStatement(
|
||||||
|
buildIsNull(left),
|
||||||
|
t.expressionStatement(buildAssignment(left, expr.right))
|
||||||
|
));
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.AssignmentExpression = function (node, parent, file, scope) {
|
||||||
|
if (t.isExpressionStatement(parent)) return;
|
||||||
|
if (!isMallet(node)) return;
|
||||||
|
|
||||||
|
var nodes = [];
|
||||||
|
var left = buildAbsoluteRef(node.left, nodes, file, scope);
|
||||||
|
|
||||||
|
nodes.push(t.logicalExpression(
|
||||||
|
"&&",
|
||||||
|
buildIsNull(left),
|
||||||
|
buildAssignment(left, node.right)
|
||||||
|
));
|
||||||
|
|
||||||
|
nodes.push(left);
|
||||||
|
|
||||||
|
return t.toSequenceExpression(nodes, scope);
|
||||||
|
};
|
||||||
17
test/fixtures/transformation/playground/mallet-operator/actual.js
vendored
Normal file
17
test/fixtures/transformation/playground/mallet-operator/actual.js
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
obj ||= {};
|
||||||
|
|
||||||
|
obj.x ||= 2;
|
||||||
|
|
||||||
|
console.log(obj.x ||= 2);
|
||||||
|
|
||||||
|
obj.x.x ||= 2;
|
||||||
|
|
||||||
|
console.log(obj.x.x ||= 2);
|
||||||
|
|
||||||
|
obj[x()] ||= 2;
|
||||||
|
|
||||||
|
console.log(obj[x()] ||= 2);
|
||||||
|
|
||||||
|
obj[y()][x()] ||= 2;
|
||||||
|
|
||||||
|
console.log(obj[y()][x()] ||= 2);
|
||||||
56
test/fixtures/transformation/playground/mallet-operator/exec.js
vendored
Normal file
56
test/fixtures/transformation/playground/mallet-operator/exec.js
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
var obj = {};
|
||||||
|
obj.x ||= 2;
|
||||||
|
assert.equal(obj.x, 2);
|
||||||
|
|
||||||
|
obj = {};
|
||||||
|
assert.equal(obj.x ||= 2, 2);
|
||||||
|
|
||||||
|
obj = { x: 1 };
|
||||||
|
obj.x ||= 2;
|
||||||
|
assert.equal(obj.x, 1);
|
||||||
|
|
||||||
|
obj = { x: 1 };
|
||||||
|
assert.equal(obj.x ||= 2, 1);
|
||||||
|
|
||||||
|
obj = { x: undefined }
|
||||||
|
obj.x ||= 2;
|
||||||
|
assert.equal(obj.x, 2);
|
||||||
|
|
||||||
|
obj = { x: undefined }
|
||||||
|
assert.equal(obj.x ||= 2, 2);
|
||||||
|
|
||||||
|
obj = { x: null }
|
||||||
|
obj.x ||= 2;
|
||||||
|
assert.equal(obj.x, 2);
|
||||||
|
|
||||||
|
obj = { x: null }
|
||||||
|
assert.equal(obj.x ||= 2, 2);
|
||||||
|
|
||||||
|
obj = { x: false }
|
||||||
|
obj.x ||= 2;
|
||||||
|
assert.equal(obj.x, false);
|
||||||
|
|
||||||
|
obj = { x: false }
|
||||||
|
assert.equal(obj.x ||= 2, false);
|
||||||
|
|
||||||
|
obj = undefined;
|
||||||
|
obj ||= 2;
|
||||||
|
assert.equal(obj, 2);
|
||||||
|
|
||||||
|
obj = undefined;
|
||||||
|
assert.equal(obj ||= 2 , 2);
|
||||||
|
|
||||||
|
obj = 1;
|
||||||
|
obj ||= 2;
|
||||||
|
assert.equal(obj, 1);
|
||||||
|
|
||||||
|
obj = 1;
|
||||||
|
assert.equal(obj ||= 2 , 1);
|
||||||
|
|
||||||
|
obj = null;
|
||||||
|
obj ||= 2;
|
||||||
|
assert.equal(obj, 2);
|
||||||
|
|
||||||
|
obj = null;
|
||||||
|
assert.equal(obj ||= 2 , 2);
|
||||||
|
|
||||||
29
test/fixtures/transformation/playground/mallet-operator/expected.js
vendored
Normal file
29
test/fixtures/transformation/playground/mallet-operator/expected.js
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _obj$x2, _x2, _obj$y2, _x4;
|
||||||
|
if (obj == null) obj = {};
|
||||||
|
if (obj.x == null) obj.x = 2;
|
||||||
|
|
||||||
|
|
||||||
|
console.log((obj.x == null && (obj.x = 2), obj.x));
|
||||||
|
|
||||||
|
var _obj$x = obj.x;
|
||||||
|
if (_obj$x.x == null) _obj$x.x = 2;
|
||||||
|
|
||||||
|
|
||||||
|
console.log((_obj$x2 = obj.x, _obj$x2.x == null && (_obj$x2.x = 2), _obj$x2.x));
|
||||||
|
|
||||||
|
var _x = x();
|
||||||
|
|
||||||
|
if (obj[_x] == null) obj[_x] = 2;
|
||||||
|
|
||||||
|
|
||||||
|
console.log((_x2 = x(), obj[_x2] == null && (obj[_x2] = 2), obj[_x2]));
|
||||||
|
|
||||||
|
var _obj$y = obj[y()];
|
||||||
|
var _x3 = x();
|
||||||
|
|
||||||
|
if (_obj$y[_x3] == null) _obj$y[_x3] = 2;
|
||||||
|
|
||||||
|
|
||||||
|
console.log((_obj$y2 = obj[y()], _x4 = x(), _obj$y2[_x4] == null && (_obj$y2[_x4] = 2), _obj$y2[_x4]));
|
||||||
Loading…
x
Reference in New Issue
Block a user