Compare commits

...

1 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

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,23 +18,49 @@ const MIXIN_CYCLIC_DESCRIPTOR = {
} }
module.exports = function mixin(object, mixins, args) { module.exports = function mixin(object, mixins, args) {
const importing = { __proto__: null }
const importers = { __proto__: null }
function instantiateMixin(name, Mixin) {
defineProperty(object, name, MIXIN_CYCLIC_DESCRIPTOR)
const instance = new Mixin(object, ...args)
defineProperty(object, name, {
value: instance,
})
return instance
}
// add lazy property for each of the mixin, this allows mixins to depend on // add lazy property for each of the mixin, this allows mixins to depend on
// one another without any special ordering // one another without any special ordering
const descriptors = {} 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 => { keys(mixins).forEach(name => {
const Mixin = mixins[name] const Mixin = mixins[name]
name = camelCase(name) name = camelCase(name)
descriptors[name] = { if (Mixin.prototype === undefined) {
configurable: true, importers[name] = Mixin(name)
get: () => { } else {
defineProperty(object, name, MIXIN_CYCLIC_DESCRIPTOR) descriptors[name] = {
const instance = new Mixin(object, ...args) configurable: true,
defineProperty(object, name, { get: () => instantiateMixin(name, Mixin),
value: instance, }
})
return instance
},
} }
}) })
defineProperties(object, descriptors) defineProperties(object, descriptors)

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",