use Object.defineProperty on computed properties - fixes #357

This commit is contained in:
Sebastian McKenzie 2015-01-02 00:36:28 +11:00
parent 7b5b8ab6ed
commit 800c350db6
16 changed files with 197 additions and 82 deletions

View File

@ -26,7 +26,8 @@ File.declarations = [
"sliced-to-array",
"object-without-properties",
"has-own",
"slice"
"slice",
"define-property"
];
File.normaliseOptions = function (opts) {

View File

@ -0,0 +1,8 @@
(function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
});

View File

@ -1,3 +0,0 @@
(function (KEY) {
return KEY;
})(OBJECT)

View File

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

View File

@ -1,6 +0,0 @@
Object.defineProperty(this, KEY, {
enumerable: true,
configurable: true,
writable: true,
value: VALUE
})

View File

@ -4,44 +4,91 @@ var t = require("../../types");
exports.ObjectExpression = function (node, parent, file) {
var hasComputed = false;
var computed = [];
node.properties = node.properties.filter(function (prop) {
if (prop.computed) {
hasComputed = true;
computed.unshift(prop);
return false;
} else {
return true;
}
});
for (var i in node.properties) {
hasComputed = t.isProperty(node.properties[i], { computed: true });
if (hasComputed) break;
}
if (!hasComputed) return;
var objId = util.getUid(parent, file);
var container = util.template("function-return-obj", {
KEY: objId,
OBJECT: node
});
var body = [];
var container = t.functionExpression(null, [], t.blockStatement(body));
container._aliasFunction = true;
var containerCallee = container.callee;
var containerBody = containerCallee.body.body;
var props = node.properties;
containerCallee._aliasFunction = true;
// normalise key
for (var i in computed) {
var prop = computed[i];
containerBody.unshift(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(objId, prop.key, true),
prop.value
)
)
);
for (i in props) {
var prop = props[i];
var key = prop.key;
if (!prop.computed && t.isIdentifier(key)) {
prop.key = t.literal(key.name);
}
}
return container;
// add all non-computed properties and `__proto__` properties to the initializer
var initProps = [];
var broken = false;
for (i in props) {
var prop = props[i];
if (prop.computed) {
broken = true;
}
if (!broken || t.isLiteral(prop.key, { value: "__proto__" })) {
initProps.push(prop);
props[i] = null;
}
}
// add a simple assignment for all Symbol member expressions due to symbol polyfill limitations
// otherwise use Object.defineProperty
for (i in props) {
var prop = props[i];
if (!prop) continue;
var key = prop.key;
var bodyNode;
if (prop.computed && t.isMemberExpression(key) && t.isIdentifier(key.object, { name: "Symbol" })) {
bodyNode = t.assignmentExpression(
"=",
t.memberExpression(objId, key, true),
prop.value
);
} else {
bodyNode = t.callExpression(file.addDeclaration("define-property"), [objId, key, prop.value]);
}
body.push(t.expressionStatement(bodyNode));
}
// only one node and it's a Object.defineProperty that returns the object
if (body.length === 1) {
var first = body[0].expression;
if (t.isCallExpression(first)) {
first.arguments[0] = t.objectExpression([]);
return first;
}
}
//
body.unshift(t.variableDeclaration("var", [
t.variableDeclarator(objId, t.objectExpression(initProps))
]));
body.push(t.returnStatement(objId));
return t.callExpression(container, []);
};

View File

@ -1,6 +1,12 @@
"use strict";
foo((function (_ref) {
_ref[bar] = "foobar";
return _ref;
})({}));
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
foo(_defineProperty({}, bar, "foobar"));

View File

@ -1,6 +1,12 @@
"use strict";
foo = (function (_foo) {
_foo[bar] = "foobar";
return _foo;
})({});
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
foo = _defineProperty({}, bar, "foobar");

View File

@ -0,0 +1,3 @@
var foo = {
[Symbol.iterator]: "foobar"
};

View File

@ -0,0 +1,8 @@
"use strict";
var foo = (function () {
var _foo = {};
_foo[Symbol.iterator] = "foobar";
return _foo;
})();

View File

@ -1,9 +1,14 @@
"use strict";
var obj = (function (_obj) {
_obj[foobar] = function () {
return "foobar";
};
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
return _obj;
})({});
var obj = _defineProperty({}, foobar, function () {
return "foobar";
});

View File

@ -1,10 +1,24 @@
"use strict";
var obj = (function (_obj) {
_obj["x" + foo] = "heh";
_obj["y" + bar] = "noo";
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
var obj = (function () {
var _obj = {};
_defineProperty(_obj, "x" + foo, "heh");
_defineProperty(_obj, "y" + bar, "noo");
_defineProperty(_obj, "foo", "foo");
_defineProperty(_obj, "bar", "bar");
return _obj;
})({
foo: "foo",
bar: "bar"
});
})();

View File

@ -1,7 +1,20 @@
"use strict";
var obj = (function (_obj) {
_obj["x" + foo] = "heh";
_obj["y" + bar] = "noo";
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
var obj = (function () {
var _obj = {};
_defineProperty(_obj, "x" + foo, "heh");
_defineProperty(_obj, "y" + bar, "noo");
return _obj;
})({});
})();

View File

@ -1,6 +1,12 @@
"use strict";
var obj = (function (_obj) {
_obj["x" + foo] = "heh";
return _obj;
})({});
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
var obj = _defineProperty({}, "x" + foo, "heh");

View File

@ -1,7 +1,12 @@
"use strict";
var _this = this;
var obj = (function (_obj) {
_obj["x" + _this.foo] = "heh";
return _obj;
})({});
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
var obj = _defineProperty({}, "x" + this.foo, "heh");

View File

@ -1,6 +1,12 @@
"use strict";
var foo = (function (_foo) {
_foo[bar] = "foobar";
return _foo;
})({});
var _defineProperty = function (obj, key, value) {
return Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
};
var foo = _defineProperty({}, bar, "foobar");