From 34170ed0f930d0047076e405d611d21485faad5d Mon Sep 17 00:00:00 2001 From: cha0s Date: Fri, 26 Mar 2021 10:51:24 -0500 Subject: [PATCH] feat: gathered HMR!! --- packages/core/src/gather.js | 87 +++++++++++++++++++++++++++---------- packages/core/src/index.js | 4 ++ 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/packages/core/src/gather.js b/packages/core/src/gather.js index c4550fa..98ec3b6 100644 --- a/packages/core/src/gather.js +++ b/packages/core/src/gather.js @@ -6,6 +6,8 @@ import {camelCase} from './string'; const debug = D('@latus/core/gather'); +export const hotGathered = new Map(); + export const decorateWithLatus = ( context, { @@ -47,51 +49,88 @@ export const gatherWithLatus = ( })) ); +const wrapperClass = (Class, id, idAttribute, type, typeAttribute) => { + class Subclass extends Class { + + static get [idAttribute]() { + return id; + } + + static get [typeAttribute]() { + return type; + } + + } + return Subclass; +}; + export default ( latus, { - type, + type: hook, idAttribute = 'id', typeAttribute = 'type', check = () => {}, }, ) => { - const gathered = latus.invokeReduce(type); - check(gathered, type); - const composed = latus.invokeComposed(`${type}.decorate`, gathered); - check(composed, `${type}.decorate`); + const raw = latus.invokeReduce(hook); + check(raw, hook); + const composed = latus.invokeComposed(`${hook}.decorate`, raw); + check(composed, `${hook}.decorate`); let uid = 1; const fromId = {}; const fromType = Object.fromEntries( Object.entries(composed) .sort(([lname], [rname]) => (lname < rname ? -1 : 1)) .map(([type, Class]) => { - const thisUid = uid++; - class Subclass extends Class { - - static get [idAttribute]() { - return thisUid; - } - - static get [typeAttribute]() { - return type; - } - - } - if (!Subclass.name) { - Subclass.name = type; - } - fromId[thisUid] = Subclass; + const id = uid++; + const Subclass = wrapperClass(Class, id, idAttribute, type, typeAttribute); + fromId[id] = Subclass; return [ type, Subclass, ]; }), ); - const result = { + const gathered = { ...fromId, ...fromType, }; - debug("gathered '%s': %O", type, result); - return result; + hotGathered.set(hook, { + idAttribute, + gathered, + typeAttribute, + }); + debug("gathered '%s': %O", hook, gathered); + return gathered; +}; + +export const refresh = (path, latus) => { + const it = hotGathered.entries(); + for (let current = it.next(); current.done !== true; current = it.next()) { + const { + value: [ + hook, + { + idAttribute, + gathered, + typeAttribute, + }, + ], + } = current; + const updates = latus.invokePlugin(hook, path); + if (!updates) { + // eslint-disable-next-line no-continue + continue; + } + const entries = Object.entries(updates); + for (let i = 0; i < entries.length; ++i) { + const [type, Class] = entries[i]; + const {[type]: {[idAttribute]: id}} = gathered; + const Subclass = wrapperClass(Class, id, idAttribute, type, typeAttribute); + gathered[type] = Subclass; + gathered[id] = Subclass; + latus.invoke('@latus/core/gathered/hmr', Subclass, hook); + } + } }; diff --git a/packages/core/src/index.js b/packages/core/src/index.js index 46cf688..3992065 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line max-classes-per-file +import {refresh} from './gather'; + export { unique as arrayUnique, flatten as arrayFlatten, @@ -22,5 +25,6 @@ export default { '@latus/core/config': () => ({ id: 'latus', }), + '@latus/core/hmr': refresh, }, };