UNPKG

@maverick-js/compiler

Version:

Maverick toolchain including the analyzer and compiler.

1,409 lines (1,401 loc) 59.3 kB
import { createFunctionCall, setGlobalLogLevel, mapLogLevelStringToNumber, log, logTime, Declarations, format, createImportDeclaration, trimQuotes, trimTrailingSemicolon, createStringLiteral, selfInvokingFunction, escapeDoubleQuotes, createObjectLiteral, trimWhitespace } from './chunks/chunk-SEGPSIF6.js'; import { isUndefined, isArray } from './chunks/chunk-3M33KLBM.js'; import { createFilter } from '@rollup/pluginutils'; import { createUnplugin } from 'unplugin'; import MagicString from 'magic-string'; import { relative } from 'pathe'; import { encode, decode } from 'html-entities'; import ts from 'typescript'; // src/utils/html.ts function escape(value, isAttr = false) { const type = typeof value; if (type !== "string") { if (!isAttr && type === "function") return escape(value()); if (isAttr && type === "boolean") return value + ""; return value; } const delimeter = isAttr ? '"' : "<", escapeDelimeter = isAttr ? "&quot;" : "&lt;"; let iDelimeter = value.indexOf(delimeter), isAmpersand = value.indexOf("&"); if (iDelimeter < 0 && isAmpersand < 0) return value; let left = 0, out = ""; while (iDelimeter >= 0 && isAmpersand >= 0) { if (iDelimeter < isAmpersand) { if (left < iDelimeter) out += value.substring(left, iDelimeter); out += escapeDelimeter; left = iDelimeter + 1; iDelimeter = value.indexOf(delimeter, left); } else { if (left < isAmpersand) out += value.substring(left, isAmpersand); out += "&amp;"; left = isAmpersand + 1; isAmpersand = value.indexOf("&", left); } } if (iDelimeter >= 0) { do { if (left < iDelimeter) out += value.substring(left, iDelimeter); out += escapeDelimeter; left = iDelimeter + 1; iDelimeter = value.indexOf(delimeter, left); } while (iDelimeter >= 0); } else while (isAmpersand >= 0) { if (left < isAmpersand) out += value.substring(left, isAmpersand); out += "&amp;"; left = isAmpersand + 1; isAmpersand = value.indexOf("&", left); } return left < value.length ? out + value.substring(left) : out; } var AST = Symbol("AST"); function createAST(root) { return { [AST]: true, root, tree: [] }; } function createElementNode(info) { return { kind: 1 /* Element */, ...info }; } function createFragmentNode(info) { return { kind: 2 /* Fragment */, ...info }; } function createTextNode(info) { return { kind: 5 /* Text */, ...info, value: encode(trimWhitespace(info.ref.getText())) }; } function createAttributeNode(info) { return { kind: 4 /* Attribute */, ...info }; } function createRefNode(info) { return { kind: 7 /* Ref */, ...info }; } function createEventNode(info) { return { kind: 8 /* Event */, ...info }; } function createDirectiveNode(info) { return { kind: 9 /* Directive */, ...info }; } function createExpressionNode(info) { return { kind: 6 /* Expression */, ...info }; } var spreadTrimRE = /(?:^\{\.{3})(.*)(?:\}$)/; function createSpreadNode(info) { return { kind: 3 /* Spread */, ...info, value: info.ref.getText().replace(spreadTrimRE, "$1") }; } function createStructuralNode(type) { return { kind: 20 /* Structural */, type }; } function isAST(value) { return !!value[AST]; } function isElementNode(node) { return node.kind === 1 /* Element */; } function isFragmentNode(node) { return node.kind === 2 /* Fragment */; } function isTextNode(node) { return node.kind === 5 /* Text */; } function isAttributeNode(node) { return node.kind === 4 /* Attribute */; } function isSpreadNode(node) { return node.kind === 3 /* Spread */; } function isExpressionNode(node) { return node.kind === 6 /* Expression */; } function isRefNode(node) { return node.kind === 7 /* Ref */; } function isEventNode(node) { return node.kind === 8 /* Event */; } function isDirectiveNode(node) { return node.kind === 9 /* Directive */; } function isStructuralNode(node) { return node.kind === 20 /* Structural */; } function isElementEnd(node) { return node.type === 1 /* ElementEnd */; } function isAttributesEnd(node) { return node.type === 6 /* AttributesEnd */; } function isChildrenStart(node) { return node.type === 4 /* ChildrenStart */; } function isChildrenEnd(node) { return node.type === 5 /* ChildrenEnd */; } // src/transformer/jsx/constants.ts var RESERVED_ATTR_NAMESPACE = /* @__PURE__ */ new Set([ "$class", "$cssvar", "$prop", "$style" ]); var RESERVED_NAMESPACE = /* @__PURE__ */ new Set([ ...RESERVED_ATTR_NAMESPACE, "$on", "$oncapture", "$use" ]); var STATICABLE_NAMESPACE = /* @__PURE__ */ new Set(["$style", "$cssvar"]); var BOOLEAN_NAMES = [ "allowfullscreen", "async", "autofocus", "autoplay", "checked", "controls", "default", "disabled", "formnovalidate", "hidden", "indeterminate", "ismap", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "seamless", "selected" ]; new Set(BOOLEAN_NAMES); var DELEGATED_EVENT_TYPE = /* @__PURE__ */ new Set([ "beforeinput", "click", "dblclick", "contextmenu", "focusin", "focusout", "input", "keydown", "keyup", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "pointerdown", "pointermove", "pointerout", "pointerover", "pointerup", "touchend", "touchmove", "touchstart" ]); var SVG_ELEMENT_TAGNAME = /* @__PURE__ */ new Set([ // "a", "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignObject", "g", "glyph", "glyphRef", "hkern", "image", "line", "linearGradient", "marker", "mask", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", // "script", "set", "stop", // "style", "svg", "switch", "symbol", "text", "textPath", // "title", "tref", "tspan", "use", "view", "vkern" ]); var VOID_ELEMENT_TAGNAME = /* @__PURE__ */ new Set([ "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr" ]); // src/utils/fn.ts function onceFn(fn) { let result; return () => result ?? (result = fn()); } // src/transformer/jsx/parse.ts function buildAST(root, meta = {}, skipRoot = false) { const ast = createAST(root); if (ts.isBinaryExpression(root) || ts.isConditionalExpression(root)) { parseExpression(root, ast, meta); } else if (!skipRoot) { parseNode(root, ast, { ...meta, parent: void 0 }); } else if (!ts.isJsxSelfClosingElement(root)) { parseChildren(root, ast, meta); } return ast; } function parseNode(node, ast, meta) { if (isJSXElementNode(node)) { parseElement(node, ast, meta); } else if (ts.isJsxFragment(node)) { parseFragment(node, ast); } else if (ts.isJsxText(node) && !isEmptyNode(node)) { ast.tree.push(createTextNode({ ref: node })); } else if (ts.isJsxExpression(node) && node.expression && !isEmptyNode(node)) { parseExpression(node, ast, meta); } } function parseElement(node, ast, meta) { const tagName = getTagName(node), isComponent = isComponentTagName(tagName), isCustomElement = tagName.includes("-"), isVoid = !isComponent && VOID_ELEMENT_TAGNAME.has(tagName), isSVG = !isComponent && (tagName === "svg" || SVG_ELEMENT_TAGNAME.has(tagName)), isSelfClosing = ts.isJsxSelfClosingElement(node), supportsChildren = isSelfClosing || isVoid; let children = !supportsChildren ? filterEmptyJSXChildNodes(Array.from(node.children)) : []; const firstChild = children[0]; if (!isComponent && firstChild && ts.isJsxFragment(firstChild)) { children = filterEmptyJSXChildNodes(Array.from(firstChild.children)); } const childCount = children.length, childElementCount = filterDOMElements(children).length, hasChildren = childCount > 0; let isDynamic = isComponent || isCustomElement; const dynamic = onceFn(() => { isDynamic = true; }); let hasSpread = false; const spread = onceFn(() => { hasSpread = true; }); const element = createElementNode({ ref: node, tagName, isVoid, isSVG, isCE: tagName.includes("-"), childCount, childElementCount, hasChildren, isComponent, dynamic: () => isDynamic, spread: () => hasSpread }); ast.tree.push(element); const attributes = isSelfClosing ? node.attributes : node.openingElement.attributes; parseElementAttrs(attributes, ast, { parent: meta, component: isComponent, dynamic, spread }); ast.tree.push(createStructuralNode(6 /* AttributesEnd */)); if (hasChildren) { if (isComponent) { const childNodes = []; for (const child of children) { if (ts.isJsxText(child)) { childNodes.push(createTextNode({ ref: child })); } else if (ts.isJsxExpression(child)) { childNodes.push(buildExpressionNode(child, { parent: node })); } else { childNodes.push(buildAST(child)); } } element.children = childNodes; } else { ast.tree.push(createStructuralNode(4 /* ChildrenStart */)); for (const child of children) { parseNode(child, ast, { parent: meta, dynamic }); } ast.tree.push(createStructuralNode(5 /* ChildrenEnd */)); } } ast.tree.push(createStructuralNode(1 /* ElementEnd */)); } function parseElementAttrs(attributes, ast, meta) { var _a, _b, _c, _d, _e; const attrs = Array.from(attributes.properties); for (const attr of attrs) { if (ts.isJsxSpreadAttribute(attr)) { ast.tree.push(createSpreadNode({ ref: attr })); meta.dynamic(); meta.spread(); continue; } const initializer = attr.initializer, node = initializer || attr, literal = initializer && ts.isStringLiteral(initializer) ? initializer : void 0, expression = initializer && ts.isJsxExpression(initializer) ? initializer.expression : void 0; if (initializer && isEmptyNode(literal || expression)) continue; let rawName = attr.name.getText() || "", rawNameParts = rawName.split(":"), hasValidNamespace = isValidNamespace(rawNameParts[0]), namespace = hasValidNamespace ? rawNameParts[0] : null, name = hasValidNamespace ? rawNameParts[1] : rawName, isStaticExpr = expression && isStaticExpression(expression), isStaticValue = !initializer || !!literal || isStaticExpr; const value = !initializer ? meta.component || namespace === "$prop" ? "true" : '""' : (literal || expression).getText(); const dynamic = !isStaticValue || namespace && !STATICABLE_NAMESPACE.has(namespace) || name === "innerHTML"; const { observable, children } = !isStaticValue && expression ? resolveExpressionChildren(expression) : { observable: false, children: void 0 }; const callId = expression && ts.isCallExpression(expression) && expression.arguments.length === 0 ? expression.expression.getText() : void 0; if (expression && !isStaticExpr) { if (name === "$ref") { ast.tree.push(createRefNode({ ref: expression, value })); (_a = meta.dynamic) == null ? void 0 : _a.call(meta); } else if (namespace === "$use") { ast.tree.push(createDirectiveNode({ ref: expression, name, value })); (_b = meta.dynamic) == null ? void 0 : _b.call(meta); } else if (namespace === "$on" || namespace === "$oncapture") { const data = !!initializer && ts.isJsxExpression(initializer) && !!initializer.expression && ts.isArrayLiteralExpression(initializer.expression) ? initializer.expression : null; ast.tree.push( createEventNode({ ref: expression, namespace, type: name, value: data ? data.elements[0].getText() : value, data: data ? data.elements[1].getText() : void 0, delegate: namespace !== "$oncapture" && DELEGATED_EVENT_TYPE.has(name) }) ); (_c = meta.dynamic) == null ? void 0 : _c.call(meta); } else if (!namespace || isValidAttrNamespace(namespace)) { ast.tree.push( createAttributeNode({ ref: expression, namespace, name, value, dynamic, observable, callId, children }) ); if (dynamic) (_d = meta.dynamic) == null ? void 0 : _d.call(meta); } } else { ast.tree.push( createAttributeNode({ ref: node, namespace: isValidAttrNamespace(namespace) ? namespace : null, name, value, dynamic, observable, callId, children }) ); if (dynamic) (_e = meta.dynamic) == null ? void 0 : _e.call(meta); } } } function parseFragment(node, ast, meta) { const childNodes = [], children = filterEmptyJSXChildNodes(Array.from(node.children)); for (const child of children) { if (ts.isJsxText(child)) { childNodes.push(createTextNode({ ref: child })); } else if (ts.isJsxExpression(child)) { childNodes.push(buildExpressionNode(child, { parent: node })); } else { childNodes.push(buildAST(child)); } } ast.tree.push( createFragmentNode({ ref: node, childCount: children.length, childElementCount: filterDOMElements(children).length, children: childNodes }) ); } function parseChildren(root, ast, meta) { const children = filterEmptyJSXChildNodes(Array.from(root.children)); for (const child of children) parseNode(child, ast, { parent: meta }); } function parseExpression(node, ast, meta) { ast.tree.push(buildExpressionNode(node, meta)); } function buildExpressionNode(node, meta) { const expression = ts.isJsxExpression(node) ? node.expression : node, isRootCallExpression = ts.isCallExpression(expression), isCallable = isRootCallExpression && expression.arguments.length === 0, { observable, children } = resolveExpressionChildren(expression), isStatic = !observable && !children && isStaticExpression(expression); return createExpressionNode({ ref: node, children, observable, root: !meta.parent, dynamic: !isStatic, value: expression.getText(), callId: isCallable ? expression.expression.getText() : void 0 }); } // src/utils/ts.ts function hasChildType(node, check) { const parse = (child) => { if (check(child)) return true; return ts.forEachChild(child, parse); }; return ts.forEachChild(node, parse); } function resolveExpressionChildren(expression) { let observable = ts.isCallExpression(expression), children, isJSXExpression = !observable && (isJSXElementNode(expression) || ts.isJsxFragment(expression)); const parse = (node) => { if (!observable && ts.isCallExpression(node)) { observable = true; } else if (isJSXElementNode(node) || ts.isJsxFragment(node)) { if (!children) children = []; children.push(buildAST(node)); return; } ts.forEachChild(node, parse); }; if (isJSXExpression) { children = [buildAST(expression)]; } else { ts.forEachChild(expression, parse); } return { observable, children }; } // src/transformer/jsx/parse-jsx.ts var tsxRE = /\.tsx/; function parseJSX(code, options = {}) { const { filename = "" } = options; const parseStartTime = process.hrtime(); const sourceFile = ts.createSourceFile( filename, code.original, 99, true, tsxRE.test(filename) ? 4 : 2 ); logTime("Parsed Source File (TS)", parseStartTime); const ast = []; let lastImportNode; const parse = (node) => { if (ts.isBinaryExpression(node) || ts.isConditionalExpression(node)) { const hasJSXChild = hasChildType( node, (node2) => isJSXElementNode(node2) || ts.isJsxFragment(node2) ); if (hasJSXChild) { ast.push(buildAST(node, {})); } return; } else if (isJSXElementNode(node) || ts.isJsxFragment(node)) { ast.push(buildAST(node, {})); return; } ts.forEachChild(node, parse); }; ts.forEachChild(sourceFile, parse); return { startPos: (lastImportNode == null ? void 0 : lastImportNode.getEnd()) ?? 0, ast }; } function isJSXElementNode(node) { return ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node); } // src/transformer/jsx/utils.ts function isComponentTagName(tagName) { return !tagName.includes("-") && (tagName[0] && tagName[0].toLowerCase() !== tagName[0] || tagName.includes(".") || /[^a-zA-Z]/.test(tagName[0])); } function getTagName(node) { return ts.isJsxElement(node) ? node.openingElement.tagName.escapedText : node.tagName.escapedText; } function isValidAttrNamespace(namespace) { return RESERVED_ATTR_NAMESPACE.has(namespace); } function isValidNamespace(namespace) { return RESERVED_NAMESPACE.has(namespace); } function isTrueBoolExpression(node) { return node.kind === ts.SyntaxKind.TrueKeyword; } function isFalseBoolExpression(node) { return node.kind === ts.SyntaxKind.FalseKeyword; } function isBoolExpression(node) { return isTrueBoolExpression(node) || isFalseBoolExpression(node); } function isStringExpression(node) { return ts.isNoSubstitutionTemplateLiteral(node) || ts.isStringLiteral(node); } function isStaticExpression(node) { return ts.isLiteralExpression(node) || ts.isNumericLiteral(node) || isStringExpression(node) || isBoolExpression(node); } function overwrite(code, node, content) { const start = node.getStart(node.getSourceFile()), end = node.getEnd(); code.overwrite(start, end, content); } function isEmptyNode(node) { const text = trimQuotes(node.getText().trim()); return text.length === 0 || text === "() => {}"; } function isEmptyExpressionNode(node) { return ts.isJsxExpression(node) && isEmptyNode(node); } function isEmptyTextNode(node) { return ts.isJsxText(node) && (isEmptyNode(node) || /^[\r\n]\s*$/.test(node.getText())); } function filterEmptyJSXChildNodes(children) { return children.filter((child) => !isEmptyExpressionNode(child) && !isEmptyTextNode(child)); } function filterDOMElements(children) { return children.filter( (node) => ts.isJsxText(node) && !isEmptyNode(node) || isJSXElementNode(node) && !isComponentTagName(getTagName(node)) ); } function serializeComponentProp(serializer, node, ctx) { if (!node.children) { return `${node.name}: ${node.value}`; } else { const serialized = serializeParentExpression(serializer, node, { ...ctx, scoped: true }); return `${node.name}: ${serialized}`; } } function serializeChildren(serializer, children, ctx, component = false) { const serialized = children.map((child) => { var _a; if (isAST(child)) { return serializer.serialize(child, ctx); } else if (isTextNode(child)) { return createStringLiteral(escapeDoubleQuotes(decode(child.value))); } else { let ast = !component && (serializer.name === "ssr" || ctx.hydratable) ? createAST(child.ref) : null; if (ast) ast.tree.push(child); const expression = child.children ? serializeParentExpression(serializer, child, ctx) : ast ? serializer.serialize(ast, ctx) : child.value; if (ctx.fragment && child.observable && ctx.hydratable && serializer.name === "dom" && ((_a = child.children) == null ? void 0 : _a.length)) { ctx.runtime.add("$$_computed"); return selfInvokingFunction( [ `const $$_signal = ${createFunctionCall("$$_computed", [`() => ${expression}`])};`, "$$_signal();", "return $$_signal;" ].join("") ); } return expression; } }); if (serialized.length === 1 && serialized[0].length === 0) return ""; return serialized.length === 1 ? serialized[0] : `[${serialized.join(", ")}]`; } function serializeComponentChildrenProp(serializer, children, ctx) { return `$children() { return ${serializeChildren(serializer, children, ctx, true)} }`; } function serializeParentExpression(serializer, node, ctx, hof = false) { let code = new MagicString(node.value), start = node.ref.getStart() + (ts.isJsxExpression(node.ref) ? 1 : 0); const returnStatement = !!node.children && node.children.length === 1 && ts.isJsxExpression(node.ref) && !!node.ref.expression && ts.isArrowFunction(node.ref.expression) && ts.isBlock(node.ref.expression.body) && node.ref.expression.body.statements.find(ts.isReturnStatement); const isAlreadyScoped = returnStatement && !!returnStatement.expression && (returnStatement.expression === node.children[0].root || ts.isParenthesizedExpression(returnStatement.expression) && returnStatement.expression.expression === node.children[0].root); for (const ast of node.children) { const expression = serializer.serialize(ast, { ...ctx, scoped: returnStatement ? !isAlreadyScoped : ctx.scoped }), nodeStart = isAlreadyScoped ? returnStatement.getStart() : ast.root.getStart(), nodeEnd = isAlreadyScoped ? returnStatement.getEnd() : ast.root.getEnd(); code.overwrite( nodeStart - start, nodeEnd - start, hof && expression.startsWith("(") ? `${hof}(() => ${expression})` : expression ); } return code.toString(); } function serializeCreateComponent(createId, mergeId, tagName, props, spreads) { const hasProps = props.filter((prop) => prop !== "$$SPREAD").length > 0; const hasSpreads = spreads.length > 0; const shouldMergeProps = hasSpreads && (hasProps || spreads.length > 1); const mergedProps = []; if (shouldMergeProps) { let i = 0; for (const prop of props) { if (prop === "$$SPREAD") { mergedProps.push(spreads.pop()); i = mergedProps.length; } else { (mergedProps[i] ??= []).push(prop); } } } const mergedPropsArgs = mergedProps.map( (prop) => isArray(prop) ? `{ ${prop.join(", ")} }` : prop ); const createComponent = createFunctionCall(createId, [ tagName, hasSpreads ? !hasProps && spreads.length === 1 ? spreads[spreads.length - 1] : createFunctionCall(mergeId, mergedPropsArgs) : hasProps ? `{ ${props.join(", ")} }` : "" ]); return { createComponent, shouldMergeProps }; } // src/transformer/dom/index.ts var ID = { template: "$$_templ", root: "$$_root", walker: "$$_walker", element: "$$_el", component: "$$_comp", expression: "$$_expr" }; var RUNTIME = { createTemplate: "$$_create_template", createFragment: "$$_create_fragment", createComponent: "$$_create_component", createWalker: "$$_create_walker", nextTemplate: "$$_next_template", nextElement: "$$_next_element", createElement: "$$_create_element", setupCustomElement: "$$_setup_custom_element", children: "$$_children", insert: "$$_insert", insertLite: "$$_insert_lite", insertAtMarker: "$$_insert_at_marker", insertAtMarkerLite: "$$_insert_at_marker_lite", listen: "$$_listen", delegateEvents: "$$_delegate_events", clone: "$$_clone", directive: "$$_directive", ref: "$$_ref", attr: "$$_attr", class: "$$_class", style: "$$_style", spread: "$$_spread", mergeProps: "$$_merge_props", computed: "$$_computed", effect: "$$_effect", peek: "$$_peek", scoped: "$$_scoped", hydrating: "$$_hydrating" }; var MARKER = { component: "<!$>", element: "<!$>", expression: "<!$>" }; var NEXT_ELEMENT = createFunctionCall(RUNTIME.nextElement, [ID.walker]); var NEXT_MARKER = `${ID.walker}.nextNode()`; var dom = { name: "dom", serialize(ast, ctx) { var _a, _b, _c, _d; const firstNode = ast.tree[0], isFirstNodeElement = isElementNode(firstNode), isFirstNodeExpression = isExpressionNode(firstNode), isFirstNodeComponent = isFirstNodeElement && firstNode.isComponent; if (isFirstNodeExpression && !firstNode.dynamic && !((_a = firstNode.children) == null ? void 0 : _a.length) && !firstNode.observable) { return firstNode.value; } let skip = -1, initRoot = false, innerHTML = false, textContent = false, childrenFragment = false, currentId, component, customElement, templateId, hierarchy = [], props = [], styles = [], spreads = [], expressions = [], scopes = [], groupedEffects = [], template = [], elements = [], locals = new Declarations(), elementChildIndex = -1, elementIds = {}, createRootId = () => { if (!initRoot) { if (!templateId) templateId = ctx.globals.create(ID.template); if (ctx.hydratable) { locals.create( `[${ID.root}, ${ID.walker}]`, createFunctionCall(RUNTIME.createWalker, [templateId]) ); ctx.runtime.add(RUNTIME.createWalker); } else { locals.create(ID.root, createFunctionCall(RUNTIME.clone, [templateId])); } currentId = ID.root; ctx.runtime.add(RUNTIME.clone); elementIds[0] = ID.root; initRoot = true; } return ID.root; }, nextElement = () => { createRootId(); ctx.runtime.add(RUNTIME.nextElement); return NEXT_ELEMENT; }, nextMarker = () => { createRootId(); return NEXT_MARKER; }, getParentElementId = () => { createRootId(); return getElementId(hierarchy, elementIds, locals); }, getCurrentElementId = () => { createRootId(); return getElementId( elementChildIndex >= 0 ? [...hierarchy, elementChildIndex] : hierarchy, elementIds, locals ); }, getNextElementId = () => { createRootId(); const element = elements.at(-1); const nextSibling = elementChildIndex + 1; return element && element.childCount > 1 ? nextSibling >= element.childElementCount ? "null" : getElementId([...hierarchy, nextSibling], elementIds, locals) : null; }, addAttrExpression = (node, runtimeId, name = node.name) => { if (node.observable) { const expression = createFunctionCall(runtimeId, [ currentId, createStringLiteral(name), node.value ]); if (ctx.groupDOMEffects) { groupedEffects.push(expression); } else { expressions.push(createFunctionCall(RUNTIME.effect, [`() => ${expression}`])); ctx.runtime.add(RUNTIME.effect); } } else { expressions.push( createFunctionCall(runtimeId, [currentId, createStringLiteral(name), node.value]) ); } ctx.runtime.add(runtimeId); }, addChildren = (children) => { const scoped = children.length > 1 || !isAST(children[0]); const serialized = serializeChildren(dom, children, { ...ctx, scoped }, true); const shouldReturn = scoped || /^(\[|\(|\$\$|\")/.test(serialized); props.push( `$children: $$_children(() => { ${shouldReturn ? `return ${serialized}` : serialized} })` ); ctx.runtime.add(RUNTIME.children); }, RUNTIME_INSERT = !ctx.diffArrays ? RUNTIME.insertLite : RUNTIME.insert, insert = (marker, block) => { const beforeId = ctx.hydratable ? null : getNextElementId(); const parentId = ctx.hydratable ? (marker == null ? void 0 : marker()) ?? null : getParentElementId(); const insertId = ctx.hydratable ? !ctx.diffArrays ? RUNTIME.insertAtMarkerLite : RUNTIME.insertAtMarker : RUNTIME_INSERT; expressions.push(createFunctionCall(insertId, [parentId, block, beforeId])); ctx.runtime.add(insertId); }; if (isFirstNodeElement && !firstNode.isComponent) { hierarchy.push(0); if (ctx.hydratable) { template.push(MARKER.element); } } for (let i = 0; i < ast.tree.length; i++) { if (i <= skip) continue; const node = ast.tree[i]; if (component) { if (isAttributeNode(node) && !node.namespace) { props.push(serializeComponentProp(dom, node, ctx)); } else if (isSpreadNode(node)) { props.push("$$SPREAD"); spreads.unshift(node.value); } else if (isStructuralNode(node) && isElementEnd(node)) { if (component.children) addChildren(component.children); const { createComponent, shouldMergeProps } = serializeCreateComponent( RUNTIME.createComponent, RUNTIME.mergeProps, component.tagName, props, spreads ); if (isFirstNodeComponent) { expressions.push(createComponent); } else { insert(() => currentId, createComponent); } ctx.runtime.add(RUNTIME.createComponent); if (shouldMergeProps) ctx.runtime.add(RUNTIME.mergeProps); props = []; spreads = []; component = void 0; } } else if (isStructuralNode(node)) { if (isAttributesEnd(node)) { const element = elements.at(-1); if (element && element.tagName.includes("-")) { const setup = createFunctionCall(RUNTIME.setupCustomElement, [ currentId, props.length > 0 ? `{ ${props.join(", ")} }` : null ]); scopes.push([expressions.length, setup]); props = []; template.push(` mk-d`); ctx.runtime.add(RUNTIME.setupCustomElement); } if (styles.length > 0) { template.push(` style="${styles.join(";")}"`); styles = []; } if (element && !element.isVoid) template.push(">"); } else if (isChildrenStart(node)) { if (innerHTML) { if ((_b = elements.at(-1)) == null ? void 0 : _b.tagName.includes("-")) { const scope = scopes.pop(); if (scope) expressions.push(scope[1]); } let depth = 0; for (let j = i + 1; j < ast.tree.length; j++) { const node2 = ast.tree[j]; if (isStructuralNode(node2)) { if (isChildrenStart(node2)) { depth++; } else if (isChildrenEnd(node2)) { if (depth === 0) { skip = j + 1; break; } else { depth--; } } } } const element = elements.pop(); if (element) { template.push(element.isVoid ? ` />` : `</${element.tagName}>`); } elementChildIndex = hierarchy.pop(); } else if (elements.at(-1) !== firstNode) { hierarchy.push(elementChildIndex); elementChildIndex = -1; } } else if (isChildrenEnd(node)) { elementChildIndex = hierarchy.pop(); } else if (isElementEnd(node)) { const element = elements.pop(); if (element) { if (element.tagName.includes("-")) { const scope = scopes.pop(); if (scope) { const inserts = expressions.slice(scope[0]); if (inserts.length) { expressions = [ ...expressions.slice(0, scope[0]), createFunctionCall(RUNTIME.scoped, [ `() => { ${inserts.join(";")} }`, scope[1] ]) ]; ctx.runtime.add(RUNTIME.scoped); } else { expressions.push(scope[1]); } } } if (textContent) { template.push(" "); textContent = false; } template.push(element.isVoid ? ` />` : `</${element.tagName}>`); } innerHTML = false; } } else if (isFragmentNode(node)) { if (node.children) { expressions.push( serializeChildren(dom, node.children, { ...ctx, scoped: true, fragment: true }) ); childrenFragment = true; } else { expressions.push('""'); } } else if (isElementNode(node)) { if (isFirstNodeComponent && node == firstNode) { component = node; continue; } if (node.isComponent) component = node; const isCustomElement = node.tagName.includes("-"); if (isCustomElement) customElement = node; const isElement = !component; if (i > 0 && isElement) elementChildIndex++; const dynamic = node.dynamic(); if (dynamic) { if (ctx.hydratable) { if (node.isComponent) { currentId = locals.create(ID.component, nextMarker()); } else if (i > 0) { currentId = locals.create(ID.element, nextElement()); } else { currentId = createRootId(); } } else { currentId = getCurrentElementId(); } } if (ctx.hydratable && i > 0 && dynamic) { template.push(MARKER.element); } if (isElement) { template.push(`<${node.tagName}`); elements.push(node); } } else if (isAttributeNode(node)) { if (node.namespace) { if (node.namespace === "$prop") { if (node.name === "innerHTML") { innerHTML = true; if (customElement) { props.push(`innerHTML: true`); } if (node.observable) { expressions.push( createFunctionCall(RUNTIME.effect, [ ctx.hydratable ? `() => { if (!${RUNTIME.hydrating}) (${currentId}.innerHTML = ${node.value}) }` : `() => void (${currentId}.innerHTML = ${node.value})` ]) ); ctx.runtime.add(RUNTIME.effect); } else { expressions.push( ctx.hydratable ? `if (!${RUNTIME.hydrating}) ${currentId}.innerHTML = ${node.value}` : `${currentId}.innerHTML = ${node.value}` ); } if (ctx.hydratable) ctx.runtime.add(RUNTIME.hydrating); } else if (customElement) { if (!node.children && node.observable) { props.push(`${node.name}: ${node.callId ?? `() => ${node.value}`}`); } else { props.push(serializeComponentProp(dom, node, ctx)); } } else if (node.observable) { if (ctx.groupDOMEffects) { if (node.name === "textContent") { textContent = true; groupedEffects.push( `${getElementId([...hierarchy, 0, 0], elementIds, locals)}.data = ${node.value}` ); } else { groupedEffects.push(`${currentId}.${node.name} = ${node.value}`); } } else { expressions.push( createFunctionCall(RUNTIME.effect, [ `() => void (${currentId}.${node.name} = ${node.value})` ]) ); ctx.runtime.add(RUNTIME.effect); } } else { expressions.push(`${currentId}.${node.name} = ${node.value};`); } } else if (node.namespace === "$class") { addAttrExpression(node, RUNTIME.class); } else if (node.namespace === "$style") { if (!node.dynamic) { styles.push(`${node.name}: ${trimQuotes(node.value)}`); } else { addAttrExpression(node, RUNTIME.style); } } else if (node.namespace === "$cssvar") { if (!node.dynamic) { styles.push(`--${node.name}: ${trimQuotes(node.value)}`); } else { addAttrExpression(node, RUNTIME.style, `--${node.name}`); } } } else if (!node.dynamic) { if (node.name === "style") { styles.push(trimTrailingSemicolon(trimQuotes(node.value))); } else { template.push(` ${node.name}="${escape(trimQuotes(node.value), true)}"`); } } else { addAttrExpression(node, RUNTIME.attr); } } else if (isRefNode(node)) { expressions.push(createFunctionCall(RUNTIME.ref, [currentId, node.value])); ctx.runtime.add(RUNTIME.ref); } else if (isEventNode(node)) { if (node.delegate && ctx.delegateEvents) { ctx.events.add(createStringLiteral(node.type)); expressions.push(`${currentId}.$$${node.type} = ${node.value};`); if (node.data) { expressions.push(`${currentId}.$$${node.type}Data = ${node.data};`); } } else { const args = [currentId, createStringLiteral(node.type), node.value]; if (node.namespace === "$oncapture") args.push(`1 /* CAPTURE */`); expressions.push(createFunctionCall(RUNTIME.listen, args)); ctx.runtime.add(RUNTIME.listen); } } else if (isDirectiveNode(node)) { expressions.push(createFunctionCall(RUNTIME.directive, [currentId, node.name, node.value])); ctx.runtime.add(RUNTIME.directive); } else if (isTextNode(node)) { if (!ctx.hydratable) elementChildIndex++; template.push(node.value); } else if (isExpressionNode(node)) { if (!node.dynamic) { template.push(encode(trimQuotes(node.value))); } else { const shouldInsert = !isFirstNodeExpression || node !== firstNode; if (!initRoot && shouldInsert) createRootId(); if (ctx.hydratable && shouldInsert) template.push(MARKER.expression); const code = !node.children ? node.value : serializeParentExpression(dom, node, ctx, !shouldInsert && RUNTIME.peek); const expression = node.callId ?? (node.observable ? `() => ${code}` : code); if (shouldInsert) { insert(() => locals.create(ID.expression, nextMarker()), expression); } else if (ctx.fragment && ctx.hydratable) { if (!node.observable && !((_c = node.children) == null ? void 0 : _c.length)) { expressions.push(expression); } else if ((_d = node.children) == null ? void 0 : _d.length) { expressions.push( selfInvokingFunction( [ `const $$_signal = ${createFunctionCall(RUNTIME.computed, [`() => ${code}`])};`, "$$_signal();", "return $$_signal;" ].join("") ) ); ctx.runtime.add(RUNTIME.computed); } else { expressions.push( node.callId ?? createFunctionCall(RUNTIME.computed, [`() => ${code}`]) ); ctx.runtime.add(RUNTIME.computed); } } else { expressions.push(expression); ctx.runtime.add(RUNTIME.peek); } } } else if (isSpreadNode(node)) { expressions.push(createFunctionCall(RUNTIME.spread, [currentId, node.value])); ctx.runtime.add(RUNTIME.spread); } } if (template.length) { const expression = createFunctionCall(RUNTIME.createTemplate, [`\`${template.join("")}\``]); if (templateId) { ctx.globals.update(templateId, expression); } else { templateId = ctx.globals.create(ID.template, expression); } ctx.runtime.add(RUNTIME.createTemplate); } else if (templateId) { ctx.globals.update(templateId, createFunctionCall(RUNTIME.createFragment)); ctx.runtime.add(RUNTIME.createFragment); } if (groupedEffects.length) { expressions.push( createFunctionCall(RUNTIME.effect, [`() => { ${groupedEffects.join(";")} }`]) ); ctx.runtime.add(RUNTIME.effect); } if (locals.size > 1 || expressions.length) { return isFirstNodeComponent || isFirstNodeExpression ? expressions.join(";") : childrenFragment && expressions.length === 1 ? expressions[expressions.length - 1] : [ ctx.scoped && `(() => { `, locals.serialize(), "\n", ...(childrenFragment ? expressions.slice(0, -1) : expressions).join(";"), ";", "\n", "\n", `return ${createRootId()}`, ctx.scoped && "})()" ].filter(Boolean).join(""); } else if (templateId) { if (ctx.hydratable) { ctx.runtime.add(RUNTIME.nextTemplate); return createFunctionCall(RUNTIME.nextTemplate, [templateId]); } ctx.runtime.add(RUNTIME.clone); return createFunctionCall(RUNTIME.clone, [templateId]); } return "null"; } }; function getElementId(positions, cache, declarations) { const key = positions.join(""); if (cache[key]) return cache[key]; let id = ID.root, hierarchy = "0"; for (let i = 1; i < positions.length; i++) { const childIndex = positions[i]; const current = hierarchy + childIndex; if (cache[current]) { id = cache[current]; } else { for (let j = 0; j <= childIndex; j++) { const sibling = hierarchy + j; id = cache[sibling] ??= declarations.create( ID.element, `${id}.${j === 0 ? "firstChild" : "nextSibling"}` ); } } hierarchy = current; } return id; } var HYDRATION_MARKER = "<!$>"; var ID2 = { template: "$$_templ" }; var RUNTIME2 = { createComponent: "$$_create_component", customElement: "$$_custom_element", ssr: "$$_ssr", attr: "$$_attr", classes: "$$_classes", styles: "$$_styles", spread: "$$_spread", mergeProps: "$$_merge_props", injectHTML: "$$_inject_html" }; var ssr = { name: "ssr", serialize(ast, ctx) { let skip = -1, merging = false, childrenFragment = false, template = "", templates = [], parts = [], innerHTML, classes = [], styles = [], props = [], merger = [], spreads = [], elements = [], component, customElements = [], commit = (part) => { if (part !== null) parts.push(part); templates.push(template); template = ""; }, marker = () => { template += HYDRATION_MARKER; }, commitInnerHTML = (i, inject = true) => { if (!innerHTML) return; if (inject) { commit(createFunctionCall(RUNTIME2.injectHTML, [innerHTML])); ctx.runtime.add(RUNTIME2.injectHTML); } let depth = 0; for (let j = i + 1; j < ast.tree.length; j++) { const node = ast.tree[j]; if (isStructuralNode(node)) { if (isChildrenStart(node)) { depth++; } else if (isChildrenEnd(node)) { if (depth === 0) { skip = j + 1; break; } else { depth--; } } } } innerHTML = void 0; }, insertCustomElement = () => { var _a, _b, _c; const customEl = customElements.at(-1); if (!customEl) return; if (customEl.children.length) { (customEl.props ??= []).push(`$children: () => [${customEl.children.join(", ")}]`); } const setup = "..." + createFunctionCall(RUNTIME2.customElement, [ `'${customEl.el.tagName}'`, ((_a = customEl.props) == null ? void 0 : _a.length) ? `{ ${customEl.props.join(", ")} }` : ((_b = customEl.spreads) == null ? void 0 : _b.length) ? "undefined" : null, ((_c = customEl.spreads) == null ? void 0 : _c.length) ? `[${customEl.spreads.join(", ")}]` : null ]); const parent = customElements.at(-2); if (parent) { parent.children.push(setup); } else { parts[customEl.part] = setup; } customElements.pop(); ctx.runtime.add(RUNTIME2.customElement); }; const firstNode = ast.tree[0], isFirstNodeElement = isElementNode(firstNode), isFirstNodeComponent = isFirstNodeElement && firstNode.isComponent; if (isFirstNodeElement && !firstNode.isComponent) { template += HYDRATION_MARKER; } for (let i = 0; i < ast.tree.length; i++) { if (i <= skip) continue; const node = ast.tree[i]; if (component) { if (isAttributeNode(node) && !node.namespace) { props.push(serializeComponentProp(ssr, node, ctx)); } else if (isSpreadNode(node)) { props.push("$$SPREAD"); spreads.unshift(node.value); } else if (isStructuralNode(node) && isElementEnd(node)) { const children = component.children; if (children) { props.push(serializeComponentChildrenProp(ssr, children, ctx)); } const { createComponent, shouldMergeProps } = serializeCreateComponent( RUNTIME2.createComponent, RUNTIME2.mergeProps, component.tagName, props, spreads ); commit(createComponent); ctx.runtime.add(RUNTIME2.createComponent); if (shouldMergeProps) ctx.runtime.add(RUNTIME2.mergeProps); props = []; spreads = []; component = void 0; } } else if (isStructuralNode(node)) { if (isAttributesEnd(node)) { const element = elements.at(-1); if (merging) { let $spread = [], $attrs = {}, $$class = {}, $$style = {}; const commitAttrs = () => { if (Object.keys($$class).length) { $attrs.$$class = createObjectLiteral($$class); $$class = {}; } if (Object.keys($$style).length) { $attrs.$$style = createObjectLiteral($$style); $$style = {}; } if (Object.keys($attrs).length) { $spread.push(createObjectLiteral($attrs)); $attrs = {}; } }; for (let i2 = 0; i2 < merger.length; i2++) { const prop = merger[i2]; if (isAttributeNode(prop)) { if (prop.namespace === "$prop") { props.push(serializeComponentProp(ssr, prop, ctx)); } else { let group = prop.namespace ? prop.namespace === "$class" ? $$class : prop.namespace === "$style" || prop.namespace === "$cssvar" ? $$style : $attrs : $attrs; group[`${prop.namespace === "$cssvar" ? "--" : ""}${prop.name}`] = prop.callId ?? prop.value; } } else { commitAttrs(); $spread.push(prop.value); } } commitAttrs(); if (element == null ? void 0 : element.tagName.includes("-")) { const customEl = customElements.at(-1); if (props.length) customEl.props = props; if ($spread.length) customEl.spreads = $spread; props = []; spreads = []; } else if ($spread.length) { commit(createFunctionCall(RUNTIME2.spread, [`[${$spread.join(", ")}]`])); ctx.runtime.add(RUNTIME2.spread); } merger = []; } else { if (classes.length) { const baseClassIdx = classes.findIndex((c) => c.name === "class"), baseClass = classes[baseClassIdx]; if (baseClass && classes.length === 1 && !baseClass.dynamic && baseClass.name === "class") { template += ` class="${escape(trimQuotes(baseClass.value), true)}"`; } else { if (baseClass) classes.splice(baseClassIdx, 1); commit( createFunctionCall(RUNTIME2.classes, [ baseClass ? baseClass.callId ?? baseClass.value : '""', classes.length > 0 ? createClassesObjectLiteral(classes) : null ]) ); ctx.runtime.add(RUNTIME2.classes); } classes = []; } if (styles.length) { const baseStyleIdx = styles.findIndex((style) => style.name === "style"), baseStyle = styles[baseStyleIdx]; if (baseStyle && styles.length === 1 && !baseStyle.dynamic && baseStyle.name === "style") { template += ` style="${escape( trimTrailingSemicolon(trimQuotes(baseStyle.value)), true )}"`; } else { if (baseStyle) styles.splice(baseStyleIdx, 1); commit( createFunctionCall(RUNTIME2.styles, [ baseStyle ? baseStyle.callId ?? baseStyle.value : '""', styles.length > 0 ? createStylesObjectLiteral(styles) : null ]) ); ctx.runtime.add(RUNTIME2.styles); } styles = []; } } merging = false; if (element && !element.isVoid && !element.tagName.includes("-")) { template += ">"; } } else if (isChildrenStart(node)) { if (innerHTML) { const hasCustomElement = customElements.length > 0; insertCu