@maverick-js/compiler
Version:
Maverick toolchain including the analyzer and compiler.
1,409 lines (1,401 loc) • 59.3 kB
JavaScript
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 ? """ : "<";
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 += "&";
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 += "&";
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