[FIX] web: fix patch descriptor

Before this commit, patching a getter of a class made it enumerable
(`Object.keys({ a: 1 })` -> `["a"]`).
In javascript, getters of a class are not enumerable but
getters of an object are enumerable.

When patching, the system replaced the descriptor of the old class
member by the member of the object.
Now, it replaces some info of the old descriptor by the new descriptor
but not the entire descriptor.

closes odoo/odoo#95921

X-original-commit: fd7c2c0c14bfaac228abacb265278157eec4aad0
Signed-off-by: Géry Debongnie <ged@odoo.com>
Signed-off-by: Michaël Mattiello <mcm@odoo.com>
This commit is contained in:
Michael (mcm)
2022-07-13 16:23:08 +02:00
parent b2e5cb8604
commit 88412a2d2b
2 changed files with 31 additions and 3 deletions
+7 -3
View File
@@ -39,7 +39,7 @@ export function patch(obj, patchName, patchValue, options = {}) {
proto = Object.getPrototypeOf(proto);
} while (!prevDesc && proto);
const newDesc = Object.getOwnPropertyDescriptor(patchValue, k);
let newDesc = Object.getOwnPropertyDescriptor(patchValue, k);
if (!objDesc.original.hasOwnProperty(k)) {
objDesc.original[k] = Object.getOwnPropertyDescriptor(obj, k);
}
@@ -48,6 +48,7 @@ export function patch(obj, patchName, patchValue, options = {}) {
const patchedFnName = `${k} (patch ${patchName})`;
if (prevDesc.value && typeof newDesc.value === "function") {
newDesc = { ...prevDesc, value: newDesc.value };
makeIntermediateFunction("value", prevDesc, newDesc, patchedFnName);
}
if ((newDesc.get || newDesc.set) && (prevDesc.get || prevDesc.set)) {
@@ -55,8 +56,11 @@ export function patch(obj, patchName, patchValue, options = {}) {
// in the previous descriptor but only one in the new descriptor
// then the other will be undefined so we need to apply the
// previous descriptor in the new one.
newDesc.get = newDesc.get || prevDesc.get;
newDesc.set = newDesc.set || prevDesc.set;
newDesc = {
...prevDesc,
get: newDesc.get || prevDesc.get,
set: newDesc.set || prevDesc.set,
};
if (prevDesc.get && typeof newDesc.get === "function") {
makeIntermediateFunction("get", prevDesc, newDesc, patchedFnName);
}
@@ -1085,6 +1085,30 @@ QUnit.module("utils", () => {
assert.verifySteps(["base.fn", "extension.fn"]);
});
QUnit.test("keep original descriptor details", async function (assert) {
class BaseClass {
// getter declared in classes are not enumerable
get getter() {
return false;
}
}
let descriptor = Object.getOwnPropertyDescriptor(BaseClass.prototype, "getter");
let getterFn = descriptor.get;
assert.strictEqual(descriptor.configurable, true);
assert.strictEqual(descriptor.enumerable, false);
patch(BaseClass.prototype, "patch", {
// getter declared in object are enumerable
get getter() {
return true;
},
});
descriptor = Object.getOwnPropertyDescriptor(BaseClass.prototype, "getter");
assert.strictEqual(descriptor.configurable, true);
assert.strictEqual(descriptor.enumerable, false);
assert.notStrictEqual(getterFn, descriptor.get);
});
QUnit.module("other");
QUnit.test("patch an object", async function (assert) {