UNPKG

@adpt/core

Version:
218 lines 7.94 kB
"use strict"; /* * Copyright 2018-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 tslib_1 = require("tslib"); const ld = tslib_1.__importStar(require("lodash")); const util = tslib_1.__importStar(require("util")); const xmlbuilder = tslib_1.__importStar(require("xmlbuilder")); const error_1 = require("./error"); const jsx_1 = require("./jsx"); const reanimate_1 = require("./reanimate"); const defaultSerializeOptions = { reanimateable: false, props: "all", }; function serializeAny(val, reanimateable) { return JSON.stringify(val, serializeSpecials(reanimateable), 2); } function serializeSpecials(reanimateable) { return function (key, value) { return value; }; } function serializedShortPropIsString(propVal) { return !(/^\d/.test(propVal)); } function canBeShort(propName, propVal) { if (propName === "xmlns" || propName.startsWith("xmlns:")) return false; if (ld.isNumber(propVal)) return true; if (ld.isString(propVal)) { const json = JSON.stringify(propVal); return (json.length < 10) && serializedShortPropIsString(json.slice(1, -1)); } return false; } function serializeShortPropVal(propVal) { const long = serializeLongPropVal(propVal, false, false); if (ld.isString(long) && ld.isString(propVal)) { return long.slice(1, -1); } return long; } function serializeLongPropVal(propVal, pretty = true, reanimateable = true) { const json = JSON.stringify(propVal, serializeSpecials(reanimateable), pretty ? 2 : undefined); if (json != null) return json; return propVal.toString(); } function collectProps(elem, options) { const props = elem.props; const shortProps = {}; let longProps = null; let propNames; switch (options.props) { case "all": propNames = Object.keys(props).sort(); break; case "none": propNames = []; break; default: if (!Array.isArray(options.props)) { throw new error_1.InternalError(`Invalid value '${options.props}' for options.props`); } propNames = options.props; } for (const propName of propNames) { if (propName === "children" || propName === "handle") continue; const prop = props[propName]; if (prop === undefined) continue; if (canBeShort(propName, prop)) { shortProps[propName] = serializeShortPropVal(prop); } else { if (longProps == null) { longProps = {}; } longProps[propName] = serializeLongPropVal(prop, true, options.reanimateable); } } return { shortProps, longProps }; } function addPropsNode(node, props) { const propsNode = node.ele("__props__", {}); for (const propName in props) { if (!props.hasOwnProperty(propName)) continue; const prop = props[propName]; propsNode.ele("prop", { name: propName }, prop); } } function serializeChildren(context, node, children, options) { for (const child of children) { switch (true) { case jsx_1.isElement(child): serializeElement(context, node, child, options); break; default: const serChild = serializeAny(child, options.reanimateable); if (serChild == null) { node.ele("typescript", {}).cdata(child.toString()); } else { node.ele("json", {}, serChild); } } } } function serializeChildrenFromElem(context, node, elem, options) { const children = jsx_1.childrenToArray(elem.props.children); serializeChildren(context, node, children, options); } function getUrn(elem) { if (!jsx_1.isComponentElement(elem)) { throw new Error(`Unable to create reanimateable representation of ` + `'${elem.componentName}' because it doesn't extend ` + `Adapt.Component`); } try { return reanimate_1.findMummyUrn(elem.componentType); } catch ( /**/_a) { /**/ } // Ensure component is registered by constructing one try { new elem.componentType({}); } catch ( /**/_b) { /**/ } return reanimate_1.findMummyUrn(elem.componentType); } function serializeBuildData(context, parent, elem, options) { const bdNode = parent.ele("buildData", {}); const succ = elem.buildData.successor; const origChildren = elem.buildData.origChildren; if (succ !== undefined) { const isNull = succ === null; const succNode = bdNode.ele("successor", { isNull }); //We can just serialize here because only an element or its successor can appear in a dom, not both if (succ !== null) serializeElement(context, succNode, succ, options); } if (origChildren !== undefined) { const origChildrenNode = bdNode.ele("origChildren", {}); serializeChildren(context, origChildrenNode, origChildren, options); } } function addLifecycleNode(context, parent, elem, options) { if (!jsx_1.isElementImpl(elem)) throw new Error(`Element not an ElementImpl: ${util.inspect(elem)}`); const lcNode = parent.ele("__lifecycle__", {}); lcNode.ele("field", { name: "stateNamespace" }, JSON.stringify(elem.stateNamespace)); lcNode.ele("field", { name: "keyPath" }, JSON.stringify(elem.keyPath)); lcNode.ele("field", { name: "path" }, JSON.stringify(elem.path)); if ("Enable this when we figure out how to serialize and reanimate SFCs".length === 0) { serializeBuildData(context, lcNode, elem, options); } } function serializeElement(context, parent, elem, options) { if (context.serializedElements.has(elem) && jsx_1.isMountedElement(elem)) { parent.ele("__elementRef__", { ref: elem.id }); return; } const { shortProps, longProps } = collectProps(elem, options); let node; if (options.reanimateable) { const urn = getUrn(elem); node = parent.ele(elem.componentName, Object.assign({}, shortProps, { xmlns: urn })); } else { node = parent.ele(elem.componentName, shortProps); } if (longProps != null) { addPropsNode(node, longProps); } serializeChildrenFromElem(context, node, elem, options); if (jsx_1.isMountedElement(elem) && options.reanimateable) { context.work.push(() => addLifecycleNode(context, node, elem, options)); } } function serializeDom(root, options = {}) { const opts = Object.assign({}, defaultSerializeOptions, options); if (opts.reanimateable && opts.props !== "all") { throw new Error(`Invalid options for serializeDom: props must be "all" when reanimateable is true`); } const context = { serializedElements: new Set(), work: [] }; const doc = xmlbuilder.create("Adapt", { headless: true }); if (root != null) serializeElement(context, doc, root, opts); while (context.work.length > 0) { const toDo = context.work.shift(); if (toDo) toDo(); } return doc.end({ pretty: true }) + "\n"; } exports.serializeDom = serializeDom; //# sourceMappingURL=dom_serialize.js.map