83 lines
2.6 KiB
JavaScript
83 lines
2.6 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = deleteUnknownAutoBindMethods;
|
||
|
function shouldDeleteClassicInstanceMethod(component, name) {
|
||
|
if (component.__reactAutoBindMap && component.__reactAutoBindMap.hasOwnProperty(name)) {
|
||
|
// It's a known autobound function, keep it
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (component.__reactAutoBindPairs && component.__reactAutoBindPairs.indexOf(name) >= 0) {
|
||
|
// It's a known autobound function, keep it
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (component[name].__reactBoundArguments !== null) {
|
||
|
// It's a function bound to specific args, keep it
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// It's a cached bound method for a function
|
||
|
// that was deleted by user, so we delete it from component.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function shouldDeleteModernInstanceMethod(component, name) {
|
||
|
var prototype = component.constructor.prototype;
|
||
|
|
||
|
var prototypeDescriptor = Object.getOwnPropertyDescriptor(prototype, name);
|
||
|
|
||
|
if (!prototypeDescriptor || !prototypeDescriptor.get) {
|
||
|
// This is definitely not an autobinding getter
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (prototypeDescriptor.get().length !== component[name].length) {
|
||
|
// The length doesn't match, bail out
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// This seems like a method bound using an autobinding getter on the prototype
|
||
|
// Hopefully we won't run into too many false positives.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function shouldDeleteInstanceMethod(component, name) {
|
||
|
var descriptor = Object.getOwnPropertyDescriptor(component, name);
|
||
|
if (typeof descriptor.value !== 'function') {
|
||
|
// Not a function, or something fancy: bail out
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (component.__reactAutoBindMap || component.__reactAutoBindPairs) {
|
||
|
// Classic
|
||
|
return shouldDeleteClassicInstanceMethod(component, name);
|
||
|
} else {
|
||
|
// Modern
|
||
|
return shouldDeleteModernInstanceMethod(component, name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Deletes autobound methods from the instance.
|
||
|
*
|
||
|
* For classic React classes, we only delete the methods that no longer exist in map.
|
||
|
* This means the user actually deleted them in code.
|
||
|
*
|
||
|
* For modern classes, we delete methods that exist on prototype with the same length,
|
||
|
* and which have getters on prototype, but are normal values on the instance.
|
||
|
* This is usually an indication that an autobinding decorator is being used,
|
||
|
* and the getter will re-generate the memoized handler on next access.
|
||
|
*/
|
||
|
function deleteUnknownAutoBindMethods(component) {
|
||
|
var names = Object.getOwnPropertyNames(component);
|
||
|
|
||
|
names.forEach(function (name) {
|
||
|
if (shouldDeleteInstanceMethod(component, name)) {
|
||
|
delete component[name];
|
||
|
}
|
||
|
});
|
||
|
}
|