module.exports =
We accept a base prototype to wrap and a set of additional base classes to inherit from.
(obj, Bases...) ->
For each of our base classes, we take their prototype, since that is what we actually want to inherit from. They are preceded by the original base prototype.
bases = [obj, (Base.prototype for Base in Bases)...]
We instantiate an ES6 proxy, which will be our new, wrapped prototype.
return proxy = Proxy.create
When a property descriptor is requested, we iterate through our base prototypes to find it.
getPropertyDescriptor: (name) ->
for base in bases
return prop if prop = Object.getPropertyDescriptor base, name
The set of property names of the wrapped prototype is simply the union of the property names of all our base prototypes.
getPropertyNames: ->
names = []
for base in bases
names.push name for name in Object.getPropertyNames base when name not in names
return names
Access to own properties is simply forwarded.
getOwnPropertyDescriptor: (name) ->
Object.getOwnPropertyDescriptor obj, name
getOwnPropertyNames: ->
Object.getOwnPropertyNames obj
defineProperty: (name, prop) ->
Object.defineProperty obj, name, prop
return proxy
delete: (name) ->
delete obj[name]
fix: ->
return if not Object.isFrozen obj
result = {}
result[name] = Object.getOwnPropertyDescriptor obj, name for name in Object.getOwnPropertyNames obj
return result
Since some ES6 convenience methods are not available in ES5, we polyfill them.
To find a property descriptor, we simply walk up the prototype tree until we find it.
Object.getPropertyDescriptor ||= (obj, name) ->
while obj
return prop if prop = Object.getOwnPropertyDescriptor obj, name
obj = Object.getPrototypeOf obj
The set of property names of an object is simply the union of all own property names of the object and its prototype chain.
Object.getPropertyNames ||= (obj) ->
names = []
while obj
names.push name for name in Object.getOwnPropertyNames obj, name when name not in names
obj = Object.getPrototypeOf obj
return names