Compare commits

...
Author SHA1 Message Date
Julien Fontanet d32c5b31e7 WiP: feat(mixin): support for lazy mixins 2022-06-23 16:38:13 +02:00
2 changed files with 44 additions and 13 deletions
+41 -10
View File
@@ -2,7 +2,12 @@
const camelCase = require('lodash/camelCase') const camelCase = require('lodash/camelCase')
const { defineProperties, defineProperty, keys } = Object const {
defineProperties,
defineProperty,
hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty),
keys,
} = Object
const noop = Function.prototype const noop = Function.prototype
const MIXIN_CYCLIC_DESCRIPTOR = { const MIXIN_CYCLIC_DESCRIPTOR = {
@@ -13,24 +18,50 @@ const MIXIN_CYCLIC_DESCRIPTOR = {
} }
module.exports = function mixin(object, mixins, args) { module.exports = function mixin(object, mixins, args) {
// add lazy property for each of the mixin, this allows mixins to depend on const importing = { __proto__: null }
// one another without any special ordering const importers = { __proto__: null }
const descriptors = {}
keys(mixins).forEach(name => {
const Mixin = mixins[name]
name = camelCase(name)
descriptors[name] = { function instantiateMixin(name, Mixin) {
configurable: true,
get: () => {
defineProperty(object, name, MIXIN_CYCLIC_DESCRIPTOR) defineProperty(object, name, MIXIN_CYCLIC_DESCRIPTOR)
const instance = new Mixin(object, ...args) const instance = new Mixin(object, ...args)
defineProperty(object, name, { defineProperty(object, name, {
value: instance, value: instance,
}) })
return instance return instance
}
// add lazy property for each of the mixin, this allows mixins to depend on
// one another without any special ordering
const descriptors = {
loadMixin(name) {
if (hasOwn(this, name)) {
return Promise.resolve(this[name])
}
let promise = importing[name]
if (promise === undefined) {
const clean = () => {
delete importing[name]
}
promise = importers[name]().then(Mixin => instantiateMixin(name, Mixin))
promise.then(clean, clean)
importing[name] = promise
}
return promise
}, },
} }
keys(mixins).forEach(name => {
const Mixin = mixins[name]
name = camelCase(name)
if (Mixin.prototype === undefined) {
importers[name] = Mixin(name)
} else {
descriptors[name] = {
configurable: true,
get: () => instantiateMixin(name, Mixin),
}
}
}) })
defineProperties(object, descriptors) defineProperties(object, descriptors)
+1 -1
View File
@@ -16,7 +16,7 @@
}, },
"preferGlobal": false, "preferGlobal": false,
"engines": { "engines": {
"node": ">=6" "node": ">=7.6"
}, },
"dependencies": { "dependencies": {
"bind-property-descriptor": "^2.0.0", "bind-property-descriptor": "^2.0.0",