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];
 | |
|     }
 | |
|   });
 | |
| } |