autocreate
Version:
`new`-less classes for ES7/Babel, TypeScript, CoffeeScript, etc.
141 lines (132 loc) • 4.14 kB
JavaScript
(function() {
var auto, copyProps, defProp, getDesc, mkAuto, named,
slice = [].slice,
hasProp = {}.hasOwnProperty;
module.exports = auto = function(cons) {
return mkAuto(cons);
};
mkAuto = function(cons, name, copier) {
var cls, create;
if (name == null) {
name = cons.name;
}
if (copier == null) {
copier = copyProps;
}
if (/^class/.test(cons.toString())) {
cls = copier(cons, named(name, cons, function() {
var args, cc;
args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
if (this instanceof cls || !(cc = cls.prototype.__class_call__)) {
return new (cons.bind.apply(cons, [cons].concat(args)));
} else {
return cc.apply(cls.prototype, arguments);
}
}));
} else {
cls = copier(cons, named(name, cons, function() {
var cc, inst, ret;
if (this instanceof cls) {
return cons.apply(this, arguments);
} else if (cc = cls.prototype.__class_call__) {
return cc.apply(cls.prototype, arguments);
} else {
inst = new create();
ret = cons.apply(inst, arguments);
if (Object(ret) === ret) {
return ret;
} else {
return inst;
}
}
}));
(create = function() {}).prototype = cls.prototype;
}
return cls;
};
getDesc = Object.getOwnPropertyDescriptor;
defProp = Object.defineProperty;
copyProps = function(src, dst) {
var d, i, k, keys, len, ref, ref1, v;
keys = [].concat((ref1 = typeof Object.getOwnPropertyNames === "function" ? Object.getOwnPropertyNames(src) : void 0) != null ? ref1 : []).concat((ref = typeof Object.getOwnPropertySymbols === "function" ? Object.getOwnPropertySymbols(src) : void 0) != null ? ref : []);
if (keys.length && (getDesc != null) && (defProp != null)) {
for (i = 0, len = keys.length; i < len; i++) {
k = keys[i];
d = getDesc(dst, k);
if ((d != null ? d.configurable : void 0) === false) {
if (d.writable) {
dst[k] = src[k];
}
continue;
}
try {
defProp(dst, k, getDesc(src, k));
} catch (_error) {}
}
} else {
for (k in src) {
if (!hasProp.call(src, k)) continue;
v = src[k];
dst[k] = v;
}
dst.prototype = src.prototype;
}
if (dst.__proto__ !== src.__proto__) {
try {
dst.__proto__ = src.__proto__;
} catch (_error) {}
}
dst.prototype.constructor = dst;
return dst;
};
auto.subclass = function(name, base, props) {
if (typeof name === "function") {
props = base;
base = name;
name = base.name;
}
return mkAuto(base, name, function(src, dst) {
dst.prototype = Object.create(base.prototype, props);
dst.prototype.constructor = dst;
dst.__proto__ = src;
return dst;
});
};
named = function(name, src, dst) {
var args, body, i, j, len, prop, ref, ref1, results;
src = {
name: name,
length: src.length
};
ref = ['name', 'length'];
for (i = 0, len = ref.length; i < len; i++) {
prop = ref[i];
if (dst[prop] !== src[prop]) {
try {
dst[prop] = src[prop];
} catch (_error) {}
}
if (dst[prop] !== src[prop]) {
try {
Object.defineProperty(dst, prop, {
value: src[prop]
});
} catch (_error) {}
}
}
if (dst.name !== name || dst.length !== src.length) {
args = "";
if (src.length) {
args = "arg" + (function() {
results = [];
for (var j = 1, ref1 = src.length; 1 <= ref1 ? j <= ref1 : j >= ref1; 1 <= ref1 ? j++ : j--){ results.push(j); }
return results;
}).apply(this).join(', arg');
}
try {
dst = new Function('$$' + name, body = ("return function NAME(" + args + ") {\n return $$NAME.apply(this, arguments);\n}").replace(/NAME/g, name))(dst);
} catch (_error) {}
}
return dst;
};
}).call(this);