Comparing version 1.5.2 to 2.0.0
@@ -5,2 +5,21 @@ # Change Log | ||
<a name="2.0.0"></a> | ||
# [2.0.0](https://github.com/untool/mixinable/compare/v1.5.2...v2.0.0) (2018-04-19) | ||
### Features | ||
* add autobinding ([a79e6af](https://github.com/untool/mixinable/commit/a79e6af)) | ||
* make mixinable methods available to mixins ([1e86af4](https://github.com/untool/mixinable/commit/1e86af4)) | ||
### BREAKING CHANGES | ||
* all mixin and mixinable methods are now automatically | ||
being bound to their respective instances | ||
* even inside mixin instances, their own mixinable methods can | ||
not be called directly any more | ||
<a name="1.5.2"></a> | ||
@@ -7,0 +26,0 @@ ## [1.5.2](https://github.com/untool/mixinable/compare/v1.5.1...v1.5.2) (2018-03-10) |
42
index.js
@@ -115,4 +115,5 @@ 'use strict'; | ||
} | ||
enhanceInstance.call(this, prototype, mixins, args); | ||
enhanceInstance(this, prototype, mixins, args); | ||
constructor.apply(this, args); | ||
bindAll(this); | ||
} | ||
@@ -127,7 +128,11 @@ Mixinable.prototype = Object.assign( | ||
function enhanceInstance(strategies, mixins, args) { | ||
function enhanceInstance(mixinable, strategies, mixins, args) { | ||
var mixinstances = mixins.map(function(mixin) { | ||
return new (bindArgs(mixin, args))(); | ||
return bindAll(new (bindArgs(mixin, args))()); | ||
}); | ||
Object.defineProperties(this, { | ||
var mixinstanceProps = Object.keys(strategies).reduce(function(result, key) { | ||
result[key] = { value: mixinable[key].bind(mixinable) }; | ||
return result; | ||
}, {}); | ||
var mixinableProps = { | ||
__implementations__: { | ||
@@ -146,3 +151,7 @@ value: Object.keys(strategies).reduce(function(result, key) { | ||
__arguments__: { value: args }, | ||
}; | ||
mixinstances.forEach(function(mixinstance) { | ||
Object.defineProperties(mixinstance, mixinstanceProps); | ||
}); | ||
Object.defineProperties(mixinable, mixinableProps); | ||
} | ||
@@ -224,1 +233,26 @@ | ||
} | ||
function getPropertyNames(obj) { | ||
var props = []; | ||
do { | ||
Object.getOwnPropertyNames(obj).forEach(function(prop) { | ||
if (props.indexOf(prop) === -1) { | ||
props.push(prop); | ||
} | ||
}); | ||
} while ((obj = Object.getPrototypeOf(obj)) !== Object.prototype); | ||
return props; | ||
} | ||
function getMethodNames(obj) { | ||
return getPropertyNames(obj).filter(function(prop) { | ||
return prop !== 'constructor' && typeof obj[prop] === 'function'; | ||
}); | ||
} | ||
function bindAll(obj) { | ||
getMethodNames(obj).forEach(function(method) { | ||
obj[method] = obj[method].bind(obj); | ||
}); | ||
return obj; | ||
} |
{ | ||
"name": "mixinable", | ||
"version": "1.5.2", | ||
"version": "2.0.0", | ||
"description": "Functional JavaScript Mixin Utility", | ||
@@ -8,7 +8,12 @@ "main": "index.js", | ||
"test": "ava --verbose", | ||
"lint": "eslint \"packages/**/*.js\"", | ||
"fmt": "prettier --write --ignore-path .gitignore '**/*.{js,json,css}' '**/README.md'", | ||
"lint": "eslint --ignore-path .gitignore \"**/*.js\"", | ||
"fmt": "prettier --write --ignore-path .gitignore '**/*.{js,json}'", | ||
"release": "standard-version", | ||
"postrelease": "git push --follow-tags; npm publish --registry https://registry.npmjs.org/" | ||
"postrelease": "git push --follow-tags; npm publish", | ||
"commitmsg": "commitlint -e $GIT_PARAMS", | ||
"precommit": "lint-staged" | ||
}, | ||
"publishConfig": { | ||
"registry": "https://registry.npmjs.org/" | ||
}, | ||
"repository": { | ||
@@ -25,4 +30,7 @@ "type": "git", | ||
"devDependencies": { | ||
"@commitlint/cli": "^6.1.3", | ||
"@commitlint/config-conventional": "^6.1.3", | ||
"ava": "^0.25.0", | ||
"eslint": "^4.18.2", | ||
"cz-conventional-changelog": "^2.1.0", | ||
"eslint": "^4.19.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
@@ -35,2 +43,13 @@ "eslint-plugin-prettier": "^2.6.0", | ||
}, | ||
"renovate": { | ||
"extends": ["config:base"], | ||
"ignoreDeps": ["prettier"], | ||
"lockFileMaintenance": { | ||
"enabled": true | ||
}, | ||
"pinVersions": false, | ||
"prCreation": "not-pending", | ||
"semanticCommits": true, | ||
"semanticPrefix": "chore:" | ||
}, | ||
"prettier": { | ||
@@ -42,27 +61,25 @@ "trailingComma": "es5", | ||
"eslintConfig": { | ||
"extends": [ | ||
"eslint:recommended", | ||
"prettier" | ||
], | ||
"plugins": [ | ||
"prettier" | ||
], | ||
"extends": ["eslint:recommended", "prettier"], | ||
"plugins": ["prettier"], | ||
"rules": { | ||
"prettier/prettier": "error" | ||
}, | ||
"env": { | ||
"node": true, | ||
"es6": true | ||
"node": true | ||
}, | ||
"rules": { | ||
"prettier/prettier": "error" | ||
"globals": { | ||
"Promise": true | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.{js,json,css}": [ | ||
"prettier --write", | ||
"git add" | ||
], | ||
"**/README.md": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
"*.{js,json}": ["prettier --write", "git add"] | ||
}, | ||
"commitlint": { | ||
"extends": ["@commitlint/config-conventional"] | ||
}, | ||
"config": { | ||
"commitizen": { | ||
"path": "./node_modules/cz-conventional-changelog" | ||
} | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# Mixinable | ||
# mixinable | ||
@@ -15,3 +15,3 @@ [![travis](https://img.shields.io/travis/untool/mixinable.svg)](https://travis-ci.org/untool/mixinable) [![npm](https://img.shields.io/npm/v/mixinable.svg)](https://www.npmjs.com/package/mixinable) <br/> | ||
```bash | ||
```text | ||
npm install -S mixinable | ||
@@ -22,3 +22,3 @@ ``` | ||
```bash | ||
```text | ||
yarn add mixinable | ||
@@ -301,3 +301,3 @@ ``` | ||
```bash | ||
```text | ||
mkdir mixinable && cd $_ | ||
@@ -304,0 +304,0 @@ git clone git@github.com:user/mixinable.git |
85
test.js
@@ -596,1 +596,86 @@ 'use strict'; | ||
}); | ||
test('internal mixin method test', function(t) { | ||
t.plan(2); | ||
var create = mixinable({ | ||
foo: mixinable.override, | ||
bar: mixinable.override, | ||
})( | ||
{ | ||
foo: function() { | ||
t.pass('first method is being called directly'); | ||
this.bar(); | ||
}, | ||
}, | ||
{ | ||
bar: function() { | ||
t.pass('second method is being called indirectly'); | ||
}, | ||
} | ||
); | ||
create().foo(); | ||
}); | ||
test('autobinding test', function(t) { | ||
return new Promise(function(resolve) { | ||
var create = mixinable({ | ||
foo: mixinable.override, | ||
bar: mixinable.override, | ||
})({ | ||
foo: function() { | ||
t.pass('first method is being called directly'); | ||
t.truthy( | ||
this.constructor.prototype.foo.hasOwnProperty('prototype'), | ||
'first mixin prototype method is unbound' | ||
); | ||
t.falsy( | ||
this.foo.hasOwnProperty('prototype'), | ||
'first mixin method is bound' | ||
); | ||
setTimeout(this.bar, 5); | ||
}, | ||
bar: function() { | ||
t.pass('second method is being called indirectly'); | ||
t.truthy( | ||
this.constructor.prototype.bar.hasOwnProperty('prototype'), | ||
'second mixin prototype method is unbound' | ||
); | ||
t.falsy( | ||
this.bar.hasOwnProperty('prototype'), | ||
'second mixin method is bound' | ||
); | ||
setTimeout(this.baz, 5); | ||
}, | ||
baz: function() { | ||
t.pass('third method is being called indirectly'); | ||
t.truthy( | ||
this.constructor.prototype.baz.hasOwnProperty('prototype'), | ||
'third mixin prototype method is unbound' | ||
); | ||
t.falsy( | ||
this.baz.hasOwnProperty('prototype'), | ||
'third mixin method is bound' | ||
); | ||
setTimeout(this.qux, 5); | ||
}, | ||
qux: function() { | ||
t.pass('fourth method is being called indirectly'); | ||
t.truthy( | ||
this.constructor.prototype.qux.hasOwnProperty('prototype'), | ||
'fourth mixin prototype method is unbound' | ||
); | ||
t.falsy( | ||
this.qux.hasOwnProperty('prototype'), | ||
'fourth mixin method is bound' | ||
); | ||
resolve(); | ||
}, | ||
}); | ||
var instance = create(); | ||
t.falsy( | ||
instance.foo.hasOwnProperty('prototype'), | ||
'mixinable method is bound' | ||
); | ||
instance.foo(); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
225976
884
11