inherits-ex
Advanced tools
Comparing version 1.2.2 to 1.2.3
@@ -0,1 +1,3 @@ | ||
var setPrototypeOf = require('./setPrototypeOf'); | ||
var arraySlice = Array.prototype.slice; | ||
@@ -13,4 +15,14 @@ var defineProperty = Object.defineProperty; | ||
} | ||
if (aClass !== aClass.prototype.constructor) | ||
if (aClass !== aClass.prototype.constructor) { | ||
aClass.prototype.constructor.apply(result, arraySlice.call(arguments, 1)); | ||
// try { | ||
// aClass.prototype.constructor.apply(result, arraySlice.call(arguments, 1)); | ||
// } catch(err) { | ||
// if (err instanceof TypeError && err.toString().lastIndexOf("invoked without 'new'") !== -1) { | ||
// result = new aClass.prototype.constructor(...arraySlice.call(arguments, 1)); | ||
// setPrototypeOf(result, aClass.prototype); | ||
// } | ||
// else throw err | ||
// } | ||
} | ||
} | ||
@@ -17,0 +29,0 @@ return result; |
var isEmptyFunction = require('./isEmptyFunction') | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
//get latest non-empty constructor function through inherits link: | ||
@@ -7,6 +10,10 @@ module.exports = function (ctor) { | ||
var isEmpty = isEmptyFunction(result); | ||
while (isEmpty && (result.super_)) { | ||
result = result.super_; | ||
// console.log(result.toString(), isEmpty) | ||
var v = result.super_ || getPrototypeOf(result); | ||
while (isEmpty && v && v !== objectSuperCtor) { | ||
result = v; | ||
v = result.super_ || getPrototypeOf(result); | ||
isEmpty = isEmptyFunction(result); | ||
} | ||
// console.log(result.toString()) | ||
//if (isEmpty) result = null; | ||
@@ -13,0 +20,0 @@ return result; |
(function() { | ||
var getProtoChain; | ||
var getProtoChain, getPrototypeOf, objectSuperCtor; | ||
getPrototypeOf = require('./getPrototypeOf'); | ||
objectSuperCtor = getPrototypeOf(Object); | ||
module.exports = getProtoChain = function(ctor, deepth) { | ||
@@ -15,3 +19,3 @@ var lastCtor, mctors, name, result; | ||
results = []; | ||
while (ctor) { | ||
while (ctor && ctor !== objectSuperCtor) { | ||
if (lastCtor && (mctors = lastCtor.mixinCtors_)) { | ||
@@ -30,3 +34,3 @@ mctors = mctors.map(function(m) { | ||
lastCtor = ctor; | ||
ctor = ctor.super_; | ||
ctor = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
results.push(name); | ||
@@ -33,0 +37,0 @@ } |
var isArray = Array.isArray; | ||
var isInheritedFrom = require('./isInheritedFrom'); | ||
var inheritsDirectly = require('./inheritsDirectly'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
@@ -20,7 +23,7 @@ * Inherit the prototype methods from one constructor into another. | ||
function inherits(ctor, superCtor, staticInherit) { | ||
var v = ctor.super_; | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var mixinCtor = ctor.mixinCtor_; | ||
if (mixinCtor && v === mixinCtor) { | ||
ctor = mixinCtor; | ||
v = ctor.super_; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
} | ||
@@ -30,7 +33,8 @@ var result = false; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
while (v != null && superCtor !== v) { | ||
// patch the missing prototype chain if exists ctor.super. | ||
while (v != null && v !== objectSuperCtor && superCtor !== v) { | ||
ctor = superCtor; | ||
superCtor = v; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
v = ctor.super_; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
} | ||
@@ -37,0 +41,0 @@ result = true; |
@@ -12,4 +12,5 @@ var newPrototype = require('./newPrototype'); | ||
if (staticInherit !== false) { | ||
// NOTE: ES6 use this to keep superCtor. | ||
setPrototypeOf(ctor, superCtor);//additional static inheritance | ||
} | ||
}; |
var isInheritedFromStr = require('./isInheritedFromStr'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
module.exports = function(ctor, superCtor, throwError) { | ||
@@ -11,6 +14,8 @@ if (typeof superCtor === 'string') return isInheritedFromStr(ctor, superCtor, throwError); | ||
} | ||
var result = ctor.super_ === superCtor; | ||
var ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var result = ctorSuper === superCtor; | ||
var checkeds = []; | ||
checkeds.push(ctor); | ||
while (!result && ((ctor = ctor.super_) != null)) { | ||
while (!result && ((ctor = ctorSuper) != null) && ctorSuper !== objectSuperCtor) { | ||
ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
if (checkeds.indexOf(ctor) >= 0) { | ||
@@ -23,3 +28,3 @@ if (throwError) | ||
checkeds.push(ctor); | ||
result = ctor.super_ === superCtor; | ||
result = ctorSuper === superCtor; | ||
} | ||
@@ -26,0 +31,0 @@ if (result) { |
@@ -0,1 +1,3 @@ | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
module.exports = function(ctor, superStr, throwError) { | ||
@@ -8,6 +10,8 @@ if (ctor.name === superStr) { | ||
} | ||
var result = ctor.super_ != null && ctor.super_.name === superStr; | ||
var ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var result = ctorSuper != null && ctorSuper.name === superStr; | ||
var checkeds = []; | ||
checkeds.push(ctor); | ||
while (!result && ((ctor = ctor.super_) != null)) { | ||
while (!result && ((ctor = ctorSuper) != null)) { | ||
ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
if (checkeds.indexOf(ctor) >= 0) { | ||
@@ -20,3 +24,3 @@ if (throwError) | ||
checkeds.push(ctor); | ||
result = ctor.super_ != null && ctor.super_.name === superStr; | ||
result = ctorSuper != null && ctorSuper.name === superStr; | ||
} | ||
@@ -23,0 +27,0 @@ if (result) { |
226
lib/mixin.js
@@ -5,10 +5,31 @@ var inheritsDirectly = require('./inheritsDirectly'); | ||
var defineProperty = require('./defineProperty'); | ||
var setPrototypeOf = require('./setPrototypeOf'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var createCtor = require('./createCtor'); | ||
var extendPrototype = require('./extend'); | ||
var getOwnPropertyNames = Object.getOwnPropertyNames; | ||
var filterOpts = { | ||
'all': 0, | ||
'errSuper': 1, | ||
'skipSuper': 2 | ||
}; | ||
/** | ||
* A11 -> A1 -> A -> Root | ||
* B11 -> B1 -> B -> Root | ||
* C11 -> C1 -> C -> Root | ||
* mixin B11, C1 : inject C to B11. | ||
* TODO: Another Implement: | ||
* B11 -> B1 -> B -> Root -> mixinCtor_ -> C1_Clone -> C -> Root? | ||
* | ||
* mixin B11, A : inject A to B11. | ||
* B11 -> B1 -> B -> Root -> mixinCtor_ -> A_Clone -> C1_Clone -> C -> Root? | ||
*/ | ||
/** | ||
* Mixin multi classes to ctor. | ||
* mixin(Class, ParentClass1, ParentClass2, ...) | ||
* + __mixin_ctors__ array to keep the mixined super ctors | ||
* + anonymous mixin_ctor hook to super_. | ||
* + mixinCtors_ array to keep the mixined super ctors | ||
* + mixinCtor_ inject to the super_ inheritance chain. | ||
* inject into methods to implement inherit. | ||
@@ -19,14 +40,15 @@ * | ||
* C11 -> C1 -> C -> Root | ||
* mixin B11, C | ||
* clone C.prototype to MixinCtor.prototype | ||
* mixin B11, C : inject C to B11. | ||
* clone C.prototype to mixinCtor_.prototype | ||
* * all mixined methods/properties are in `mixinCtor_` | ||
* for k,method of C.prototype | ||
* originalMethod = MixinCtor.prototype[k] | ||
* if isFunction(originalMethod) and originalMethod.__mixin_prototype__ | ||
* #B11.__super__ is MixinCtor.prototype | ||
* originalMethod = mixinCtor_.prototype[k] | ||
* if isFunction(originalMethod) and originalMethod.__mixin_super__ | ||
* #B11.__super__ is mixinCtor_.prototype | ||
* method = -> | ||
* B11.__super__ = originalMethod.__mixin_prototype__ | ||
* B11.__super__ = originalMethod.__mixin_super__ | ||
* method.apply this, arguments | ||
* B11.__super__ = MixinCtor | ||
* method.__mixin_prototype__ = C.prototype | ||
* B11 -> MixinCtor -> B1 -> B -> Root | ||
* B11.__super__ = mixinCtor_ | ||
* method.__mixin_super__ = C.prototype | ||
* B11 -> mixinCtor_ -> B1 -> B -> Root | ||
* | ||
@@ -78,34 +100,153 @@ mixin the exists method: the new mixin method will oerwrite the old one. | ||
/** | ||
* check the function body whether call the super | ||
* | ||
*/ | ||
function isSuperInFunction(aMethod) { | ||
return (typeof aMethod === 'function') && aMethod.__mixin_super__ && | ||
aMethod.toString().indexOf('__super__') >= 0; | ||
var vStr = aMethod.toString(); | ||
return vStr.indexOf('__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
} | ||
// function isSuperInFunction(aMethod) { | ||
// return aMethod.toString().indexOf('__super__') >= 0; | ||
// } | ||
function mixin(ctor, superCtor) { | ||
function clonePrototype(dest, src) { | ||
var sp = src.prototype; | ||
var dp = dest.prototype; | ||
var names = getOwnPropertyNames(sp); | ||
function _mixin_gen_method(origM, newM, src) { | ||
var oldSuper = src.__super__; | ||
return function() { | ||
src.__super__ = origM.__mixin_super__; | ||
var result = newM.apply(this, arguments); | ||
src.__super__ = oldSuper; | ||
return result; | ||
}; | ||
// function isES6SuperInFunction(aMethod) { | ||
// return /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(aMethod.toString()); | ||
// } | ||
//TODO: cant use async function. MUST make chain too. | ||
function _mixinGenMethod(aMixinSuper, aMethod, src) { | ||
var oldSuper = src.__super__; | ||
return function() { | ||
// src.__super__ = aMixinSuper; | ||
console.error('mx', aMixinSuper, 'src', src, 'aMethod', aMethod); | ||
// var oldvar = getPrototypeOf(this); | ||
// setPrototypeOf(this, aMixinSuper); | ||
var result = aMethod.apply(this, arguments); | ||
// setPrototypeOf(this, oldvar); | ||
// src.__super__ = oldSuper; | ||
return result; | ||
}; | ||
} | ||
function _mixinGenMethodES6(aMixinSuper, aMethod, src) { | ||
var oldSuper = getPrototypeOf(src.prototype); | ||
return function() { | ||
setPrototypeOf(src.prototype, aMixinSuper); | ||
var result = aMethod.apply(this, arguments); | ||
setPrototypeOf(src.prototype, oldSuper); | ||
return result; | ||
}; | ||
} | ||
function _getFilterFunc(filter){ | ||
if (!filter) { | ||
filter = function all(name, value){return value}; | ||
} else if (filter === 1) { | ||
filter = function raiseErrorOnSuper(name, value) { | ||
if (typeof value === 'function' && isSuperInFunction(value)) { | ||
throw new Error(name + ' method: should not use super'); | ||
} | ||
return value; | ||
} | ||
for (var i = 1; i < names.length; i++ ) { //i = 1 to skip constructor property | ||
var k = names[i]; | ||
var method = sp[k]; | ||
var originalMethod = dp[k]; | ||
if (isSuperInFunction(originalMethod) && sp !== originalMethod.__mixin_super__) { | ||
method = _mixin_gen_method(originalMethod, method, src); | ||
} else if (filter === 2) { | ||
filter = function skipOnSuper(name, value) { | ||
if (typeof value !== 'function' || !isSuperInFunction(value)) { | ||
return value; | ||
} | ||
if (typeof method === 'function') method.__mixin_super__ = sp; | ||
dp[k] = method; | ||
} | ||
} else if (Array.isArray(filter) && filter.length) { | ||
var inFilter = filter; | ||
filter = function allowedInFilter(name, value) { | ||
if (inFilter.indexOf(name) >= 0) { | ||
return value; | ||
} | ||
} | ||
} else if (typeof filter !== 'function') { | ||
throw new Error('filter option value error:' + filter); | ||
} | ||
var v = ctor.super_; | ||
return filter; | ||
} | ||
//clone src(superCtor) to dest(MixinCtor) | ||
function clonePrototype(dest, src, ctor, filter) { | ||
filter = _getFilterFunc(filter); | ||
var sp = src.prototype; | ||
var dp = dest.prototype; | ||
var names = getOwnPropertyNames(sp); | ||
for (var i = 0; i < names.length; i++ ) { | ||
var k = names[i]; | ||
if (k === 'Class' || k === 'constructor') continue; | ||
var value = filter(k, sp[k]); | ||
// console.log(k, value) | ||
if (value !== void 0) dp[k] = value; | ||
// continue; | ||
// var method = sp[k]; | ||
// var mixinedMethod = dp[k]; // the method is already clone into mixinCtor_ | ||
// just override the property simply. | ||
// if (mixinedMethod !== void 0 && typeof mixinedMethod !== 'function') { | ||
// // Already be defined as property in the mixin ctor | ||
// continue; | ||
// } | ||
// if (typeof method === 'function') { | ||
// console.log(src, k, getProtoChain(dest.chain)) | ||
// if (mixinedMethod && mixinedMethod.__mixin_super__) continue; | ||
// if (isSuperInFunction(method)) { | ||
// console.log('mixined', method) | ||
// method = _mixinGenMethod(dest.chain.__super__, method, src); | ||
// method.__mixin_super__ = true; | ||
// } | ||
// dp[k] = method; | ||
// continue; | ||
// if (mixinedMethod && mixinedMethod.__mixin_super__){ | ||
// if (isSuperInFunction(method)) { | ||
// // pass the last mixin super to control the super's parent. | ||
// // 但是这将导致代码不会在单一类中流转,不过似乎函数复制过来本来就没有继承关系了。 | ||
// // A1->A B1->B C1->C假设 Mixin(B1, [A1,C1]),那么 C1上的方法,本来如果super应该是C | ||
// // 但是应为上次方法复制过来的时候指定了 __mixin_super__ 为 A1,就跳到A1上了。 | ||
// // 不过这个__mixin_super__应该在闭包中,否则会断链。 | ||
// // 又想到了一招,直接构造新的prototype: 形成双根chain,仅当mixin时用这个chain, | ||
// // mixinCtor.chain -> A1CloneCtor -> A1 | ||
// // mixinCtor.chain -> C1CloneCtor -> A1CloneCtor -> A1 | ||
// //method = _mixinGenMethod(mixinedMethod.__mixin_super__, method, src); | ||
// method = _mixinGenMethod(dest.chain, method, src); | ||
// } | ||
// else if (isES6SuperInFunction(method)) { | ||
// method = _mixinGenMethodES6(mixinedMethod.__mixin_super__, method, src); | ||
// } | ||
// } | ||
//last mixin_super of this mixined method. | ||
// method.__mixin_super__ = sp; | ||
// } | ||
// dp[k] = method; | ||
} | ||
} | ||
// function shadowCloneCtor(ctor) { | ||
// var result = createCtor('Clone__' + ctor.name, ''); | ||
// inheritsDirectly(result, ctor); | ||
// return result; | ||
// } | ||
// function findLastClonedCtor(ctor) { | ||
// var result; | ||
// while (ctor && ctor.name.indexOf('Clone__') === 0) { | ||
// result = ctor; | ||
// ctor = ctor.super_; | ||
// } | ||
// return result; | ||
// } | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
function mixin(ctor, superCtor, options) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); // original superCtor | ||
var result = false; | ||
@@ -118,3 +259,8 @@ if (!isMixinedFrom(ctor, superCtor) && !isInheritedFrom(ctor, superCtor) && !isInheritedFrom(superCtor, ctor)) { | ||
defineProperty(ctor, 'mixinCtor_', mixinCtor); | ||
if (v) inheritsDirectly(mixinCtor, v); | ||
if (v && v !== objectSuperCtor) inheritsDirectly(mixinCtor, v); | ||
// defineProperty(mixinCtor, 'chain', shadowCloneCtor(superCtor)); | ||
// inheritsDirectly(mixinCtor.chain, shadowCloneCtor(superCtor)); | ||
// } else { | ||
// var lastChainCtor = findLastClonedCtor(mixinCtor.chain); | ||
// inheritsDirectly(lastChainCtor, shadowCloneCtor(superCtor)); | ||
} | ||
@@ -126,3 +272,3 @@ if (!mixinCtors) { | ||
mixinCtors.push(superCtor);//quickly check in isMixinedFrom. | ||
clonePrototype(mixinCtor, superCtor); | ||
clonePrototype(mixinCtor, superCtor, ctor, options && options.filter); | ||
inheritsDirectly(ctor, mixinCtor); | ||
@@ -134,3 +280,3 @@ result = true; | ||
module.exports = function(ctor, superCtors, options) { | ||
var mixins = module.exports = function(ctor, superCtors, options) { | ||
if (typeof superCtors === 'function') return mixin(ctor, superCtors, options); | ||
@@ -143,1 +289,3 @@ for (var i = 0; i < superCtors.length; i++) { | ||
}; | ||
mixins.filterOpts = filterOpts; |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/snowyu/inherits-ex.js", | ||
"version": "1.2.2", | ||
"version": "1.2.3", | ||
"author": { | ||
@@ -8,0 +8,0 @@ "name": "Riceball LEE", |
@@ -27,2 +27,3 @@ ### Inherits-Ex [![npm](https://img.shields.io/npm/v/inherits-ex.svg)](https://npmjs.org/package/inherits-ex) | ||
+ duplication inheritance check | ||
+ Es6 Class supports | ||
+ more helper functions | ||
@@ -143,4 +144,14 @@ | ||
## mixin(ctor, superCtor|[superCtor, ...]) | ||
## mixin(ctor, superCtor|superCtor[], options:{ filter: number|function}) | ||
* options: | ||
* filter: defaults to 0. | ||
* `0`: copy all properties(methods) | ||
* `1`: raise error if found a method using `super` | ||
* `2`: skip these methods which using `super` | ||
* `string[]`: only name in the array of string will be copied. | ||
* `function(name, value){return value}` the callback function of filter. | ||
* name: the property name | ||
* value: the property value. | ||
```js | ||
@@ -153,22 +164,30 @@ var mixin = require('inherits-ex/lib/mixin') | ||
+ duplication mixin or inheritance check | ||
+ the methods in mixins could super() across mixin classes. | ||
+ **NOTE:**:the methods in mixins using `super()` will jump to the old class(not stay on the class). | ||
* The mixined properties(methods) are cloned(copied) from superCtors | ||
* The all mixined properties(methods) are the first parent's ctor(`MixinCtor_`) | ||
* eg, `ctor -> MixinCtor_ -> original parents` | ||
``` coffee | ||
## Coffee@2.x | ||
mCallOrder = [] | ||
class Root | ||
class C | ||
class C extends Root | ||
m: -> | ||
mCallOrder.push 'C' | ||
super | ||
class A | ||
m: -> | ||
mCallOrder.push 'A' | ||
class A1 | ||
class A1 extends A | ||
m: -> | ||
mCallOrder.push 'A1' | ||
super | ||
class B | ||
inherits B, Root | ||
class B1 | ||
class B1 extends B | ||
m: -> | ||
@@ -178,11 +197,8 @@ mCallOrder.push 'B1' | ||
inherits(C, Root).should.be.equal true, "C should inherits from Root" | ||
inherits(B1, B).should.be.equal true, "B1 should inherits from B" | ||
inherits(A1, A).should.be.equal true, "A1 should inherits from A" | ||
mixin(B1, [A1, C]).should.be.equal true, 'mixin' | ||
o = new B1() | ||
o.m("a", 12) # call chain: B1::m -> C::m -> A1::m -> A::m | ||
o.m("a", 12) # call chain: B1::m -> C::m | ||
A::m.should.have.been.calledOnce | ||
A::m.should.have.been.calledWith "a", 12 | ||
mCallOrder.should.be.deep.equal ['B1', 'C', 'A1', 'A'] | ||
mCallOrder.should.be.deep.equal ['B1', 'C'] | ||
``` | ||
@@ -207,2 +223,4 @@ | ||
NOTE: DO NOT SUPPORT ES6 Class | ||
### usage | ||
@@ -234,2 +252,5 @@ | ||
NOTE: DO NOT SUPPORT ES6 Class | ||
## createFunction(name, [args,] body[, scope[, values]]) | ||
@@ -236,0 +257,0 @@ |
@@ -0,1 +1,3 @@ | ||
var setPrototypeOf = require('./setPrototypeOf'); | ||
var arraySlice = Array.prototype.slice; | ||
@@ -13,4 +15,14 @@ var defineProperty = Object.defineProperty; | ||
} | ||
if (aClass !== aClass.prototype.constructor) | ||
if (aClass !== aClass.prototype.constructor) { | ||
aClass.prototype.constructor.apply(result, arraySlice.call(arguments, 1)); | ||
// try { | ||
// aClass.prototype.constructor.apply(result, arraySlice.call(arguments, 1)); | ||
// } catch(err) { | ||
// if (err instanceof TypeError && err.toString().lastIndexOf("invoked without 'new'") !== -1) { | ||
// result = new aClass.prototype.constructor(...arraySlice.call(arguments, 1)); | ||
// setPrototypeOf(result, aClass.prototype); | ||
// } | ||
// else throw err | ||
// } | ||
} | ||
} | ||
@@ -17,0 +29,0 @@ return result; |
var isEmptyFunction = require('./isEmptyFunction') | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
//get latest non-empty constructor function through inherits link: | ||
@@ -7,6 +10,10 @@ module.exports = function (ctor) { | ||
var isEmpty = isEmptyFunction(result); | ||
while (isEmpty && (result.super_)) { | ||
result = result.super_; | ||
// console.log(result.toString(), isEmpty) | ||
var v = result.super_ || getPrototypeOf(result); | ||
while (isEmpty && v && v !== objectSuperCtor) { | ||
result = v; | ||
v = result.super_ || getPrototypeOf(result); | ||
isEmpty = isEmptyFunction(result); | ||
} | ||
// console.log(result.toString()) | ||
//if (isEmpty) result = null; | ||
@@ -13,0 +20,0 @@ return result; |
var isArray = Array.isArray; | ||
var isInheritedFrom = require('./isInheritedFrom'); | ||
var inheritsDirectly = require('./inheritsDirectly'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
/** | ||
@@ -20,7 +23,7 @@ * Inherit the prototype methods from one constructor into another. | ||
function inherits(ctor, superCtor, staticInherit) { | ||
var v = ctor.super_; | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var mixinCtor = ctor.mixinCtor_; | ||
if (mixinCtor && v === mixinCtor) { | ||
ctor = mixinCtor; | ||
v = ctor.super_; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
} | ||
@@ -30,7 +33,8 @@ var result = false; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
while (v != null && superCtor !== v) { | ||
// patch the missing prototype chain if exists ctor.super. | ||
while (v != null && v !== objectSuperCtor && superCtor !== v) { | ||
ctor = superCtor; | ||
superCtor = v; | ||
inheritsDirectly(ctor, superCtor, staticInherit); | ||
v = ctor.super_; | ||
v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
} | ||
@@ -37,0 +41,0 @@ result = true; |
@@ -12,4 +12,5 @@ var newPrototype = require('./newPrototype'); | ||
if (staticInherit !== false) { | ||
// NOTE: ES6 use this to keep superCtor. | ||
setPrototypeOf(ctor, superCtor);//additional static inheritance | ||
} | ||
}; |
var isInheritedFromStr = require('./isInheritedFromStr'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
module.exports = function(ctor, superCtor, throwError) { | ||
@@ -11,6 +14,8 @@ if (typeof superCtor === 'string') return isInheritedFromStr(ctor, superCtor, throwError); | ||
} | ||
var result = ctor.super_ === superCtor; | ||
var ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var result = ctorSuper === superCtor; | ||
var checkeds = []; | ||
checkeds.push(ctor); | ||
while (!result && ((ctor = ctor.super_) != null)) { | ||
while (!result && ((ctor = ctorSuper) != null) && ctorSuper !== objectSuperCtor) { | ||
ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
if (checkeds.indexOf(ctor) >= 0) { | ||
@@ -23,3 +28,3 @@ if (throwError) | ||
checkeds.push(ctor); | ||
result = ctor.super_ === superCtor; | ||
result = ctorSuper === superCtor; | ||
} | ||
@@ -26,0 +31,0 @@ if (result) { |
@@ -0,1 +1,3 @@ | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
module.exports = function(ctor, superStr, throwError) { | ||
@@ -8,6 +10,8 @@ if (ctor.name === superStr) { | ||
} | ||
var result = ctor.super_ != null && ctor.super_.name === superStr; | ||
var ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
var result = ctorSuper != null && ctorSuper.name === superStr; | ||
var checkeds = []; | ||
checkeds.push(ctor); | ||
while (!result && ((ctor = ctor.super_) != null)) { | ||
while (!result && ((ctor = ctorSuper) != null)) { | ||
ctorSuper = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); | ||
if (checkeds.indexOf(ctor) >= 0) { | ||
@@ -20,3 +24,3 @@ if (throwError) | ||
checkeds.push(ctor); | ||
result = ctor.super_ != null && ctor.super_.name === superStr; | ||
result = ctorSuper != null && ctorSuper.name === superStr; | ||
} | ||
@@ -23,0 +27,0 @@ if (result) { |
226
src/mixin.js
@@ -5,10 +5,31 @@ var inheritsDirectly = require('./inheritsDirectly'); | ||
var defineProperty = require('./defineProperty'); | ||
var setPrototypeOf = require('./setPrototypeOf'); | ||
var getPrototypeOf = require('./getPrototypeOf'); | ||
var createCtor = require('./createCtor'); | ||
var extendPrototype = require('./extend'); | ||
var getOwnPropertyNames = Object.getOwnPropertyNames; | ||
var filterOpts = { | ||
'all': 0, | ||
'errSuper': 1, | ||
'skipSuper': 2 | ||
}; | ||
/** | ||
* A11 -> A1 -> A -> Root | ||
* B11 -> B1 -> B -> Root | ||
* C11 -> C1 -> C -> Root | ||
* mixin B11, C1 : inject C to B11. | ||
* TODO: Another Implement: | ||
* B11 -> B1 -> B -> Root -> mixinCtor_ -> C1_Clone -> C -> Root? | ||
* | ||
* mixin B11, A : inject A to B11. | ||
* B11 -> B1 -> B -> Root -> mixinCtor_ -> A_Clone -> C1_Clone -> C -> Root? | ||
*/ | ||
/** | ||
* Mixin multi classes to ctor. | ||
* mixin(Class, ParentClass1, ParentClass2, ...) | ||
* + __mixin_ctors__ array to keep the mixined super ctors | ||
* + anonymous mixin_ctor hook to super_. | ||
* + mixinCtors_ array to keep the mixined super ctors | ||
* + mixinCtor_ inject to the super_ inheritance chain. | ||
* inject into methods to implement inherit. | ||
@@ -19,14 +40,15 @@ * | ||
* C11 -> C1 -> C -> Root | ||
* mixin B11, C | ||
* clone C.prototype to MixinCtor.prototype | ||
* mixin B11, C : inject C to B11. | ||
* clone C.prototype to mixinCtor_.prototype | ||
* * all mixined methods/properties are in `mixinCtor_` | ||
* for k,method of C.prototype | ||
* originalMethod = MixinCtor.prototype[k] | ||
* if isFunction(originalMethod) and originalMethod.__mixin_prototype__ | ||
* #B11.__super__ is MixinCtor.prototype | ||
* originalMethod = mixinCtor_.prototype[k] | ||
* if isFunction(originalMethod) and originalMethod.__mixin_super__ | ||
* #B11.__super__ is mixinCtor_.prototype | ||
* method = -> | ||
* B11.__super__ = originalMethod.__mixin_prototype__ | ||
* B11.__super__ = originalMethod.__mixin_super__ | ||
* method.apply this, arguments | ||
* B11.__super__ = MixinCtor | ||
* method.__mixin_prototype__ = C.prototype | ||
* B11 -> MixinCtor -> B1 -> B -> Root | ||
* B11.__super__ = mixinCtor_ | ||
* method.__mixin_super__ = C.prototype | ||
* B11 -> mixinCtor_ -> B1 -> B -> Root | ||
* | ||
@@ -78,34 +100,153 @@ mixin the exists method: the new mixin method will oerwrite the old one. | ||
/** | ||
* check the function body whether call the super | ||
* | ||
*/ | ||
function isSuperInFunction(aMethod) { | ||
return (typeof aMethod === 'function') && aMethod.__mixin_super__ && | ||
aMethod.toString().indexOf('__super__') >= 0; | ||
var vStr = aMethod.toString(); | ||
return vStr.indexOf('__super__') >= 0 || /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(vStr); | ||
} | ||
// function isSuperInFunction(aMethod) { | ||
// return aMethod.toString().indexOf('__super__') >= 0; | ||
// } | ||
function mixin(ctor, superCtor) { | ||
function clonePrototype(dest, src) { | ||
var sp = src.prototype; | ||
var dp = dest.prototype; | ||
var names = getOwnPropertyNames(sp); | ||
function _mixin_gen_method(origM, newM, src) { | ||
var oldSuper = src.__super__; | ||
return function() { | ||
src.__super__ = origM.__mixin_super__; | ||
var result = newM.apply(this, arguments); | ||
src.__super__ = oldSuper; | ||
return result; | ||
}; | ||
// function isES6SuperInFunction(aMethod) { | ||
// return /(\s+|^|[;(\[])super[(]|super[.]\S+[(]/.test(aMethod.toString()); | ||
// } | ||
//TODO: cant use async function. MUST make chain too. | ||
function _mixinGenMethod(aMixinSuper, aMethod, src) { | ||
var oldSuper = src.__super__; | ||
return function() { | ||
// src.__super__ = aMixinSuper; | ||
console.error('mx', aMixinSuper, 'src', src, 'aMethod', aMethod); | ||
// var oldvar = getPrototypeOf(this); | ||
// setPrototypeOf(this, aMixinSuper); | ||
var result = aMethod.apply(this, arguments); | ||
// setPrototypeOf(this, oldvar); | ||
// src.__super__ = oldSuper; | ||
return result; | ||
}; | ||
} | ||
function _mixinGenMethodES6(aMixinSuper, aMethod, src) { | ||
var oldSuper = getPrototypeOf(src.prototype); | ||
return function() { | ||
setPrototypeOf(src.prototype, aMixinSuper); | ||
var result = aMethod.apply(this, arguments); | ||
setPrototypeOf(src.prototype, oldSuper); | ||
return result; | ||
}; | ||
} | ||
function _getFilterFunc(filter){ | ||
if (!filter) { | ||
filter = function all(name, value){return value}; | ||
} else if (filter === 1) { | ||
filter = function raiseErrorOnSuper(name, value) { | ||
if (typeof value === 'function' && isSuperInFunction(value)) { | ||
throw new Error(name + ' method: should not use super'); | ||
} | ||
return value; | ||
} | ||
for (var i = 1; i < names.length; i++ ) { //i = 1 to skip constructor property | ||
var k = names[i]; | ||
var method = sp[k]; | ||
var originalMethod = dp[k]; | ||
if (isSuperInFunction(originalMethod) && sp !== originalMethod.__mixin_super__) { | ||
method = _mixin_gen_method(originalMethod, method, src); | ||
} else if (filter === 2) { | ||
filter = function skipOnSuper(name, value) { | ||
if (typeof value !== 'function' || !isSuperInFunction(value)) { | ||
return value; | ||
} | ||
if (typeof method === 'function') method.__mixin_super__ = sp; | ||
dp[k] = method; | ||
} | ||
} else if (Array.isArray(filter) && filter.length) { | ||
var inFilter = filter; | ||
filter = function allowedInFilter(name, value) { | ||
if (inFilter.indexOf(name) >= 0) { | ||
return value; | ||
} | ||
} | ||
} else if (typeof filter !== 'function') { | ||
throw new Error('filter option value error:' + filter); | ||
} | ||
var v = ctor.super_; | ||
return filter; | ||
} | ||
//clone src(superCtor) to dest(MixinCtor) | ||
function clonePrototype(dest, src, ctor, filter) { | ||
filter = _getFilterFunc(filter); | ||
var sp = src.prototype; | ||
var dp = dest.prototype; | ||
var names = getOwnPropertyNames(sp); | ||
for (var i = 0; i < names.length; i++ ) { | ||
var k = names[i]; | ||
if (k === 'Class' || k === 'constructor') continue; | ||
var value = filter(k, sp[k]); | ||
// console.log(k, value) | ||
if (value !== void 0) dp[k] = value; | ||
// continue; | ||
// var method = sp[k]; | ||
// var mixinedMethod = dp[k]; // the method is already clone into mixinCtor_ | ||
// just override the property simply. | ||
// if (mixinedMethod !== void 0 && typeof mixinedMethod !== 'function') { | ||
// // Already be defined as property in the mixin ctor | ||
// continue; | ||
// } | ||
// if (typeof method === 'function') { | ||
// console.log(src, k, getProtoChain(dest.chain)) | ||
// if (mixinedMethod && mixinedMethod.__mixin_super__) continue; | ||
// if (isSuperInFunction(method)) { | ||
// console.log('mixined', method) | ||
// method = _mixinGenMethod(dest.chain.__super__, method, src); | ||
// method.__mixin_super__ = true; | ||
// } | ||
// dp[k] = method; | ||
// continue; | ||
// if (mixinedMethod && mixinedMethod.__mixin_super__){ | ||
// if (isSuperInFunction(method)) { | ||
// // pass the last mixin super to control the super's parent. | ||
// // 但是这将导致代码不会在单一类中流转,不过似乎函数复制过来本来就没有继承关系了。 | ||
// // A1->A B1->B C1->C假设 Mixin(B1, [A1,C1]),那么 C1上的方法,本来如果super应该是C | ||
// // 但是应为上次方法复制过来的时候指定了 __mixin_super__ 为 A1,就跳到A1上了。 | ||
// // 不过这个__mixin_super__应该在闭包中,否则会断链。 | ||
// // 又想到了一招,直接构造新的prototype: 形成双根chain,仅当mixin时用这个chain, | ||
// // mixinCtor.chain -> A1CloneCtor -> A1 | ||
// // mixinCtor.chain -> C1CloneCtor -> A1CloneCtor -> A1 | ||
// //method = _mixinGenMethod(mixinedMethod.__mixin_super__, method, src); | ||
// method = _mixinGenMethod(dest.chain, method, src); | ||
// } | ||
// else if (isES6SuperInFunction(method)) { | ||
// method = _mixinGenMethodES6(mixinedMethod.__mixin_super__, method, src); | ||
// } | ||
// } | ||
//last mixin_super of this mixined method. | ||
// method.__mixin_super__ = sp; | ||
// } | ||
// dp[k] = method; | ||
} | ||
} | ||
// function shadowCloneCtor(ctor) { | ||
// var result = createCtor('Clone__' + ctor.name, ''); | ||
// inheritsDirectly(result, ctor); | ||
// return result; | ||
// } | ||
// function findLastClonedCtor(ctor) { | ||
// var result; | ||
// while (ctor && ctor.name.indexOf('Clone__') === 0) { | ||
// result = ctor; | ||
// ctor = ctor.super_; | ||
// } | ||
// return result; | ||
// } | ||
var objectSuperCtor = getPrototypeOf(Object); | ||
function mixin(ctor, superCtor, options) { | ||
var v = (ctor.hasOwnProperty('super_') && ctor.super_) || getPrototypeOf(ctor); // original superCtor | ||
var result = false; | ||
@@ -118,3 +259,8 @@ if (!isMixinedFrom(ctor, superCtor) && !isInheritedFrom(ctor, superCtor) && !isInheritedFrom(superCtor, ctor)) { | ||
defineProperty(ctor, 'mixinCtor_', mixinCtor); | ||
if (v) inheritsDirectly(mixinCtor, v); | ||
if (v && v !== objectSuperCtor) inheritsDirectly(mixinCtor, v); | ||
// defineProperty(mixinCtor, 'chain', shadowCloneCtor(superCtor)); | ||
// inheritsDirectly(mixinCtor.chain, shadowCloneCtor(superCtor)); | ||
// } else { | ||
// var lastChainCtor = findLastClonedCtor(mixinCtor.chain); | ||
// inheritsDirectly(lastChainCtor, shadowCloneCtor(superCtor)); | ||
} | ||
@@ -126,3 +272,3 @@ if (!mixinCtors) { | ||
mixinCtors.push(superCtor);//quickly check in isMixinedFrom. | ||
clonePrototype(mixinCtor, superCtor); | ||
clonePrototype(mixinCtor, superCtor, ctor, options && options.filter); | ||
inheritsDirectly(ctor, mixinCtor); | ||
@@ -134,3 +280,3 @@ result = true; | ||
module.exports = function(ctor, superCtors, options) { | ||
var mixins = module.exports = function(ctor, superCtors, options) { | ||
if (typeof superCtors === 'function') return mixin(ctor, superCtors, options); | ||
@@ -143,1 +289,3 @@ for (var i = 0; i < superCtors.length; i++) { | ||
}; | ||
mixins.filterOpts = filterOpts; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
110837
79
1849
285
2