import { isFunction } from '../lib/typeof.js';

/**
 * A list of HTMLElement properties to proxy from the node to the component instance.
 * @type Array
 * @private
 */
const DOM_PROXY = [
    'attributes',
    'classList',
    'getAttribute',
    'hasAttribute',
    'setAttribute',
    'removeAttribute',
    'addEventListener',
    'removeEventListener',
    'dispatchEvent',
    'style',
    'querySelector',
    'querySelectorAll',
    'shadowRoot',
    'attachShadow',
    'createShadowRoot',
];

/**
 * Reference to Element prototype.
 * @type Object
 * @private
 */
const ELEMENT_PROTOTYPE = Element.prototype;

/**
 * Reference to Node prototype.
 * @type Object
 * @private
 */
function checkNode() {
    if (!this.node) {
        throw new ReferenceError('The component\'s `node` is undefined.');
    }
}

/**
 * Add a proxy property descriptor to a prototype.
 * @private
 *
 * @param {Object} proto The prototype to update.
 * @param {String} property The property name to proxy.
 */
function proxyProperty(proto, property) {
    let desc = {};
    let propDescriptor = Object.getOwnPropertyDescriptor(ELEMENT_PROTOTYPE, property);
    let hasProp = !!propDescriptor;
    let isFn = hasProp && isFunction(propDescriptor.value);
    if (isFn || (!hasProp && typeof ELEMENT_PROTOTYPE[property] === 'function')) {
        desc.value = function(...args) {
            checkNode.call(this);
            return this.node[property].call(this.node, ...args);
        };
    } else if (hasProp) {
        desc.get = function() {
            checkNode.call(this);
            return this.node[property];
        };
        desc.set = function(val) {
            checkNode.call(this);
            return this.node[property] = val;
        };
    }
    Object.defineProperty(proto, property, desc);
}

/**
 * Add HTMLElement properties and methods proxies to a prototype.
 * @method proxy
 * @memberof DNA
 *
 * @param {Function} Component The component class to proxy.
 * @return {Function} The updated class.
 */
export function proxy(Component) {
    DOM_PROXY.forEach((prop) => {
        proxyProperty(Component.prototype, prop);
    });
    return Component;
}

@@ -1,52 +1,4 @@
-import %7B isFunction %7D from '../lib/typeof.js';%0A%0A
 /**%0A
@@ -136,15 +136,14 @@
 Y = 
-%5B
+%7B
 %0A    
-'
 attr
@@ -148,24 +148,25 @@
 tributes
-'
+: 1
 ,%0A    
-'
 classLis
@@ -166,24 +166,25 @@
 lassList
-'
+: 1
 ,%0A    
-'
 getAttri
@@ -187,24 +187,25 @@
 ttribute
-'
+: 0
 ,%0A    
-'
 hasAttri
@@ -208,24 +208,25 @@
 ttribute
-'
+: 0
 ,%0A    
-'
 setAttri
@@ -229,24 +229,25 @@
 ttribute
-'
+: 0
 ,%0A    
-'
 removeAt
@@ -253,24 +253,25 @@
 ttribute
-'
+: 0
 ,%0A    
-'
 addEvent
@@ -278,24 +278,25 @@
 Listener
-'
+: 0
 ,%0A    
-'
 removeEv
@@ -306,24 +306,25 @@
 Listener
-'
+: 0
 ,%0A    
-'
 dispatch
@@ -332,29 +332,31 @@
 vent
-'
+: 0
 ,%0A    
-'
 style
-'
+: 1
 ,%0A    
-'
 quer
@@ -364,24 +364,25 @@
 Selector
-'
+: 0
 ,%0A    
-'
 querySel
@@ -389,24 +389,25 @@
 ectorAll
-'
+: 0
 ,%0A    
-'
 shadowRo
@@ -408,24 +408,25 @@
 adowRoot
-'
+: 1
 ,%0A    
-'
 attachSh
@@ -433,16 +433,17 @@
 adow
-'
+: 0
 ,%0A    
-'
 crea
@@ -458,129 +458,14 @@
 Root
-',%0A%5D;%0A%0A/**%0A * Reference to Element prototype.%0A * @type Object%0A * @private%0A */%0Aconst ELEMENT_PROTOTYPE = Element.prototype
+: 0,%0A%7D
 ;%0A%0A/
@@ -842,333 +842,174 @@
 .%0A *
-/%0Afunction proxyProperty(proto, property) %7B%0A    let desc = %7B%7D;%0A    let propDescriptor = Object.getOwnPropertyDescriptor(ELEMENT_PROTOTYPE, property);%0A    let hasProp = !!propDescriptor;%0A    let isFn = hasProp && isFunction(propDescriptor.value);%0A    if (isFn %7C%7C (!hasProp && typeof ELEMENT_PROTOTYPE%5Bproperty%5D === 'function')
+ @param %7BNumber%7D type The property type (0: function, 1: getter, 2: setter).%0A */%0Afunction proxyProperty(proto, property, type) %7B%0A    let desc = %7B%7D;%0A    if (type === 0
 ) %7B%0A
@@ -1178,15 +1178,16 @@
 if (
-hasProp
+type %3E 0
 ) %7B%0A
@@ -1299,24 +1299,52 @@
 %0A        %7D;%0A
+        if (type %3E 2) %7B%0A    
         desc
@@ -1362,24 +1362,28 @@
 tion(val) %7B%0A
+    
             
@@ -1408,32 +1408,36 @@
 s);%0A            
+    
 return this.node
@@ -1458,26 +1458,40 @@
 al;%0A        
+  
+  %7D;%0A        
 %7D
-;
 %0A    %7D%0A    O
@@ -1794,35 +1794,32 @@
     
-DOM_PROXY.forEach((prop) =%3E
+for (let k in DOM_PROXY)
  %7B%0A 
@@ -1864,20 +1864,31 @@
 pe, 
-prop
+k, DOM_PROXY%5Bk%5D
 );%0A    %7D
 );%0A 
@@ -1883,18 +1883,16 @@
 );%0A    %7D
-);
 %0A    ret

improve proxy function