appjs
Version:
AppJS is a SDK on top of nodejs to develop desktop applications using HTML/CSS/JS
218 lines (194 loc) • 5.69 kB
JavaScript
var decorate = require('./utils').decorate;
var _hasOwn = Object.prototype.hasOwnProperty,
_apply = Function.prototype.apply,
_bind = Function.prototype.bind;
module.exports = {
Ephemeral: Ephemeral,
MirrorHandler: MirrorHandler,
ReferenceType: ReferenceType
};
var ephemerals = new WeakMap;
function Ephemeral(target, data){
this.handler = new MirrorHandler(target);
Object.keys(Object(data)).forEach(function(key){
this[key] = data[key];
}, this);
var proxy = Proxy.create(this.handler, target.__proto__);
ephemerals.set(proxy, this);
return proxy;
}
Ephemeral.unwrap = function unwrap(target){
return ephemerals.get(target);
};
decorate(Ephemeral.prototype, [
function retarget(target){
this.handler.target = target;
},
function morph(handler, data){
this.handler.__proto__ = handler;
Object.keys(Object(data)).forEach(function(key){
this[key] = data[key];
}, this.handler);
},
function unmorph(){
this.handler.__proto__ = MirrorHandler.prototype;
}
]);
function MirrorHandler(target){
this.target = target;
}
decorate(MirrorHandler.prototype, [
function keys(){
return Object.keys(this.target);
},
function enumerate(){
var i=0, k=[];
for (k[i++] in this.target);
return k;
},
function getOwnPropertyNames(){
return Object.getOwnPropertyNames(this.target);
},
function get(rcvr, key){
return this.target[key];
},
function set(rcvr, key, value){
this.target[key] = value;
return true;
},
function has(key){
return key in this.target;
},
function hasOwn(key){
return _hasOwn.call(this.target, key);
},
function delet\u0065(key){
delete this.target[key];
return true;
},
function defineProperty(key, desc){
Object.defineProperty(this.target, key, desc);
return true;
},
function getOwnPropertyDescriptor(key){
var desc = Object.getOwnPropertyDescriptor(this.target, key);
desc && (desc.configurable = true);
return desc;
},
function apply(rcvr, args){
return _apply.call(this.target, rcvr, args);
},
function construct(args){
return new (_bind.apply(this.target, [null].concat(args)));
}
]);
var references = new WeakMap;
function ReferenceType(keys, accessors){
this.accessors = Object.create(null);
this.refKeys = Object.create(null);
if (Array.isArray(keys)) {
this.names = keys;
keys.forEach(function(key){ this[key] = key }, this.refKeys);
} else {
this.names = Object.keys(keys);
this.names.forEach(function(key){ this[key] = keys[key] }, this.refKeys);
}
if (accessors) {
var accessorKeys = Object.keys(accessors);
this.names = this.names.concat(accessorKeys);
accessorKeys.forEach(function(key){
this[key] = Object.getOwnPropertyDescriptor(accessors, key);
}, this.accessors);
}
function ReferenceHandler(reference, target){
this.reference = reference;
this.target = target;
}
ReferenceHandler.prototype = this;
return function Reference(reference){
var proxy = Proxy.create(new ReferenceHandler(reference, this), Reference.prototype);
references.set(proxy, reference);
return proxy;
};
}
ReferenceType.unwrap = function unwrap(target){
return references.get(target);
};
decorate(ReferenceType.prototype, [
function keys(){
return this.names.concat(Object.keys(this.target));
},
function enumerate(){
var i = this.names.length, k = this.names.slice();
for (k[i++] in this.target);
return k;
},
function getOwnPropertyNames(){
return this.names.concat(Object.getOwnPropertyNames(this.target));
},
function get(rcvr, key){
if (key === '__proto__') {
return this.target.__proto__;
} else if (key in this.refKeys) {
return this.reference[this.refKeys[key]];
} else if (key in this.accessors) {
return this.accessors[key].get.call(this.reference);
} else {
return this.target[key];
}
},
function set(rcvr, key, value){
if (key in this.refKeys) {
this.reference[this.refKeys[key]] = value;
} else if (key in this.accessors) {
this.accessors[key].set.call(this.reference, value);
} else {
this.target[key] = value;
}
return true;
},
function has(key){
return key in this.refKeys || key in this.accessors || key in this.target;
},
function hasOwn(key){
return key in this.refKeys || key in this.accessors || _hasOwn.call(this.target, key);
},
function delet\u0065(key){
if (key in this.refKeys) {
delete this.reference[this.refKeys[key]];
} else {
delete this.target[key];
}
return true;
},
function defineProperty(key, desc){
if (key in this.refKeys) {
Object.defineProperty(this.reference, this.refKeys[key], desc);
} else if (key in this.accessors) {
this.accessors[key].set.call(this.reference, desc.value);
} else {
Object.defineProperty(this.target, key, desc);
}
return true;
},
function getOwnPropertyDescriptor(key){
if (key in this.refKeys) {
var desc = Object.getOwnPropertyDescriptor(this.reference, this.refKeys[key]);
} else if (key in this.accessors) {
return {
enumerable: true, configurable: true, writable: true,
value: this.accessors[key].get.call(this.reference)
};
} else {
var desc = Object.getOwnPropertyDescriptor(this.target, key);
}
desc && (desc.configurable = true);
return desc;
},
function apply(rcvr, args){
return _apply.call(this.reference, rcvr, args);
},
function construct(args){
return new (_bind.apply(this.reference, [null].concat(args)));
}
]);