UNPKG

@lifeart/gxt

Version:

<img align="right" width="95" height="95" alt="Philosopher’s stone, logo of PostCSS" src="./public/logo.png">

1,349 lines (1,339 loc) • 47.1 kB
import { Preprocessor } from 'content-tag'; import { builders, preprocess, traverse } from '@glimmer/syntax'; import { transformAsync, transformSync } from '@babel/core'; import { S as SYMBOLS, E as EVENT_TYPE, M as MAIN_IMPORT, C as CONSTANTS } from './symbols-KamXCUHQ.js'; let flags; let bindings = /* @__PURE__ */ new Set(); function setBindings(b) { bindings = b; } function setFlags(f) { flags = f; } let ctxIndex = 0; function nextCtxName() { return `ctx${ctxIndex++}`; } function escapeString(str) { if (typeof str !== "string") { throw new Error("Not a string"); } try { if (typeof JSON.parse(str) !== "string") { return JSON.stringify(str); } return JSON.stringify(JSON.parse(str)); } catch (e) { return JSON.stringify(str); } } function isPath(str) { return str.startsWith("$:"); } function resolvePath(str) { if (bindings.has(str)) { return str; } if (str === "has-block-params") { str = str.replace("has-block-params", `${SYMBOLS.$_hasBlockParams}.bind(this, $slots)`); } else if (str === "has-block") { str = str.replace("has-block", `${SYMBOLS.$_hasBlock}.bind(this, $slots)`); } else if (str === "component") { return SYMBOLS.COMPONENT_HELPER; } else if (str === "helper") { return SYMBOLS.HELPER_HELPER; } else if (str === "modifier") { return SYMBOLS.MODIFIER_HELPER; } return toSafeJSPath(toOptionalChaining(str).replace("$:", "").replace("@", `this[${SYMBOLS.$args}].`)); } function toSafeJSPath(str) { if (str.includes("(") || !str.includes(".")) { return str; } const parts = str.split("."); const result = parts.map((p) => { if (p.endsWith("?")) { if (isSafeKey(p.slice(0, -1))) { return p; } else if (p.includes("[")) { return p.slice(0, -1); } else { return `["${p.slice(0, -1)}"]?`; } } else if (p.includes("[")) { return p; } else if (isSafeKey(p)) { return p; } else { return `["${p}"]`; } }).reduce((acc, el) => { if (el.startsWith("[")) { return acc + el; } else { if (acc.length) { return acc + "." + el; } else { return el; } } }, ""); return result; } function toOptionalChaining(str) { if (typeof str !== "string") { return str; } if (str.includes("'") || str.includes('"')) { return str; } if (str.includes("$_")) { return str; } else if (str.includes("?.")) { return str; } else if (str.split(".").length < 3) { return str; } const result = str.split("...").map((el) => el.split(".").join("?.")).join("..."); if (result.includes("this?.")) { return result.replace("this?.", "this."); } else if (result.includes(`this[${SYMBOLS.$args}]?.`)) { return result.replace(`this[${SYMBOLS.$args}]?.`, `this[${SYMBOLS.$args}].`); } return result; } function serializePath(p, wrap = flags.IS_GLIMMER_COMPAT_MODE) { if (typeof p !== "string") { return p; } if (p.includes("...")) { return p; } const isFunction = p.startsWith("$:(") || p.startsWith("$:...(") || p.startsWith("$:function"); if (wrap === false) { return resolvePath(p); } if (isFunction) { return resolvePath(p); } return `() => ${resolvePath(p)}`; } function resolvedChildren(els) { return els.filter((el) => { if (el.type === "CommentStatement" || el.type === "MustacheCommentStatement") { return false; } if (el.type === "TextNode" && el.chars.trim().length === 0 && el.chars.includes("\n")) { return false; } return true; }); } function serializeChildren(children, ctxName) { if (children.length === 0) { return ""; } return `${children.map((child) => { if (typeof child === "string") { if (isPath(child)) { return serializePath(child); } return `${SYMBOLS.TEXT}(${SYMBOLS.API}(this),${escapeString(child)})`; } return serializeNode(child, ctxName); }).join(", ")}`; } function toChildArray(childs, ctxName = "this") { if (!childs) { return "[]"; } return `[${childs.map((child) => serializeNode(child, ctxName)).filter((el) => el).join(", ")}]`; } function toPropName(name) { let result = name.replace("@", ""); return isSafeKey(result) ? result : JSON.stringify(result); } function serializeAttribute(key, value) { if (typeof value === "boolean") { return `['${key}', ${String(value)}]`; } else if (typeof value === "number") { return `['${key}', ${value}]`; } else if (value === null) { return `['${key}', null]`; } else if (typeof value === "undefined") { return `['${key}', undefined]`; } if (isPath(value)) { return `['${key}', ${serializePath(value)}]`; } return `['${key}', ${escapeString(value)}]`; } function serializeProp(attr) { if (attr[1] === null) { return `${toPropName(attr[0])}: null`; } else if (typeof attr[1] === "boolean") { return `${toPropName(attr[0])}: ${attr[1]}`; } else if (typeof attr[1] === "number") { return `${toPropName(attr[0])}: ${attr[1]}`; } else if (typeof attr[1] === "undefined") { return `${toPropName(attr[0])}: undefined`; } const isScopeValue = isPath(attr[1]); const key = toPropName(attr[0]); return `${key}: ${isScopeValue ? serializePath(attr[1]) : escapeString(attr[1])}`; } function isSafeKey(key) { return /^[a-z_$@][a-z0-9_$]*$/i.test(key); } function toComponent(ref, args, ctx) { if (ref.includes(".")) { return `${SYMBOLS.DYNAMIC_COMPONENT}($:()=>${ref},${args},${ctx})`; } else { return `${SYMBOLS.COMPONENT}(${ref},${args},${ctx})`; } } function toObject(args) { return `{${args.map((attr) => serializeProp(attr)).join(", ")}}`; } function toArray(args) { return `[${args.map((attr) => serializeAttribute(attr[0], attr[1])).join(", ")}]`; } function toArgs(args, slots, props) { if (flags.IS_GLIMMER_COMPAT_MODE === false) { const extraArgs = [...args]; if (props !== "{}" && !props.includes(SYMBOLS.EMPTY_DOM_PROPS)) { extraArgs.push([`$:[${SYMBOLS.$PROPS_SYMBOL}]`, `$:${props}`]); } if (slots !== "{}") { extraArgs.push([`$:[${SYMBOLS.$SLOTS_SYMBOL}]`, `$:${slots}`]); } const result2 = toObject(extraArgs); return result2; } const result = `${SYMBOLS.ARGS}(${toObject(args)},${slots},${props})`; return result.replace(`${SYMBOLS.ARGS}({},{},{})`, "{}").replace("$_args({},{},$_edp)", "{}"); } function hasStableChildsForControlNode(childs) { if (childs === null) { return true; } let hasStableChild = false; if (childs.length === 1 && typeof childs[0] === "object") { const child = childs[0]; if (child === null) { return true; } if ("isControl" in child) { hasStableChild = false; } else { if (child.events.filter(([id]) => id === EVENT_TYPE.ON_CREATED).length) { return false; } hasStableChild = true; } } return hasStableChild; } function serializeNode(node, ctxName = "this") { if (node === null) { return null; } if (typeof node === "object" && "isControl" in node) { const key = `@${node.type}`; const arrayName = node.condition; const paramNames = node.blockParams; const childs = (node.children || []).filter((el) => el !== null); const isSync = node.isSync; const inverses = node.inverse; let eachKey = node.key; if (eachKey === "@index") { console.warn("@index identity not supported"); eachKey = "@identity"; } const newCtxName = nextCtxName(); if (key === "@yield") { return `$:${SYMBOLS.SLOT}(${escapeString(eachKey)}, () => [${paramNames.join(",")}], $slots, ${ctxName})`; } else if (key === "@in-element") { return `$:${SYMBOLS.$_inElement}(${arrayName}, $:(${newCtxName}) => [${serializeChildren(childs, newCtxName)}], ${ctxName})`; } else if (key === "@each") { if (paramNames.length === 0) { paramNames.push("$noop"); } if (paramNames.length === 1) { paramNames.push("$index"); } let hasStableChild = hasStableChildsForControlNode(childs); const FN_NAME = isSync ? SYMBOLS.EACH_SYNC : SYMBOLS.EACH; const EACH_KEY = eachKey ? escapeString(eachKey) : null; const FN_FN_ARGS = `${paramNames.join(",")},${newCtxName}`; const indexParamName = paramNames[1]; const paramBounds = new RegExp(`(?<!\\.)\\b${indexParamName}\\b(?!(=|'|"|:)[^ ]*)`, "g"); if (hasStableChild) { let childText = toChildArray(childs, newCtxName).split(paramBounds).filter(Boolean).join(`${indexParamName}.value`); if (childs.length === 1) { const length = childText.length; childText = childText.slice(1, length - 1); } return `${FN_NAME}(${arrayName}, (${FN_FN_ARGS}) => ${childText}, ${EACH_KEY}, ${ctxName})`; } else { const extraContextName = nextCtxName(); let childText = toChildArray(childs, extraContextName).split(paramBounds).filter(Boolean).join(`${indexParamName}.value`); return `${FN_NAME}(${arrayName}, (${FN_FN_ARGS}) => [${SYMBOLS.$_ucw}((${extraContextName}) => ${childText}, ${newCtxName})], ${EACH_KEY}, ${ctxName})`; } } else if (key === "@if") { let hasStableTrueChild = hasStableChildsForControlNode(childs); let hasStableFalseChild = hasStableChildsForControlNode(inverses); hasStableTrueChild = false; hasStableFalseChild = false; let trueBranch = `(${newCtxName}) => ${toChildArray(childs, newCtxName)}`; let extraContextName = nextCtxName(); if (!hasStableTrueChild) { trueBranch = `(${newCtxName}) => ${SYMBOLS.$_ucw}((${extraContextName}) => ${toChildArray(childs, extraContextName)}, ${newCtxName})`; } let falseBranch = `(${newCtxName}) => ${toChildArray(inverses, newCtxName)}`; if (!hasStableFalseChild) { falseBranch = `(${newCtxName}) => ${SYMBOLS.$_ucw}((${extraContextName}) => ${toChildArray(inverses, extraContextName)}, ${newCtxName})`; } return `${SYMBOLS.IF}(${arrayName}, ${trueBranch}, ${falseBranch}, ${ctxName})`; } } else if (typeof node === "object" && node.tag && (bindings.has(node.tag) || node.tag.startsWith("$:$_") || node.tag.includes("."))) { const hasSplatAttrs = node.attributes.find((attr) => { return attr[0] === "...attributes"; }); const attributes = node.attributes.filter((attr) => { return attr[0] !== "...attributes"; }); const args = attributes.filter((attr) => { return attr[0].startsWith("@"); }); const attrs = attributes.filter((attr) => { return !attr[0].startsWith("@"); }); const props = node.properties; let secondArg = hasSplatAttrs ? `[[...$fw[0], ...${toArray(props)}],[...$fw[1], ...${toArray(attrs)}],[...$fw[2],...${toArray(node.events)}]]` : `[${toArray(props)},${toArray(attrs)},${toArray(node.events)}]`; let isSecondArgEmpty = secondArg === "[[],[],[]]"; if (isSecondArgEmpty) { secondArg = SYMBOLS.EMPTY_DOM_PROPS; } if (node.selfClosing) { return toComponent(node.tag, toArgs(args, "{}", secondArg), ctxName); } else { const slots = node.children.filter((child) => { if (typeof child === "string") { return false; } else if ("isControl" in child) { return false; } else { return child.tag.startsWith(":"); } }); if (slots.length === 0) { slots.push(node); } const serializedSlots = slots.map((slot) => { const sContext = nextCtxName(); const slotChildren = serializeChildren(slot.children, sContext); const hasBlockParams = slot.blockParams.length > 0; const slotName = slot.tag.startsWith(":") ? slot.tag.slice(1) : "default"; return `${slotName}_: ${hasBlockParams},${slotName}: (${[sContext, ...slot.blockParams].join(",")}) => [${slotChildren}]`; }); const slotsObj = `{${serializedSlots.join(",")}}`; return toComponent(node.tag, toArgs(args, slotsObj, secondArg), ctxName); } } else if (typeof node === "object" && node.tag) { const hasSplatAttrs = node.attributes.find((attr) => { return attr[0] === "...attributes"; }); const attributes = node.attributes.filter((attr) => { return attr[0] !== "...attributes"; }); let tagProps = `[${toArray(node.properties)},${toArray(attributes)},${toArray(node.events)}${hasSplatAttrs ? `,$fw` : ""}]`; if (tagProps === "[[],[],[]]") { tagProps = SYMBOLS.EMPTY_DOM_PROPS; } return `${SYMBOLS.TAG}('${node.tag}', ${tagProps}, [${serializeChildren(node.children, ctxName)}], ${ctxName})`; } else { if (typeof node === "string" || typeof node === "number") { if (typeof node === "number") { node = String(node); } if (isPath(node)) { return serializePath(node); } else { return `${SYMBOLS.TEXT}(${SYMBOLS.API}(this),${escapeString(node)})`; } } throw new Error("Unknown node type: " + JSON.stringify(node, null, 2)); } } function getScopeBindings(path, bindings = /* @__PURE__ */ new Set()) { Object.keys(path.scope.bindings).forEach((key) => { bindings.add(key); }); if (path.parentPath) { getScopeBindings(path.parentPath, bindings); } return bindings; } function processTemplate(hbsToProcess, mode) { return function babelPlugin(babel) { const { types: t } = babel; return { name: "ast-transform", // not required visitor: { VariableDeclarator(path, context) { if (mode !== "development") { return; } if (!context.tokensForHotReload) { return; } const tokensForHotReload = context.tokensForHotReload; if (path.node.id.type === "Identifier") { if (path.node.id.name === "existingTokensToReload") { path.node.init = t.arrayExpression(tokensForHotReload.map((token) => { return t.stringLiteral(token); })); } } }, ExportNamedDeclaration(path, context) { if (mode !== "development") { return; } if (!context.tokensForHotReload) { context.tokensForHotReload = []; } if (path.node.declaration) { if (path.node.declaration.type === "VariableDeclaration") { const declarations = path.node.declaration.declarations; if (declarations.length === 1) { const declaration = declarations[0]; if (declaration.id.type === "Identifier") { const existingTokens = context.tokensForHotReload; existingTokens.push(declaration.id.name); } } } else if (path.node.declaration.type === "ClassDeclaration") { const declaration = path.node.declaration; if (declaration.id.type === "Identifier") { const existingTokens = context.tokensForHotReload; existingTokens.push(declaration.id.name); } } } }, ClassBody: { enter(_, context) { context.isInsideClassBody = true; if (_.node.body.length === 1) { context.isInsideClassBody = false; } }, exit(_, context) { context.isInsideClassBody = false; } }, ClassMethod(path) { if (path.node.key.name === "$static") { path.replaceWith(t.classProperty( t.identifier(SYMBOLS.$template), // hbs literal t.taggedTemplateExpression(t.identifier("hbs"), path.node.body.body[0].expression.arguments[0]), null, null, true )); } }, CallExpression(path) { if (path.node.callee && path.node.callee.type === "Identifier") { if (path.node.callee.name === "scope") { path.remove(); } else if (path.node.callee.name === "template") { path.replaceWith(t.taggedTemplateExpression(t.identifier("hbs"), path.node.arguments[0])); } else if (path.node.callee.name === "formula") { if (mode === "production") { if (path.node.arguments.length === 2) { path.node.arguments.pop(); } } } else if (path.node.callee.name === "getRenderTargets") { if (mode === "production") { if (path.node.arguments.length === 2) { path.node.arguments.pop(); } } } } }, ImportDeclaration(path) { if (path.node.source.value === "@ember/template-compiler") { path.node.source.value = MAIN_IMPORT; path.node.specifiers.forEach((specifier) => { specifier.local.name = "hbs"; specifier.imported.name = "hbs"; }); } }, Program(path) { const PUBLIC_API = Object.values(SYMBOLS); const IMPORTS = PUBLIC_API.map((name) => { return t.importSpecifier(t.identifier(name), t.identifier(name)); }); path.node.body.unshift(t.importDeclaration(IMPORTS, t.stringLiteral(MAIN_IMPORT))); }, ReturnStatement: { enter(_, context) { context.isInsideReturnStatement = true; }, exit(_, context) { context.isInsideReturnStatement = false; } }, TaggedTemplateExpression(path, context) { if (path.node.tag.name === "hbs") { const template = path.node.quasi.quasis[0].value.raw; const isInsideClassBody = context.isInsideClassBody === true; const hasThisInTemplate = template.includes("this"); let hasThisAccess = isInsideClassBody === true || hasThisInTemplate; if (context.isInsideReturnStatement === true) { hasThisAccess = true; } hbsToProcess.push({ template, flags: { hasThisAccess }, bindings: getScopeBindings(path) }); path.replaceWith(t.identifier("$placeholder")); } } } }; }; } function stripGXTDebug(babel) { const { types: t } = babel; return { name: "string-gxt-debug-info-transform", // not required visitor: { BinaryExpression(path) { if (t.isLiteral(path.node.right)) { if (path.node.right.value === "/tests.html") { path.replaceWith(t.booleanLiteral(false)); } } }, ClassMethod(path) { if (path.node.kind === "constructor") { if (path.node.params.length === 2) { if (path.node.params[1].name === "debugName") { path.node.params.pop(); } } } }, ExpressionStatement(path) { if (path.node.expression && path.node.expression.type === "CallExpression") { if (path.node.expression.callee.type === "MemberExpression") { if (path.node.expression.callee.object.name === "console") { path.remove(); } } } }, ClassProperty(path) { if (path.node.key.name === "_debugName") { path.remove(); } }, FunctionDeclaration(path) { const nodeName = path.node.id.name; if (nodeName === "formula" || nodeName === "cell") { path.node.params.pop(); } }, AssignmentPattern(path) { if (path.node.left.name === "debugName") { path.remove(); } }, NewExpression(path) { if (path.node.callee && path.node.callee.type === "Identifier") { if (path.node.callee.name === "MergedCell" || path.node.callee.name === "Cell") { path.node.arguments.pop(); } } }, CallExpression(path) { if (path.node.callee && path.node.callee.type === "Identifier") { const name = path.node.callee.name; if (name === "addToTree" && path.node.arguments.length === 3) { path.node.arguments.pop(); } else if (name === "cell" || name === "formula" || name === "resolveRenderable") { if (path.node.arguments.length === 2) { path.node.arguments.pop(); } } } } } }; } const booleanAttributes = ["checked", "readonly", "autoplay", "allowfullscreen", "async", "autofocus", "autoplay", "controls", "default", "defer", "disabled", "formnovalidate", "inert", "ismap", "itemscope", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "required", "reversed", "selected"]; const propertyKeys = [ "class", "shadowrootmode", // boolean attributes (https://meiert.com/en/blog/boolean-attributes-of-html/) "checked", "readonly", "value", "autoplay", "allowfullscreen", "async", "autofocus", "autoplay", "controls", "default", "defer", "disabled", "formnovalidate", "inert", "ismap", "itemscope", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "required", "reversed", "selected" ]; const COMPILE_TIME_HELPERS = ["has-block-params", "has-block"]; const BUILTIN_HELPERS = { "or": SYMBOLS.$__or, "and": SYMBOLS.$__and, "eq": SYMBOLS.$__eq, "not": SYMBOLS.$__not, "if": SYMBOLS.$__if, "debugger": `${SYMBOLS.$__debugger}.call`, "log": SYMBOLS.$__log, "array": SYMBOLS.$__array, "hash": SYMBOLS.$__hash, "fn": SYMBOLS.$__fn }; const SPECIAL_HELPERS = [SYMBOLS.HELPER_HELPER, SYMBOLS.MODIFIER_HELPER, SYMBOLS.COMPONENT_HELPER]; function patchNodePath(node, bindings) { if (node.path.type !== "PathExpression") { return; } if (bindings.has(node.path.original)) { return; } if (node.path.original === "unless") { node.path.original = BUILTIN_HELPERS["if"]; if (node.params.length === 3) { const condTrue = node.params[1]; const condFalse = node.params[2]; node.params[1] = condFalse; node.params[2] = condTrue; } else { node.params.push(); const condTrue = node.params[1]; const condFalse = { type: "StringLiteral", value: "", original: "", loc: node.loc }; node.params[1] = condFalse; node.params[2] = condTrue; } } else if (node.path.original === "debugger") { node.path.original = BUILTIN_HELPERS["debugger"]; node.params.unshift(builders.path("this")); } else if (node.path.original in BUILTIN_HELPERS) { node.path.original = BUILTIN_HELPERS[node.path.original]; } if (node.path.original.includes(".")) { node.path.original = toSafeJSPath(toOptionalChaining(node.path.original)); } } function convert(seenNodes, flags, bindings = /* @__PURE__ */ new Set()) { setFlags(flags); setBindings(bindings); function serializeParam(p) { if (typeof p !== "string") { if (typeof p === "object" && p !== null) { let t = ToJSType(p, false); if (typeof t !== "string") { return String(t); } return toOptionalChaining(t); } return String(p); } return isPath(p) ? serializePath(p, false) : escapeString(p); } function toModifier(nodePath, params, hash) { if (flags.WITH_MODIFIER_MANAGER) { return `${SYMBOLS.$_maybeModifier}($:${resolvePath(nodePath)},$n,[${params.map((p) => serializeParam(p)).join(",")}],${toObject(hash)})`; } else { return `$:${resolvePath(nodePath)}($n,${params.map((p) => serializeParam(p)).join(",")})`; } } function hasResolvedBinding(fnPath) { let hasBinding = fnPath.startsWith("$_") || fnPath.startsWith("this.") || fnPath.startsWith("this[") || bindings.has(fnPath.split(".")[0]?.split("?")[0]); if (COMPILE_TIME_HELPERS.includes(fnPath)) { hasBinding = false; } return hasBinding; } function toHelper(nodePath, params, hash) { const fnPath = resolvePath(nodePath); if (SPECIAL_HELPERS.includes(fnPath)) { return `$:${fnPath}([${params.map((p) => serializeParam(p)).join(",")}],${toObject(hash)})`; } let hasBinding = hasResolvedBinding(fnPath); if ((!hasBinding || flags.WITH_HELPER_MANAGER) && !nodePath.startsWith("$_")) { if (!hasBinding) { hash.push([CONSTANTS.SCOPE_KEY, `$:()=>this[${SYMBOLS.$args}]?.${CONSTANTS.SCOPE_KEY}`]); } return `$:${SYMBOLS.$_maybeHelper}(${hasBinding ? fnPath : JSON.stringify(fnPath)},[${params.map((p) => serializeParam(p)).join(",")}],${toObject(hash)})`; } else { return `$:${fnPath}(${params.map((p) => serializeParam(p)).join(",")})`; } } function ToJSType(node, wrap = true) { seenNodes.add(node); if (node.type === "ConcatStatement") { return `$:() => [${node.parts.map((p) => { if (p.type === "TextNode") { seenNodes.add(p); return escapeString(p.chars); } let value = ToJSType(p, false); return value; }).join(",")}].join('')`; } else if (node.type === "UndefinedLiteral") { return void 0; } else if (node.type === "NullLiteral") { return null; } else if (node.type === "BooleanLiteral") { return node.value; } else if (node.type === "SubExpression") { if (node.path.type !== "PathExpression") { return null; } patchNodePath(node, bindings); const hashArgs = node.hash.pairs.map((pair) => { return [pair.key, ToJSType(pair.value, false)]; }); if (node.path.original === "element") { return `$:function(args){${SYMBOLS.$_GET_ARGS}(this, arguments);const $fw = ${SYMBOLS.$_GET_FW}(this, arguments);const $slots = ${SYMBOLS.$_GET_SLOTS}(this, arguments);return{[${SYMBOLS.$nodes}]:[${SYMBOLS.TAG}(${ToJSType(node.params[0])}, $fw,[()=>${SYMBOLS.SLOT}('default',()=>[],$slots,this)], this)], ctx: this};}`; } else if (node.path.original === SYMBOLS.$__hash) { return `$:${SYMBOLS.$__hash}(${toObject(hashArgs)})`; } return toHelper(node.path.original, node.params, hashArgs); } else if (node.type === "NumberLiteral") { return node.value; } if (node.type === "StringLiteral") { return escapeString(node.value); } else if (node.type === "TextNode") { if (node.chars.trim().length === 0 && node.chars.includes("\n")) { return null; } else if (node.chars.trim().length === 0 && node.chars.length > 1) { return null; } return node.chars; } else if (node.type === "ElementNode") { return ElementToNode(node); } else if (node.type === "PathExpression") { return `$:${toOptionalChaining(resolvePath(node.original))}`; } else if (node.type === "MustacheStatement") { if (node.path.type !== "PathExpression") { if (node.path.type === "BooleanLiteral" || node.path.type === "UndefinedLiteral" || node.path.type === "NumberLiteral" || node.path.type === "NullLiteral") { return node.path.value; } else if (node.path.type === "SubExpression") { return `${wrap ? `$:() => ` : ""}${ToJSType(node.path)}`; } else if (node.path.type === "StringLiteral") { return escapeString(node.path.value); } return null; } patchNodePath(node, bindings); const hashArgs = node.hash.pairs.map((pair) => { return [pair.key, ToJSType(pair.value)]; }); if (node.path.original === "yield" || node.path.original === "outlet") { let slotName = node.hash.pairs.find((p) => p.key === "to")?.value || "default"; if (typeof slotName !== "string") { slotName = ToJSType(slotName); } return { type: "yield", isControl: true, blockParams: node.params.map((p) => ToJSType(p)), children: [], inverse: [], key: slotName, condition: "", isSync: true }; } if (node.params.length === 0) { if (node.path.original === SYMBOLS.$__hash) { return `${wrap ? `$:() => ` : ""}${ToJSType(node.path)}(${toObject(hashArgs)})`; } if (hashArgs.length === 0) { const fnPath = resolvePath(node.path.original); let hasBinding = hasResolvedBinding(fnPath); if (!hasBinding) { return toHelper(node.path.original, [], hashArgs); } else { return ToJSType(node.path); } } return toHelper(node.path.original, [], hashArgs); } else { return `${wrap ? `$:() => ` : ""}${toHelper(node.path.original, node.params, hashArgs)}`; } } else if (node.type === "BlockStatement") { if (!node.params.length) { return null; } node.program.blockParams.forEach((p) => { bindings.add(p); }); const childElements = resolvedChildren(node.program.body); const elseChildElements = node.inverse?.body ? resolvedChildren(node.inverse.body) : void 0; if (!childElements.length) { return null; } if (node.path.type !== "PathExpression") { return null; } const name = node.path.original; const keyPair = node.hash.pairs.find((p) => p.key === "key"); const syncPair = node.hash.pairs.find((p) => p.key === "sync"); let keyValue = null; let syncValue = false; if (keyPair) { if (keyPair.value.type === "StringLiteral") { keyValue = keyPair.value.original; } else { keyValue = ToJSType(keyPair.value); } } if (syncPair) { if (syncPair.value.type === "BooleanLiteral") { syncValue = syncPair.value.value; } else { syncValue = ToJSType(syncPair.value); } } const children = childElements?.map((el) => ToJSType(el)) ?? null; const inverse = elseChildElements?.map((el) => ToJSType(el)) ?? null; const cleanupBindings = () => { node.program.blockParams.forEach((p) => { bindings.delete(p); }); }; try { if (name === "in-element") { return { type: "in-element", isControl: true, condition: ToJSType(node.params[0]), blockParams: [], children, inverse: [], isSync: true, key: "" }; } else if (name === "unless") { return { type: "if", isControl: true, condition: serializePath(ToJSType(node.params[0])), blockParams: node.program.blockParams, children: inverse, inverse: children, isSync: syncValue, key: keyValue }; } else if (name === "let") { let fixChildScopes = function(str) { Object.keys(namesToReplace).forEach((key) => { const re = new RegExp(`(?<!\\.)\\b${key}\\b(?!(=|'|"|:)[^ ]*)`, "g"); if (primitives.has(key)) { str = str.replace(re, namesToReplace[key]); } else { str = str.replace(re, `${namesToReplace[key]}()`); } }); return str; }; const varScopeName = Math.random().toString(36).substring(7); const namesToReplace = {}; const primitives = /* @__PURE__ */ new Set(); const vars = node.params.map((p, index) => { let isString = p.type === "StringLiteral"; let isBoolean = p.type === "BooleanLiteral"; let isNumber = p.type === "NumberLiteral"; let isNull = p.type === "NullLiteral"; let isUndefined = p.type === "UndefinedLiteral"; let originalName = node.program.blockParams[index]; let newName = `Let_${originalName}_${varScopeName}`; namesToReplace[originalName] = `${newName}`; let castToPrimitive = isString || isBoolean || isNull || isUndefined || isNumber; if (castToPrimitive) { primitives.add(originalName); return `let ${newName} = ${ToJSType(p, false)};`; } else { return `let ${newName} = $:() => ${ToJSType(p)};`; } }); const result = `$:...(() => {let self = this;${vars.join("").split("this.").join("self.")}return [${fixChildScopes(serializeChildren( children, "this" // @todo - fix possible context floating here ))}]})()`; return result; } return { type: name, isControl: true, condition: serializePath(ToJSType(node.params[0])), blockParams: node.program.blockParams, isSync: syncValue, children, inverse, key: keyValue }; } finally { cleanupBindings(); } } } function hasStableChild(node) { const childrenWithoutEmptyTextNodes = resolvedChildren(node.children); if (childrenWithoutEmptyTextNodes.length === 0) { return true; } const firstChild = childrenWithoutEmptyTextNodes[0]; if (firstChild.type === "TextNode") { return true; } if (firstChild.type === "ElementNode" && !firstChild.tag.startsWith(":") && firstChild.tag.toLowerCase() === firstChild.tag) { return true; } return false; } const propsToCast = { class: "", // className readonly: "readOnly" }; function isAttribute(name) { return !propertyKeys.includes(name); } const convertedNodes = /* @__PURE__ */ new WeakSet(); function ElementToNode(element) { if (element.tag === "math" && !convertedNodes.has(element)) { convertedNodes.add(element); const parent = builders.element(`$:${SYMBOLS.MATH_NAMESPACE}`, { children: [element] }); return ElementToNode(parent); } else if (element.tag === "svg" && !convertedNodes.has(element)) { convertedNodes.add(element); const parent = builders.element(`$:${SYMBOLS.SVG_NAMESPACE}`, { children: [element] }); return ElementToNode(parent); } else if (element.tag === "foreignObject" && !convertedNodes.has(element)) { convertedNodes.add(element); const parent = builders.element(`$:${SYMBOLS.HTML_NAMESPACE}`, { children: element.children }); element.children = [parent]; return ElementToNode(parent); } element.blockParams.forEach((p) => { bindings.add(p); }); const children = resolvedChildren(element.children).map((el) => ToJSType(el)).filter((el) => el !== null); element.blockParams.forEach((p) => { bindings.delete(p); }); const rawStyleEvents = element.attributes.filter((attr) => { return attr.name.startsWith("style."); }); element.attributes = element.attributes.filter((attr) => { return !rawStyleEvents.includes(attr); }); const styleEvents = rawStyleEvents.map((attr) => { const propertyName = attr.name.split(".").pop(); const value = attr.value.type === "TextNode" ? escapeString(attr.value.chars) : ToJSType(attr.value); const isPath2 = typeof value === "string" ? value.includes(".") : false; return [EVENT_TYPE.ON_CREATED, `$:function($v,$n){$n.style.setProperty('${propertyName}',$v);}.bind(null,${SYMBOLS.$_TO_VALUE}(${isPath2 ? `$:()=>${value}` : value}))`]; }); const extraEvents = []; const node = { tag: element.tag, selfClosing: element.selfClosing, blockParams: element.blockParams, hasStableChild: hasStableChild(element), attributes: element.attributes.filter((el) => isAttribute(el.name)).map((attr) => { const rawValue = ToJSType(attr.value); return [attr.name, rawValue]; }), properties: element.attributes.filter((el) => !isAttribute(el.name)).map((attr) => { const rawValue = ToJSType(attr.value); if (booleanAttributes.includes(attr.name) && attr.value.type === "TextNode" && attr.value.chars === "") { const castedProp2 = propsToCast[attr.name]; return [typeof castedProp2 === "string" ? castedProp2 : attr.name, true]; } const castedProp = propsToCast[attr.name]; return [typeof castedProp === "string" ? castedProp : attr.name, rawValue]; }), events: [...extraEvents, ...styleEvents, ...element.modifiers.map((mod) => { if (mod.path.type !== "PathExpression") { return null; } const hashArgs = mod.hash.pairs.map((pair) => { return [pair.key, ToJSType(pair.value, false)]; }); if (mod.path.original === "on") { const firstParam = mod.params[0]; if (firstParam.type === "StringLiteral") { const tail = mod.params.slice(2).map((p) => ToJSType(p)).join(","); return [firstParam.original, `$:($e, $n) => ${ToJSType(mod.params[1])}($e, $n${tail.length ? `,${tail}` : ""})`]; } else { return null; } } else { return [ // @me here EVENT_TYPE.ON_CREATED, `$:($n) => ${toModifier(mod.path.original, mod.params, hashArgs)}` ]; } }).filter((el) => el !== null)], children }; if (children.length === 1 && typeof children[0] === "string") { const v = children[0]; if (!v.includes(SYMBOLS.SLOT) && !node.tag.startsWith(":") && node.tag.toLowerCase() === node.tag && !v.includes("...")) { node.children = []; node.events.push([EVENT_TYPE.TEXT_CONTENT, v]); } } return node; } return { ToJSType, ElementToNode }; } function isSimpleElement(element) { const tag = element.tag; if (tag.includes(".") || tag.startsWith(":")) { return false; } return tag.toLowerCase() === tag; } function isAllChildNodesSimpleElements(children) { return children.every((child) => { if (child.type === "ElementNode") { return isSimpleElement(child) && isAllChildNodesSimpleElements(child.children); } else if (child.type === "TextNode") { return true; } else if (child.type === "MustacheCommentStatement") { return true; } else if (child.type === "CommentStatement") { return true; } else if (child.type === "MustacheStatement") { if (child.path.type !== "PathExpression") { return false; } else if (child.path.original === "yield" || child.path.original === "outlet") { return false; } else if (child.path.data) { return true; } } return false; }); } function processTransformedFiles(babelResult, hbsToProcess, seenNodes, flags, fileName, programs, programResults) { const txt = babelResult?.code ?? ""; const globalFlags = flags; hbsToProcess.forEach((content) => { const flags2 = content.flags; const bindings = content.bindings; const { ToJSType, ElementToNode } = convert(seenNodes, globalFlags, bindings); const ast = preprocess(content.template); const program = { meta: flags2, bindings, template: [] }; traverse(ast, { Template(node) { const isSimple = isAllChildNodesSimpleElements(node.body); if (!isSimple && flags2.hasThisAccess === false) { flags2.hasThisAccess = true; } }, MustacheStatement(node) { if (seenNodes.has(node)) { return; } seenNodes.add(node); program.template.push(ToJSType(node)); }, TextNode(node) { if (seenNodes.has(node)) { return; } seenNodes.add(node); if (node.chars.trim().length !== 0) { program.template.push(ToJSType(node)); } }, BlockStatement(node) { if (seenNodes.has(node)) { return; } seenNodes.add(node); program.template.push(ToJSType(node)); }, ElementNode: { enter(node) { if (seenNodes.has(node)) { return; } node.blockParams.forEach((p) => { bindings.add(p); }); seenNodes.add(node); program.template.push(ElementToNode(node)); }, exit(node) { node.blockParams.forEach((p) => { bindings.delete(p); }); } } }); programs.push(program); }); programs.forEach((program) => { const input = program.template; setBindings(program.bindings); const results = input.reduce((acc, node) => { const serializedNode = serializeNode(node); if (typeof serializedNode === "string") { acc.push(serializedNode); return acc; } return acc; }, []); const isClass = txt?.includes("template = ") ?? false; const isTemplateTag = fileName.endsWith(".gts") || fileName.endsWith(".gjs"); let result = ""; let finContext = program.meta.hasThisAccess ? "this" : "this"; const hasFw = results.some((el) => el.includes("$fw")); const hasSlots = results.some((el) => el.includes("$slots")); const slotsResolution = `const $slots = ${SYMBOLS.$_GET_SLOTS}(this, arguments);`; const maybeFw = `${hasFw ? `const $fw = ${SYMBOLS.$_GET_FW}(this, arguments);` : ""}`; const maybeSlots = `${hasSlots ? slotsResolution : ""}`; const declareRoots = `const roots = [${results.join(", ")}];`; const declareReturn = `return ${SYMBOLS.FINALIZE_COMPONENT}(roots, ${finContext});`; if (isTemplateTag) { result = `function () { ${maybeFw} ${SYMBOLS.$_GET_ARGS}(this, arguments); ${maybeSlots} ${declareRoots} ${declareReturn} }`; } else { result = isClass ? `() => { ${maybeSlots} ${maybeFw} ${declareRoots} ${declareReturn} }` : `(() => { ${SYMBOLS.$_GET_ARGS}(this, arguments); ${maybeSlots} ${maybeFw} ${declareRoots} ${declareReturn} })()`; } programResults.push(result); }); let src = txt ?? ""; programResults.forEach((result) => { src = src?.replace("$placeholder", result); }); return src.split("$:").join(""); } function transform(source, fileName, mode, isLibBuild = false, flags) { const programs = []; const seenNodes = /* @__PURE__ */ new Set(); const rawTxt = source; const hbsToProcess = []; const programResults = []; const isAsync = flags.ASYNC_COMPILE_TRANSFORMS; const plugins = [processTemplate(hbsToProcess, mode)]; if (!isLibBuild) { plugins.push("module:decorator-transforms"); } const replacedFileName = fileName.replace(".gts", ".ts").replace(".gjs", ".js"); const babelConfig = { plugins, filename: replacedFileName, presets: [["@babel/preset-typescript", { allExtensions: true, onlyRemoveTypeImports: true }]] }; if (isAsync) { return transformAsync(rawTxt, babelConfig).then((babelResult) => { return processTransformedFiles(babelResult, hbsToProcess, seenNodes, flags, fileName, programs, programResults); }); } else { const babelResult = transformSync(rawTxt, babelConfig); return processTransformedFiles(babelResult, hbsToProcess, seenNodes, flags, fileName, programs, programResults); } } function defaultFlags() { return { IS_GLIMMER_COMPAT_MODE: true, RUN_EVENT_DESTRUCTORS_FOR_SCOPED_NODES: false, TRY_CATCH_ERROR_HANDLING: true, SUPPORT_SHADOW_DOM: true, REACTIVE_MODIFIERS: true, WITH_HELPER_MANAGER: false, WITH_MODIFIER_MANAGER: false, WITH_EMBER_INTEGRATION: false, WITH_CONTEXT_API: true, ASYNC_COMPILE_TRANSFORMS: true }; } function fixExportsForHMR(code) { return code.split("export const ").join("export let "); } function shouldHotReloadFile(fileName, code) { const isProperExtension = fileName.endsWith(".gts") || fileName.endsWith(".gjs"); const isNotTest = !fileName.includes("-test"); const hasTemplateTag = code.includes("<template>"); return isProperExtension && isNotTest && hasTemplateTag; } const HMR = ` if (import.meta.hot) { const existingTokensToReload: string[] = []; import.meta.hot.accept((newModule) => { if (newModule) { const moduleTokens = Object.keys(newModule); const newTokens = moduleTokens.filter( (token) => !existingTokensToReload.includes(token), ); if ( newTokens.length || moduleTokens.length !== existingTokensToReload.length ) { import.meta.hot?.invalidate(); } else { moduleTokens.forEach((token) => { const oldModule = existingTokensToReload.find((t) => t === token); if (oldModule) { window.hotReload(eval(oldModule), newModule[token]); } }); existingTokensToReload.length = 0; existingTokensToReload.push(...moduleTokens); } } }); } `; const p = new Preprocessor(); function fixContentTagOutput(code) { return code.split("static{").join("$static() {"); } const extensionsToResolve = [".mjs", ".js", ".mts", ".ts", ".jsx", ".tsx", ".json", ".gts", ".gjs"]; const templateFileRegex = /\.(gts|gjs)$/; const scriptFileRegex = /\.(ts|js)$/; function compiler(mode, options = {}) { let isLibBuild = false; let flags = defaultFlags(); return { enforce: "pre", name: "glimmer-next", config(config, mode2) { if (options.authorMode === true) { isLibBuild = config.build?.lib !== void 0; } flags = { ...flags, ...options.flags ?? {} }; let defineValues = flags; if (!isLibBuild) { defineValues["IS_DEV_MODE"] = mode2.mode === "development"; } else { defineValues = {}; } return { define: defineValues, resolve: { extensions: extensionsToResolve } }; }, transform(code, file) { if (templateFileRegex.test(file)) { const intermediate = fixContentTagOutput(p.process(code, { filename: file })); if (mode === "development") { const shouldHotReload = options.disableHMR ? false : shouldHotReloadFile(file, code); return transform(fixExportsForHMR(intermediate) + (shouldHotReload ? HMR : ""), file, mode, isLibBuild, flags); } else { return transform(intermediate, file, mode, isLibBuild, flags); } } if (!code.includes(MAIN_IMPORT)) { return; } let result = void 0; if (scriptFileRegex.test(file)) { const source = code; const result2 = transform(source, file, mode, false, flags); return result2; } return result; } }; } export { compiler, stripGXTDebug };