UNPKG

@adpt/cloud

Version:
124 lines 4.81 kB
"use strict"; /* * Copyright 2019 Unbounded Systems, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const core_1 = require("@adpt/core"); const utils_1 = require("@adpt/utils"); const Action_1 = require("./Action"); // FIXME(mark): The use of componentName here may not be quite sufficient. // Since it's this ID that matches up Elements from the old and new DOM, // this indirectly decides whether we either perform a // delete-old-element plus create-new-element or just an update-new-element. // So if the Element at a certain ID is replaced with a component of the // same name (and still same ID), BUT has a different implementation or // semantics, we won't detect that here. exports.idFunc = (el) => `${el.id}:${el.componentName}`; class ActionPlugin { constructor() { this.elements = new Map(); } async start(options) { if (options.logger == null) throw new Error(`Plugin start called without logger`); this.logger = options.logger; if (options.dataDir == null) throw new Error(`Plugin start called without dataDir`); this.dataDir = options.dataDir; } async observe(oldDom, newDom) { const obs = {}; const callShould = async (list, op) => { for (const el of list) { const context = this.context(el); const inst = Action_1.getActionInstance(el); if (!inst) continue; const id = exports.idFunc(el); this.elements.set(id, el); const ret = Action_1.toDetail(await inst.shouldAct(op, context)); obs[id] = { type: ret.act ? op : core_1.ChangeType.none, detail: ret.detail, }; } }; const diff = core_1.domDiff(oldDom, newDom, exports.idFunc); await callShould(diff.deleted, core_1.ChangeType.delete); await callShould(diff.added, core_1.ChangeType.create); await callShould(diff.commonNew, core_1.ChangeType.modify); return obs; } analyze(_oldDom, _newDom, observations) { // Aggregate all "none" items into one PluginAction const noAction = []; const actions = Object.keys(observations).map((id) => { const obs = observations[id]; const el = this.elements.get(id); if (!el) throw new Error(`Internal error: unable to look up element for ID ${id}`); const context = this.context(el); if (obs.type === core_1.ChangeType.none) { noAction.push(el); return null; } const inst = Action_1.getActionInstance(el); if (!inst) throw new Error(`Unexpected error getting Action instance`); return { type: obs.type, detail: obs.detail, act: async () => inst.action(obs.type, context), changes: [{ type: obs.type, detail: obs.detail, element: el, }] }; }).filter(utils_1.notNull); if (noAction.length > 0) { actions.push({ type: core_1.ChangeType.none, detail: "No action required", act: async () => { }, changes: noAction.map((el) => ({ type: core_1.ChangeType.none, detail: "No action required", element: el, })) }); } return actions; } async finish() { } context(el) { const logger = this.logger; const dataDir = this.dataDir; if (!logger || !dataDir) throw new Error(`Plugin not initialized correctly`); return { buildData: el.buildData, dataDir, logger }; } } exports.ActionPlugin = ActionPlugin; function createActionPlugin() { return new ActionPlugin(); } exports.createActionPlugin = createActionPlugin; core_1.registerPlugin({ name: "Action", module, create: createActionPlugin, }); //# sourceMappingURL=action_plugin.js.map