UNPKG

woby

Version:

A high-performance framework with fine-grained observable/signal-based reactivity for building rich applications.

168 lines (167 loc) 6.44 kB
"use strict"; const setters = require("./setters-CyO2VUT6.cjs"); const wrap_clone_element = require("./wrap_clone_element-C4XivH3I.cjs"); const template = (fn) => { const safePropertyRe = /^[a-z0-9-_]+$/i; const checkValidProperty = (property) => { if (setters.isString(property) && safePropertyRe.test(property)) return true; throw new Error(`Invalid property, only alphanumeric properties are allowed inside templates, received: "${property}"`); }; const makeAccessor = (actionsWithNodes) => { return new Proxy({}, { get(target, prop) { checkValidProperty(prop); const accessor = (node, method, key, targetNode) => { if (key) checkValidProperty(key); actionsWithNodes.push([node, method, prop, key, targetNode]); }; const metadata = { [setters.SYMBOL_TEMPLATE_ACCESSOR]: true }; return setters.assign(accessor, metadata); } }); }; const makeActionsWithNodesAndTemplate = () => { const actionsWithNodes = []; const accessor = makeAccessor(actionsWithNodes); const component = fn(accessor); if (setters.isFunction(component)) { const root = component(); if (root instanceof Element) { return { actionsWithNodes, root }; } } throw new Error("Invalid template, it must return a function that returns an Element"); }; const makeActionsWithPaths = (actionsWithNodes) => { const actionsWithPaths = []; for (let i = 0, l = actionsWithNodes.length; i < l; i++) { const [node, method, prop, key, targetNode] = actionsWithNodes[i]; const nodePath = makeNodePath(node); const targetNodePath = targetNode ? makeNodePath(targetNode) : void 0; actionsWithPaths.push([nodePath, method, prop, key, targetNodePath]); } return actionsWithPaths; }; const makeNodePath = /* @__PURE__ */ (() => { let prevNode = null; let prevPath; return (node) => { if (node === prevNode) return prevPath; const path = []; let child = node; let parent = child.parentNode; while (parent) { const index = !child.previousSibling ? 0 : !child.nextSibling ? -0 : setters.indexOf(parent.childNodes, child); path.push(index); child = parent; parent = parent.parentNode; } prevNode = node; prevPath = path; return path; }; })(); const makeNodePathProperties = (path) => { const properties = ["root"]; const parts = path.slice().reverse(); for (let i = 0, l = parts.length; i < l; i++) { const part = parts[i]; if (Object.is(0, part)) { properties.push("firstChild"); } else if (Object.is(-0, part)) { properties.push("lastChild"); } else { properties.push("firstChild"); for (let nsi = 0; nsi < part; nsi++) { properties.push("nextSibling"); } } } return properties; }; const makeReviverPaths = (actionsWithPaths) => { const paths = []; for (let i = 0, l = actionsWithPaths.length; i < l; i++) { const action = actionsWithPaths[i]; const nodePath = action[0]; const targetNodePath = action[4]; paths.push(nodePath); if (targetNodePath) { paths.push(targetNodePath); } } return paths; }; const makeReviverVariablesData = (paths, properties) => { const data = new Array(paths.length); for (let i = 0, l = paths.length; i < l; i++) { data[i] = { path: paths[i], properties: properties[i] }; } return data; }; const makeReviverVariables = (actionsWithPaths) => { const paths = makeReviverPaths(actionsWithPaths); const properties = paths.map(makeNodePathProperties); const data = makeReviverVariablesData(paths, properties); const assignments = []; const map = /* @__PURE__ */ new Map(); let variableId = 0; while (true) { const datum = data.find((datum2) => datum2.properties.length > 1); if (!datum) break; const [current, next] = datum.properties; const variable = `$${variableId++}`; const assignment = `const ${variable} = ${current}.${next};`; assignments.push(assignment); for (let i = 0, l = data.length; i < l; i++) { const datum2 = data[i]; const [otherCurrent, otherNext] = datum2.properties; if (otherCurrent !== current || otherNext !== next) continue; datum2.properties[0] = variable; datum2.properties.splice(1, 1); } } for (let i = 0, l = data.length; i < l; i++) { const datum = data[i]; map.set(datum.path, datum.properties[0]); } return { assignments, map }; }; const makeReviverActions = (actionsWithPaths, variables) => { const actions = []; for (let i = 0, l = actionsWithPaths.length; i < l; i++) { const [nodePath, method, prop, key, targetNodePath] = actionsWithPaths[i]; if (targetNodePath) { actions.push(`this.${method} ( props["${prop}"], ${variables.get(targetNodePath)} );`); } else if (key) { actions.push(`this.${method} ( ${variables.get(nodePath)}, "${key}", props["${prop}"] );`); } else { actions.push(`this.${method} ( ${variables.get(nodePath)}, props["${prop}"] );`); } } return actions; }; const makeReviver = (actionsWithPaths) => { const { assignments, map } = makeReviverVariables(actionsWithPaths); const actions = makeReviverActions(actionsWithPaths, map); const fn2 = new Function("root", "props", `${assignments.join("")}${actions.join("")}return root;`); const apis = { setAttribute: setters.setAttribute, setChildReplacement: setters.setChildReplacement, setClasses: setters.setClasses, setEvent: setters.setEvent, setHTML: setters.setHTML, setProperty: setters.setProperty, setRef: setters.setRef, setStyles: setters.setStyles }; const reviver = fn2.bind(apis); return reviver; }; const makeComponent = () => { const { actionsWithNodes, root } = makeActionsWithNodesAndTemplate(); const actionsWithPaths = makeActionsWithPaths(actionsWithNodes); const reviver = makeReviver(actionsWithPaths); return (props) => { const clone = root.cloneNode(true); return wrap_clone_element.wrapElement(reviver.bind(void 0, clone, props)); }; }; return makeComponent(); }; exports.template = template; //# sourceMappingURL=template-C8XYMS58.cjs.map