custom-ability
Advanced tools
Comparing version 1.6.2 to 2.0.0-alpha.0
@@ -1,209 +0,233 @@ | ||
(function() { | ||
'use strict'; | ||
var defineProperty, extend, extendFilter, getNonEnumNames, injectMethod, injectMethods, injectMethodsFromNonEnum, isArray, isBoolean, isFunction, isInjectedOnParent, | ||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; | ||
isArray = require('util-ex/lib/is/type/array'); | ||
isFunction = require('util-ex/lib/is/type/function'); | ||
isBoolean = require('util-ex/lib/is/type/boolean'); | ||
extend = require('util-ex/lib/_extend'); | ||
extendFilter = require('util-ex/lib/extend'); | ||
injectMethods = require('util-ex/lib/injectMethods'); | ||
injectMethod = require('util-ex/lib/injectMethod'); | ||
defineProperty = require('util-ex/lib/defineProperty'); | ||
getNonEnumNames = require('util-ex/lib/get-non-enumerable-names'); | ||
isInjectedOnParent = require('./injected-on-parent'); | ||
injectMethodsFromNonEnum = function(aTargetClass, aObject, filter, isStatic) { | ||
var nonEnumNames, result; | ||
nonEnumNames = getNonEnumNames(aObject); | ||
result = []; | ||
nonEnumNames.forEach(function(k) { | ||
var is$, v, vK; | ||
if ((isStatic || k !== 'constructor') && isFunction(v = aObject[k])) { | ||
is$ = k[0] === '$'; | ||
if (is$) { | ||
k = k.substr(1); | ||
} | ||
vK = isStatic ? '@' + k : k; | ||
if (!filter || filter(vK)) { | ||
if (isFunction(aTargetClass[k])) { | ||
injectMethod(aTargetClass, k, v); | ||
} else if (aTargetClass[k] != null) { | ||
throw new TypeError('the same non-null name is not function:' + k); | ||
} else { | ||
if (is$ && aObject[k]) { | ||
v = aObject[k]; | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createAbilityInjector = void 0; | ||
const array_1 = __importDefault(require("util-ex/lib/is/type/array")); | ||
const function_1 = __importDefault(require("util-ex/lib/is/type/function")); | ||
const extend_1 = __importDefault(require("util-ex/lib/extend")); | ||
const injectMethods_1 = __importDefault(require("util-ex/lib/injectMethods")); | ||
const injectMethod_1 = __importDefault(require("util-ex/lib/injectMethod")); | ||
const defineProperty_1 = __importDefault(require("util-ex/lib/defineProperty")); | ||
const get_non_enumerable_names_1 = require("util-ex/lib/get-non-enumerable-names"); | ||
const injected_on_parent_1 = __importDefault(require("./injected-on-parent")); | ||
/** | ||
* Inject methods from NonEnum members of the aObject | ||
* | ||
* @internal | ||
* @param aTargetClass the target class | ||
* @param aObject the NonEnum methods of the object will be injected into aTargetClass | ||
* @param filter | ||
* @param isStatic Whether the injected methods on the aObject is static | ||
* @returns already injected method name list | ||
*/ | ||
function injectMethodsFromNonEnum(aTargetClass, aObject, filter, isStatic) { | ||
const nonEnumNames = (0, get_non_enumerable_names_1.getNonEnumerableNames)(aObject); | ||
const result = []; | ||
nonEnumNames.forEach(function (name) { | ||
let v, vName; | ||
if ((isStatic || name !== 'constructor') && (0, function_1.default)(v = aObject[name])) { | ||
const is$ = name[0] === '$'; | ||
// get rid of the first char '$' | ||
if (is$) { | ||
name = name.substring(1); | ||
} | ||
aTargetClass[k] = v; | ||
} | ||
result.push(k); | ||
vName = isStatic ? '@' + name : name; | ||
if (!filter || filter(vName)) { | ||
if ((0, function_1.default)(aTargetClass[name])) { | ||
(0, injectMethod_1.default)(aTargetClass, name, v); | ||
} | ||
else if (aTargetClass[name] != null) { | ||
throw new TypeError('the same non-null name is not function:' + name); | ||
} | ||
else { | ||
if (is$ && aObject[name]) { | ||
v = aObject[name]; | ||
} | ||
aTargetClass[name] = v; | ||
} | ||
result.push(name); | ||
} | ||
} | ||
} | ||
}); | ||
return result; | ||
}; | ||
module.exports = function(abilityClass, aCoreMethod, isGetClassFunc) { | ||
var abilityFn, filter, getAdditionalAbility, injectAdditionalAbility; | ||
if (isBoolean(aCoreMethod)) { | ||
isGetClassFunc = aCoreMethod; | ||
aCoreMethod = void 0; | ||
} | ||
; | ||
/** | ||
* Creates a function that adds(injects) the ability to the target class based on the ability class. | ||
* | ||
* @param abilityClass The ability class to inject into the target class. | ||
* @param aCoreMethod An optional parameter that specifies the core methods that the ability class must have. | ||
* This is a minimum set of methods required for the ability to be considered injected. | ||
* Core methods are defined in the ability class, and can be static or instance methods. | ||
* If a core method is a static method, it must be prefixed with the "@" symbol. | ||
* @param isGetClassFunc An optional parameter that indicates whether abilityClass should be invoked | ||
* with aClass and aOptions to get the actual ability class. defaults to false | ||
* @returns Another function that accepts the target class and options to include or exclude specific | ||
* properties and methods. | ||
* The returned function injects the abilities into the target class and returns the modified class. | ||
*/ | ||
function createAbilityInjector(abilityClass, aCoreMethod, isGetClassFunc) { | ||
if (typeof aCoreMethod === 'boolean') { | ||
isGetClassFunc = aCoreMethod; | ||
aCoreMethod = undefined; | ||
} | ||
abilityFn = function(aClass, aOptions) { | ||
var $abilities, AbilityClass, aClassPrototype, filterMethods, vAbilities, vAddtionalAbilityInjected, vExcludes, vFilter, vIncludes, vInjectedOnParent, vName, vhasCoreMethod; | ||
AbilityClass = abilityClass; | ||
if (isGetClassFunc === true) { | ||
AbilityClass = abilityClass(aClass, aOptions); | ||
} | ||
if (!AbilityClass) { | ||
throw new TypeError('no abilityClass'); | ||
} | ||
vName = AbilityClass.name; | ||
if (aClass != null) { | ||
aClassPrototype = aClass.prototype; | ||
vhasCoreMethod = isArray(aCoreMethod) ? aCoreMethod[0] : aCoreMethod; | ||
if (vhasCoreMethod) { | ||
if (vhasCoreMethod[0] !== '@') { | ||
vhasCoreMethod = aClassPrototype.hasOwnProperty(vhasCoreMethod); | ||
} else { | ||
vhasCoreMethod = vhasCoreMethod.substr(1); | ||
vhasCoreMethod = aClass.hasOwnProperty(vhasCoreMethod); | ||
} | ||
function abilityFn(aClass, aOptions) { | ||
let AbilityClass = abilityClass; | ||
if (isGetClassFunc === true) { | ||
AbilityClass = abilityClass(aClass, aOptions); | ||
} | ||
if (vName) { | ||
$abilities = aClass.prototype.$abilities; | ||
vInjectedOnParent = isInjectedOnParent(aClass, vName); | ||
if (!aClass.prototype.hasOwnProperty('$abilities')) { | ||
$abilities = null; | ||
} | ||
if (!AbilityClass) { | ||
throw new TypeError('no abilityClass'); | ||
} | ||
if (!(vhasCoreMethod || ($abilities && $abilities['$' + vName]))) { | ||
if ((aOptions == null) || !(aOptions.include || aOptions.exclude)) { | ||
const vName = AbilityClass.name; | ||
if (aClass != null) { | ||
let $abilities, vAdditionalAbilityInjected, vExcludes, vIncludes, vInjectedOnParent; | ||
let aClassPrototype = aClass.prototype; | ||
let vHasCoreMethod = (0, array_1.default)(aCoreMethod) ? aCoreMethod[0] : aCoreMethod; | ||
if (vHasCoreMethod) { | ||
if (vHasCoreMethod[0] !== '@') { | ||
vHasCoreMethod = aClassPrototype.hasOwnProperty(vHasCoreMethod); | ||
} | ||
else { | ||
vHasCoreMethod = vHasCoreMethod.substring(1); | ||
vHasCoreMethod = aClass.hasOwnProperty(vHasCoreMethod); | ||
} | ||
} | ||
if (vName) { | ||
vAddtionalAbilityInjected = injectAdditionalAbility(aClass, vName, filterMethods); | ||
$abilities = aClass.prototype.$abilities; | ||
vInjectedOnParent = (0, injected_on_parent_1.default)(aClass, vName); | ||
if (!aClass.prototype.hasOwnProperty('$abilities')) { | ||
$abilities = null; | ||
} | ||
} | ||
vExcludes = injectMethodsFromNonEnum(aClass, AbilityClass, null, true); | ||
extendFilter(aClass, AbilityClass, function(k) { | ||
return !(indexOf.call(vExcludes, k) >= 0); | ||
}); | ||
if (vAddtionalAbilityInjected) { | ||
aClassPrototype = vAddtionalAbilityInjected.prototype; | ||
} | ||
if (!vInjectedOnParent) { | ||
vExcludes = injectMethodsFromNonEnum(aClassPrototype, AbilityClass.prototype); | ||
extendFilter(aClassPrototype, AbilityClass.prototype, function(k) { | ||
return !(indexOf.call(vExcludes, k) >= 0); | ||
}); | ||
} | ||
} else { | ||
vIncludes = aOptions.include; | ||
if (vIncludes) { | ||
if (!isArray(vIncludes)) { | ||
vIncludes = [vIncludes]; | ||
} | ||
} else { | ||
vIncludes = []; | ||
} | ||
if (aCoreMethod) { | ||
if (isArray(aCoreMethod)) { | ||
vIncludes = vIncludes.concat(aCoreMethod); | ||
} else { | ||
vIncludes.push(aCoreMethod); | ||
} | ||
} | ||
vExcludes = aOptions.exclude; | ||
if (vExcludes) { | ||
if (!isArray(vExcludes)) { | ||
vExcludes = [vExcludes]; | ||
} | ||
} else { | ||
vExcludes = []; | ||
} | ||
vFilter = function(isStatic) { | ||
return function(k) { | ||
return filter(k, vIncludes, vExcludes, isStatic); | ||
}; | ||
}; | ||
vAbilities = injectMethodsFromNonEnum(aClass, AbilityClass, vFilter(true), true); | ||
vAbilities = vAbilities.concat(injectMethodsFromNonEnum(aClass.prototype, AbilityClass.prototype, vFilter())); | ||
vExcludes = vExcludes.concat(vAbilities); | ||
vAbilities = void 0; | ||
filterMethods = function(methods) { | ||
var k; | ||
if (methods instanceof Object) { | ||
for (k in methods) { | ||
if (!vFilter(k)) { | ||
delete methods[k]; | ||
} | ||
if (!(vHasCoreMethod || ($abilities && $abilities['$' + vName]))) { | ||
if ((aOptions == null) || !(aOptions.include || aOptions.exclude)) { | ||
if (vName) { | ||
vAdditionalAbilityInjected = injectAdditionalAbility(aClass, vName); | ||
} | ||
vExcludes = injectMethodsFromNonEnum(aClass, AbilityClass, null, true); | ||
(0, extend_1.default)(aClass, AbilityClass, function (k) { | ||
return !(vExcludes.indexOf(k) >= 0); | ||
}); | ||
if (vAdditionalAbilityInjected) { | ||
aClassPrototype = vAdditionalAbilityInjected.prototype; | ||
} | ||
if (!vInjectedOnParent) { | ||
vExcludes = injectMethodsFromNonEnum(aClassPrototype, AbilityClass.prototype); | ||
(0, extend_1.default)(aClassPrototype, AbilityClass.prototype, function (k) { | ||
return !(vExcludes.indexOf(k) >= 0); | ||
}); | ||
} | ||
} | ||
} | ||
}; | ||
if (vName) { | ||
vAddtionalAbilityInjected = injectAdditionalAbility(aClass, vName, filterMethods); | ||
else { | ||
vIncludes = aOptions.include; | ||
if (vIncludes) { | ||
if (!(0, array_1.default)(vIncludes)) { | ||
vIncludes = [vIncludes]; | ||
} | ||
} | ||
else { | ||
vIncludes = []; | ||
} | ||
if (aCoreMethod) { | ||
if ((0, array_1.default)(aCoreMethod)) { | ||
vIncludes = vIncludes.concat(aCoreMethod); | ||
} | ||
else { | ||
vIncludes.push(aCoreMethod); | ||
} | ||
} | ||
vExcludes = aOptions.exclude; | ||
if (vExcludes) { | ||
if (!(0, array_1.default)(vExcludes)) { | ||
vExcludes = [vExcludes]; | ||
} | ||
} | ||
else { | ||
vExcludes = []; | ||
} | ||
const vGenFilter = function (isStatic) { | ||
return function (k) { | ||
return filter(k, vIncludes, vExcludes, isStatic); | ||
}; | ||
}; | ||
let vAbilities = injectMethodsFromNonEnum(aClass, AbilityClass, vGenFilter(true), true); | ||
vAbilities = vAbilities.concat(injectMethodsFromNonEnum(aClass.prototype, AbilityClass.prototype, vGenFilter())); | ||
vExcludes = vExcludes.concat(vAbilities); | ||
vAbilities = undefined; | ||
const filterMethods = function (methods, isStatic) { | ||
if (methods instanceof Object) { | ||
const vFilter = vGenFilter(isStatic); | ||
for (const k in methods) { | ||
if (!vFilter(k)) { | ||
delete methods[k]; | ||
} | ||
} | ||
} | ||
}; | ||
if (vName) { | ||
vAdditionalAbilityInjected = injectAdditionalAbility(aClass, vName, filterMethods); | ||
} | ||
(0, extend_1.default)(aClass, AbilityClass, vGenFilter(true)); | ||
if (vAdditionalAbilityInjected) { | ||
aClassPrototype = vAdditionalAbilityInjected.prototype; | ||
} | ||
if (!vInjectedOnParent) { | ||
(0, extend_1.default)(aClassPrototype, AbilityClass.prototype, vGenFilter()); | ||
} | ||
filterMethods(aOptions.methods); | ||
filterMethods(aOptions.classMethods); | ||
} | ||
if (aOptions != null) { | ||
if (!vInjectedOnParent && aOptions.methods instanceof Object) { | ||
(0, injectMethods_1.default)(aClassPrototype, aOptions.methods, aOptions); | ||
} | ||
if (aOptions.classMethods instanceof Object) { | ||
(0, injectMethods_1.default)(aClass, aOptions.classMethods, aOptions); | ||
} | ||
} | ||
if (vName) { | ||
if (aClassPrototype !== aClass.prototype) { | ||
aClassPrototype = aClass.prototype; | ||
} | ||
if (!aClassPrototype.hasOwnProperty('$abilities')) { | ||
$abilities = {}; | ||
(0, defineProperty_1.default)(aClassPrototype, '$abilities', $abilities); | ||
} | ||
$abilities['$' + vName] = abilityFn; | ||
} | ||
} | ||
extendFilter(aClass, AbilityClass, vFilter(true)); | ||
if (vAddtionalAbilityInjected) { | ||
aClassPrototype = vAddtionalAbilityInjected.prototype; | ||
} | ||
else { | ||
aClass = AbilityClass; | ||
} | ||
return aClass; | ||
} | ||
; | ||
function filter(k, aIncludes, aExcludes, aIsStatic) { | ||
if (aIsStatic) { | ||
k = '@' + k; | ||
} | ||
let result = aIncludes.length; | ||
if (result) { | ||
result = aIncludes.indexOf(k) >= 0; | ||
if (!result && aExcludes.length) { | ||
result = !(aExcludes.indexOf(k) >= 0); | ||
} | ||
if (!vInjectedOnParent) { | ||
extendFilter(aClassPrototype, AbilityClass.prototype, vFilter()); | ||
} | ||
filterMethods(aOptions.methods); | ||
filterMethods(aOptions.classMethods); | ||
} | ||
if (aOptions != null) { | ||
if (!vInjectedOnParent && aOptions.methods instanceof Object) { | ||
injectMethods(aClassPrototype, aOptions.methods, aOptions); | ||
} | ||
if (aOptions.classMethods instanceof Object) { | ||
injectMethods(aClass, aOptions.classMethods, aOptions); | ||
} | ||
} | ||
if (vName) { | ||
if (aClassPrototype !== aClass.prototype) { | ||
aClassPrototype = aClass.prototype; | ||
} | ||
if (!aClassPrototype.hasOwnProperty('$abilities')) { | ||
$abilities = {}; | ||
defineProperty(aClassPrototype, '$abilities', $abilities); | ||
} | ||
$abilities['$' + vName] = abilityFn; | ||
} | ||
} | ||
} else { | ||
aClass = AbilityClass; | ||
} | ||
return aClass; | ||
}; | ||
abilityFn.filter = filter = function(k, aIncludes, aExcludes, aIsStatic) { | ||
var result; | ||
if (aIsStatic) { | ||
k = '@' + k; | ||
} | ||
result = aIncludes.length; | ||
if (result) { | ||
result = indexOf.call(aIncludes, k) >= 0; | ||
if (!result && aExcludes.length) { | ||
result = !(indexOf.call(aExcludes, k) >= 0); | ||
else if (aExcludes.length) { | ||
result = !(aExcludes.indexOf(k) >= 0); | ||
} | ||
} else if (aExcludes.length) { | ||
result = !(indexOf.call(aExcludes, k) >= 0); | ||
} else { | ||
result = true; | ||
} | ||
return result; | ||
}; | ||
getAdditionalAbility = function(aClass, aName) { | ||
var result; | ||
result = []; | ||
else { | ||
result = true; | ||
} | ||
return result; | ||
} | ||
; | ||
abilityFn.filter = filter; | ||
/* // eslint-disable-next-line unused-imports/no-unused-vars | ||
function getAdditionalAbility(aClass, aName) { | ||
const result = []; | ||
while (aClass && aClass.prototype) { | ||
@@ -217,34 +241,34 @@ if (aClass.prototype.hasOwnProperty('$abilities') && !aClass.prototype.$abilities['$' + aName] && aClass.prototype.$abilities[aName]) { | ||
}; | ||
injectAdditionalAbility = function(aClass, aName, filterMethods) { | ||
var $abilities, result, vAbility, vOptions; | ||
while (aClass && aClass.prototype) { | ||
if (aClass.prototype.hasOwnProperty('$abilities')) { | ||
$abilities = aClass.prototype.$abilities; | ||
if (!$abilities['$' + aName] && (vAbility = $abilities[aName])) { | ||
vOptions = vAbility(); | ||
$abilities['$' + aName] = abilityFn; | ||
result = aClass; | ||
if (vOptions != null) { | ||
if (filterMethods) { | ||
filterMethods(vOptions.methods); | ||
filterMethods(vOptions.classMethods); | ||
} | ||
if (vOptions.methods instanceof Object) { | ||
injectMethods(aClass.prototype, vOptions.methods, vOptions); | ||
} | ||
if (vOptions.classMethods instanceof Object) { | ||
injectMethods(aClass, vOptions.classMethods, vOptions); | ||
} | ||
*/ | ||
function injectAdditionalAbility(aClass, aName, filterMethods) { | ||
let result; | ||
while (aClass && aClass.prototype) { | ||
if (aClass.prototype.hasOwnProperty('$abilities')) { | ||
const $abilities = aClass.prototype.$abilities; | ||
let vAbility; | ||
if (!$abilities['$' + aName] && (vAbility = $abilities[aName])) { | ||
const vOptions = vAbility(); | ||
result = aClass; | ||
if (vOptions != null) { | ||
if (filterMethods) { | ||
filterMethods(vOptions.methods); | ||
filterMethods(vOptions.classMethods); | ||
} | ||
if (vOptions.methods instanceof Object) { | ||
(0, injectMethods_1.default)(aClass.prototype, vOptions.methods, vOptions); | ||
} | ||
if (vOptions.classMethods instanceof Object) { | ||
(0, injectMethods_1.default)(aClass, vOptions.classMethods, vOptions); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
aClass = aClass.super_; | ||
} | ||
aClass = aClass.super_; | ||
} | ||
return result; | ||
}; | ||
return result; | ||
} | ||
; | ||
return abilityFn; | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=custom-ability.js.map | ||
} | ||
exports.createAbilityInjector = createAbilityInjector; | ||
; |
@@ -1,24 +0,25 @@ | ||
(function() { | ||
var getPrototypeOf; | ||
getPrototypeOf = require('inherits-ex/lib/getPrototypeOf'); | ||
module.exports = function(aClass, aName) { | ||
var result, vPrototype; | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.hasAbilityOnParent = void 0; | ||
const getPrototypeOf_1 = __importDefault(require("inherits-ex/lib/getPrototypeOf")); | ||
function hasAbilityOnParent(aClass, aName) { | ||
let result, vPrototype; | ||
result = false; | ||
if (aClass) { | ||
vPrototype = aClass.prototype; | ||
vPrototype = aClass.prototype; | ||
} | ||
while (vPrototype) { | ||
if (vPrototype.hasOwnProperty('$abilities') && vPrototype.$abilities.hasOwnProperty(aName)) { | ||
result = true; | ||
break; | ||
} | ||
vPrototype = getPrototypeOf(vPrototype); | ||
if (vPrototype.hasOwnProperty('$abilities') && vPrototype.$abilities.hasOwnProperty(aName)) { | ||
result = true; | ||
break; | ||
} | ||
vPrototype = (0, getPrototypeOf_1.default)(vPrototype); | ||
} | ||
return result; | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=has-ability-on-parent.js.map | ||
} | ||
exports.hasAbilityOnParent = hasAbilityOnParent; | ||
; | ||
exports.default = hasAbilityOnParent; |
@@ -1,12 +0,12 @@ | ||
(function() { | ||
var hasAbilityOnParent; | ||
hasAbilityOnParent = require('./has-ability-on-parent'); | ||
module.exports = function(aClass, aName) { | ||
return hasAbilityOnParent(aClass, '$' + aName); | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=injected-on-parent.js.map | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.injectedOnParent = void 0; | ||
const has_ability_on_parent_1 = __importDefault(require("./has-ability-on-parent")); | ||
function injectedOnParent(aClass, aName) { | ||
return (0, has_ability_on_parent_1.default)(aClass, '$' + aName); | ||
} | ||
exports.injectedOnParent = injectedOnParent; | ||
exports.default = injectedOnParent; |
@@ -1,15 +0,60 @@ | ||
(function() { | ||
module.exports = function(packageName, aClass, aOptions) { | ||
var addAbility; | ||
try { | ||
addAbility = require(packageName + '/ability'); | ||
} catch (undefined) {} | ||
if (!addAbility) { | ||
throw TypeError('the package no ability supports.'); | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
return addAbility(aClass, aOptions); | ||
}; | ||
}).call(this); | ||
//# sourceMappingURL=require.js.map | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.requireAbility = void 0; | ||
function getDefaultEntry(name) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let result = (yield Promise.resolve(`${name}`).then(s => __importStar(require(s)))).default; | ||
if (typeof result !== "function" && typeof result.default === "function") { | ||
result = result.default; | ||
} | ||
return result; | ||
}); | ||
} | ||
function requireAbility(packageName, aClass, aOptions) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let addAbility; | ||
try { | ||
addAbility = yield getDefaultEntry(packageName + '/ability.js'); | ||
} | ||
catch (error) { } | ||
if (typeof addAbility !== "function") { | ||
throw new TypeError('the package no ability supports.'); | ||
} | ||
return addAbility(aClass, aOptions); | ||
}); | ||
} | ||
exports.requireAbility = requireAbility; | ||
; | ||
exports.default = requireAbility; |
{ | ||
"name": "custom-ability", | ||
"version": "1.6.2", | ||
"version": "2.0.0-alpha.0", | ||
"description": "make custom ability more easy. generate the ability which can be added to any class directly.", | ||
"homepage": "https://github.com/snowyu/custom-ability.js", | ||
"main": "./index", | ||
"main": "./lib/index.js", | ||
"module": "./lib/esm/index.js", | ||
"files": [ | ||
@@ -16,25 +17,44 @@ "README.md", | ||
"scripts": { | ||
"test": "grunt test" | ||
"build": "npm run build.ts && npm run doc.md", | ||
"build.ts": "npm run build.ts.cjs && npm run build.ts.mjs", | ||
"build.ts.d": "tsc --declaration --emitDeclarationOnly --outDir lib", | ||
"build.ts.cjs": "tsc --module commonjs -outDir lib", | ||
"build.ts.mjs": "tsc --moduleResolution nodenext --module es2022 -outDir lib/esm", | ||
"clean": "rm -fr web docs lib", | ||
"clean.doc": "rm -fr web docs", | ||
"clean.ts": "rm -fr lib/*.d.ts", | ||
"clean.lib": "rm -fr lib", | ||
"doc": "typedoc --plugin none --out web ./src", | ||
"doc.md": "typedoc --plugin typedoc-plugin-markdown --out docs ./src", | ||
"lint": "npx eslint --config .eslintrc.yml src", | ||
"lint.fix": "npm run lint -- --fix", | ||
"release": "npm run clean && npm run build && npx standard-version", | ||
"release.alpha": "npm run release -- --prerelease alpha", | ||
"test": "mocha" | ||
}, | ||
"engines": { | ||
"node": ">=12" | ||
}, | ||
"dependencies": { | ||
"inherits-ex": "~1.3.0", | ||
"util-ex": "^0.3.15" | ||
"inherits-ex": "^2.1.0-alpha.3", | ||
"util-ex": "^2.0.0-alpha.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "~2.0.0", | ||
"coffee-script": "^1.12.7", | ||
"connect-livereload": "*", | ||
"grunt": "*", | ||
"grunt-contrib-clean": "*", | ||
"grunt-contrib-coffee": "1.0.0", | ||
"grunt-contrib-copy": "*", | ||
"grunt-contrib-jshint": "*", | ||
"grunt-contrib-watch": "*", | ||
"grunt-mocha-test": "~0.13.2", | ||
"grunt-newer": "*", | ||
"mocha": "~3.4.2", | ||
"pre-commit": "~1.2.2", | ||
"sinon": "~2.4.1", | ||
"sinon-chai": "~2.12.0", | ||
"source-map-support": "*" | ||
"@antfu/eslint-config": "^0.38.4", | ||
"@types/chai": "^4.3.4", | ||
"@types/mocha": "^10.0.1", | ||
"@types/node": "^18.15.11", | ||
"@types/sinon": "^10.0.13", | ||
"@types/sinon-chai": "^3.2.9", | ||
"chai": "~4.3.7", | ||
"eslint": "^8.37.0", | ||
"eslint-config-prettier": "^8.8.0", | ||
"eslint-plugin-tsdoc": "^0.2.17", | ||
"mocha": "~10.2.0", | ||
"sinon": "~15.0.3", | ||
"sinon-chai": "~3.7.0", | ||
"ts-node": "^10.9.1", | ||
"typedoc": "^0.23.28", | ||
"typedoc-plugin-markdown": "^3.14.0", | ||
"typescript": "^5.0.4" | ||
}, | ||
@@ -41,0 +61,0 @@ "pre-commit": [ |
204
README.md
# custom-ability [![Build Status](https://img.shields.io/travis/snowyu/custom-ability.js/master.png)](http://travis-ci.org/snowyu/custom-ability.js) [![npm](https://img.shields.io/npm/v/custom-ability.svg)](https://npmjs.org/package/custom-ability) [![downloads](https://img.shields.io/npm/dm/custom-ability.svg)](https://npmjs.org/package/custom-ability) [![license](https://img.shields.io/npm/l/custom-ability.svg)](https://npmjs.org/package/custom-ability) | ||
generate the ability which can be added to any class directly. | ||
It makes custom ability more easy. | ||
This library provides a simple way to inject abilities into classes. An "ability"(a "mixin" class) is defined as a set of methods that can be added(injected) to a class to enhance its functionality. | ||
Sometimes, we still feel that the class is a little big, and too many features in it. | ||
We just need some of the features(methods) inside. So as a class developer can | ||
consider these functions to extract, as a kind of ability to the user. | ||
Sometimes we may feel that a class is too large, containing too many features or methods. In such cases, as a developer, we can extract some of these functions as separate abilities, which users can use selectively based on their needs. | ||
## Usage | ||
**Features:** | ||
* Allows you to easily inject "abilities" (i.e. methods) from one class into another class, without needing to extend the target class. | ||
* Can inject both static and instance methods. | ||
* Allows you to specify a set of "core methods" for the ability class, which will be used to check if the ability has already been injected into a target class. | ||
* Prevents the same ability from being injected multiple times into the same class. | ||
* The mechanism to prevent duplicate injection of the same ability is achieved through the `$abilities` member on the prototype of the target class. This member records all injected ability names (i.e. abilityClass.name). | ||
* It will traverse and check the parent classes of the target class until it finds the `$abilities`. | ||
* Additionally, if the `coreMethod` parameter is set, the first method name in `coreMethod` will also be checked in the target class. | ||
* Supports optional include and exclude parameters, which allow you to specify which methods should be injected or excluded from injection. | ||
* Supports optional methods and classMethods parameters, which allow you to inject additional methods into the target class. | ||
**Usage:** | ||
1. Define an ability class that contains the methods you want to inject into other classes. | ||
2. Use the customAbility function to create a new function that can inject the ability into target classes. | ||
3. Call the new function with the ability class and any optional parameters to inject the ability into a target class. | ||
## Examples | ||
Suppose we wanna add the RefCount ability to any class directly. | ||
@@ -30,27 +45,34 @@ | ||
```coffee | ||
# ability.coffee | ||
customAbility = require 'custom-ability' | ||
```js | ||
// ability.js | ||
const makeAbility = require('custom-ability') | ||
class RefCountable | ||
# define the instance methods here: | ||
release: -> | ||
result = --@RefCount | ||
@destroy() unless result >= 0 | ||
result | ||
free: @::release | ||
addRef: -> | ||
if not isUndefined @RefCount | ||
++@RefCount | ||
class RefCountable { | ||
// the class methods if any: | ||
static someClassMethod() {} | ||
//define the instance methods here: | ||
release() { | ||
let result = --this.RefCount | ||
if (result < 0) this.destroy() | ||
return result | ||
} | ||
free() { | ||
return this.release() | ||
} | ||
addRef() { | ||
if (!isUndefined(this.RefCount)) | ||
++this.RefCount | ||
else | ||
@RefCount = 1 | ||
this.RefCount = 1 | ||
} | ||
# the class methods if any: | ||
@someClassMethod: -> | ||
} | ||
# We set the `addRef` method as the core methods. | ||
# The Core methods are the ability MUST have. | ||
# they're used to check the same ability whether the ability already added. | ||
module.exports = customAbility RefCountable, 'addRef' | ||
// # We set the `addRef` method as the core methods. | ||
// # The Core methods are the ability MUST have. | ||
// # the first core method will be used to check the same ability whether the ability already added too. | ||
module.exports = makeAbility(RefCountable, 'addRef') | ||
``` | ||
@@ -73,15 +95,18 @@ | ||
```coffee | ||
refable = require 'ref-object/ability' | ||
```js | ||
const addRefAbility = require('ref-object/ability') | ||
class MyClass | ||
refable MyClass, exclude: '@someClassMethod' #someClassMethod would not be added to the class | ||
destroy: ->console.log 'destroy' | ||
class MyClass { | ||
destroy() {console.log('destroy')} | ||
} | ||
my = new MyClass | ||
// someClassMethod would not be added to the class | ||
addRefAbility(MyClass, exclude: '@someClassMethod') | ||
my.addRef() | ||
my.free() # nothing | ||
my.free() # print the 'destroy' here. | ||
const my = new MyClass | ||
my.addRef() // add reference count | ||
my.free() // dec reference count, do nothing | ||
my.free() // now destroy, print the 'destroy' here. | ||
``` | ||
@@ -93,2 +118,6 @@ | ||
Another type of injection is the "additional abilities" that can be injected using the methods and classMethods parameters. These additional methods are necessary when modifying existing methods of the target class to call the old/original method to make a certain ability work. | ||
The injected methods are encapsulated in a closure. And the passed `this` object inside the closure is not the original instance object, but `self`, and the original method is referred to as `super`. | ||
In order to make certain ability to work, you need to modify some methods | ||
@@ -101,25 +130,30 @@ of the class which could call the old(original) method. this time we need | ||
```coffee | ||
eventable = require 'events-ex/eventable' | ||
eventableOptions = require './eventable-options' | ||
```js | ||
const eventable = require('events-ex/eventable') | ||
const eventableOptions = require('./eventable-options') | ||
module.exports = (aClass, aOptions)-> | ||
eventable aClass, eventableOptions(aOptions) | ||
module.exports = function(aClass, aOptions){ | ||
return eventable(aClass, eventableOptions(aOptions)) | ||
} | ||
``` | ||
```coffee | ||
# eventable-options.coffee | ||
module.exports = (aOptions)-> | ||
aOptions = {} unless aOptions | ||
aOptions.methods = {} unless aOptions.methods | ||
extend aOptions.methods, | ||
# override methods: (btw: classMethods to override the class methods) | ||
setObjectState: (value, emitted = true)-> | ||
self= @self | ||
@super.call(self, value) | ||
self.emit value, self if emitted | ||
return | ||
```js | ||
// eventable-options.js | ||
module.exports = function (aOptions){ | ||
if (!aOptions) aOptions = {} | ||
if (!aOptions.methods) aOptions.methods = {} | ||
extend( aOptions.methods, { | ||
// override methods: (btw: classMethods to override the class methods) | ||
setObjectState(value, emitted = true) { | ||
// The injected methods are encapsulated in a closure. | ||
// The `this` object inside the closure is not the original instance object, but `self`, and the original method is referred to as `super`. | ||
self= this.self | ||
this.super.setObjectState.call(self, value) | ||
if (emitted) self.emit(value, self) | ||
} | ||
}) | ||
... | ||
return aOptions | ||
# more detail on [AbstractObject/src/eventable-options.coffee](https://github.com/snowyu/abstract-object) | ||
// more detail on [AbstractObject/src/eventable-options.coffee](https://github.com/snowyu/abstract-object) | ||
} | ||
``` | ||
@@ -133,8 +167,8 @@ | ||
```coffee | ||
eventable = require 'events-ex/eventable' | ||
```js | ||
const eventable = require 'events-ex/eventable' | ||
class MyClass | ||
inherits MyClass, AbstractObject | ||
eventable MyClass | ||
class MyClass extends AbstractObject {} | ||
// inherits MyClass, AbstractObject | ||
eventable(MyClass) | ||
``` | ||
@@ -144,8 +178,9 @@ | ||
```coffee | ||
AbstractObject = require('./lib/abstract-object') | ||
```js | ||
const AbstractObject = require('./lib/abstract-object') | ||
AbstractObject.$abilities = | ||
# "Eventable" is the AbilityClass name | ||
AbstractObject.$abilities = { | ||
// "Eventable" is the AbilityClass name | ||
Eventable: require('./lib/eventable-options') | ||
} | ||
@@ -157,4 +192,6 @@ module.exports = AbstractObject | ||
just one function: | ||
This library provides a function customAbility that can inject the abilities of a "mixin" class onto another target class or object. | ||
Abilities can be defined as static or instance methods on the "mixin" class. | ||
```js | ||
@@ -164,33 +201,42 @@ var customAbility = require('custom-ability') | ||
### customAbility(abilityClass[, coreMethod[, isGetClassFunction]]) | ||
### customAbility(abilityClass: Function|object, coreMethod?: string|string[], isGetClassFunction = false): WithAbilityFn | ||
__arguments__ | ||
The injected abilities are provided by the `abilityClass` parameter, which is expected to be a class. The function takes the following parameters: | ||
* abilityClass *(function)*: the class will become to abilitiable. | ||
* coreMethod *(string|arrayOf string)*: optional must have coreMethod(s). | ||
**arguments** | ||
* `abilityClass` *(function)*: the class that provides the abilities to be injected | ||
* `coreMethod` *(string|arrayOf string)*: optional must have coreMethod(s). | ||
* a string or an array of strings that represent core methods of the abilityClass. | ||
* And if one or more of these methods are present in the target class, the ability will not be injected. | ||
* **note**: `@` prefix means class/static method. | ||
* isGetClassFunction *(boolean)*: the `AbilityClass` is a `function(aClass, aOptions)` | ||
* `isGetClassFunction` *(boolean)*: the `AbilityClass` is a `function(aClass, aOptions)` | ||
to return the real `Ability Class` if true. defaults to false. | ||
* Whether abilityClass should be invoked with aClass and aOptions to get the actual ability class. | ||
__return__ | ||
**return** | ||
* *(function)*: a function which can inject the ability to any class directly. | ||
the function customAbility should be modified its name. | ||
function customAbility(abilityClass: Function|object, coreMethod?: string|string[], isGetClassFunction = false): WithAbilityFn | ||
The exported function returns another function (`WithAbilityFn(targetClass, options?: {include?: string|string[], exclude?: string|string[], methods? : {[name: string]: Function}, , classMethods? : {[name: string]: Function}}): targetClass`) that takes two parameters: | ||
This custom ability injection function has two arguments: `function(class[, options])` | ||
* `class`: the class to be injected the ability. | ||
* `options` *(object)*: optional options | ||
* `include`*(array|string)*: only these methods will be added to the class | ||
* `class`: the target class to be injected the ability. | ||
* `options` *(object)*: an optional options object that can contain the following properties: | ||
* `include`*(array|string)*: only these methods will be added(injected) to the class | ||
* **note**: `@` prefix means class/static method. | ||
* `exclude`*(array|string)*: these methods would not be added to the class | ||
* **note**: the `coreMethod` could not be excluded. It's always added to the class. | ||
* `exclude`*(array|string)*: these methods would not be added(injected) to the class | ||
* **note**: the `coreMethod` could not be excluded. It's always added(injected) to the class. | ||
* **note**: `@` prefix means class/static method. | ||
* `methods`*(object)*: injected/hooked methods to the class | ||
* key: the method name to hook. | ||
* value: the new method function, if original method is exists or not in replacedMethods: | ||
* value: the new method function, if original method is exists: | ||
* use `this.super()` to call the original method. | ||
* `this.self` is the original `this` object. | ||
* `classMethods` *(object)*: hooked class methods to the class, it's the same usage as the `methods`. | ||
* `replacedMethods` *(array)*: the method name in the array will be replaced the original | ||
method directly. | ||
@@ -484,3 +530,3 @@ ## Specification | ||
self= @self | ||
@super.call(self, value) | ||
this.super.call(self, value) | ||
self.emit value, self if emitted | ||
@@ -487,0 +533,0 @@ return |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
114493
38
2649
528
17
1
1
1
+ Addedinherits-ex@2.1.0(transitive)
+ Addedutil-ex@2.1.0(transitive)
- Removedinherits-ex@1.3.61.6.0(transitive)
- Removedutil-ex@0.3.18(transitive)
- Removedxtend@4.0.2(transitive)
Updatedinherits-ex@^2.1.0-alpha.3
Updatedutil-ex@^2.0.0-alpha.1