marko
Version:
Optimized runtime for Marko templates.
11,772 lines • 524 kB
JavaScript
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
//#region \0rolldown/runtime.js
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __exportAll = (all, no_symbols) => {
let target = {};
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
return target;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let package_json = require("../../package.json");
package_json = __toESM(package_json, 1);
let _marko_compiler = require("@marko/compiler");
let _marko_compiler_babel_utils = require("@marko/compiler/babel-utils");
let fastest_levenshtein = require("fastest-levenshtein");
let path = require("path");
path = __toESM(path, 1);
let magic_string = require("magic-string");
magic_string = __toESM(magic_string, 1);
let _marko_compiler_internal_babel = require("@marko/compiler/internal/babel");
let _marko_compiler_modules = require("@marko/compiler/modules");
_marko_compiler_modules = __toESM(_marko_compiler_modules, 1);
//#region src/translator/util/runtime-info.ts
var runtime_info_default = {
name: package_json.default.name,
taglibId: "marko-core"
};
//#endregion
//#region src/translator/util/get-tag-name.ts
function getTagName(tag) {
switch (tag.node.name.type) {
case "StringLiteral": return tag.node.name.value;
case "TemplateLiteral": if (tag.node.name.quasis.length === 1) return tag.node.name.quasis[0].value.cooked;
}
}
function getTagNameHint(node) {
return _marko_compiler.types.isIdentifier(node.name) ? node.name.name : _marko_compiler.types.isStringLiteral(node.name) ? node.name.value : "tag";
}
//#endregion
//#region src/translator/util/assert.ts
const docsAnchors = {
if: "if--else",
"else-if": "if--else",
else: "if--else",
effect: "script",
attrs: ""
};
const languageDocsURL = "https://markojs.com/docs/reference/language";
const valueAttrLink = `[\`value=\` attribute](${languageDocsURL}#shorthand-value)`;
function assertNoSpreadAttrs(tag) {
const { attributes } = tag.node;
for (let i = 0; i < attributes.length; i++) if (attributes[i].type === "MarkoSpreadAttribute") throw tag.get("attributes")[i].buildCodeFrameError(`The ${coreTagLink(tag)} does not support [\`...spread\` attributes](${languageDocsURL}#spread-attributes).`);
}
function assertOnlyValueAttr(tag, required, change, hint) {
let valueAttr;
let changeAttr;
for (const attr of tag.node.attributes) if (!valueAttr && isValueAttr(attr)) valueAttr = attr;
else if (change && !changeAttr && isValueChangeAttr(attr)) changeAttr = attr;
else throw buildUnsupportedAttrsError(tag, change, hint);
if (required && !valueAttr) throw tag.get("name").buildCodeFrameError(`The ${coreTagLink(tag)} requires a ${valueAttrLink}.`);
return valueAttr;
}
function assertHasVar(tag, hint) {
if (!tag.node.var) throw tag.get("name").buildCodeFrameError(withHint(`The ${coreTagLink(tag)} requires a [tag variable](${languageDocsURL}#tag-variables).`, typeof hint === "function" ? hint(tag) : hint));
}
function assertIdentifierVar(tag) {
const tagVar = tag.node.var;
if (tagVar && tagVar.type !== "Identifier") throw tag.get("var").buildCodeFrameError(`The ${coreTagLink(tag)} variable cannot be destructured.`);
}
function assertNoTagVarMutation(tag) {
const tagVar = tag.node.var;
if (tagVar?.type === "Identifier") {
const constantViolations = tag.scope.getBinding(tagVar.name)?.constantViolations;
if (constantViolations?.length) {
for (const assignment of constantViolations) if (assignment.type !== "MarkoTag") throw assignment.buildCodeFrameError(`${tagVar.name} is readonly and cannot be mutated.`);
}
}
}
function assertHasBody(tag) {
if (!tag.node.body.body.length) throw tag.get("name").buildCodeFrameError(`The ${coreTagLink(tag)} requires [body content](${languageDocsURL}#tag-content).`);
}
function assertNoBodyContent(tag) {
if (tag.node.body.body.length) throw tag.get("name").buildCodeFrameError(`The ${coreTagLink(tag)} does not support body content.`);
}
function buildAttrsError(tag, attrs, msg) {
return buildRangeError(tag, attrs[0].loc?.start, attrs[attrs.length - 1].loc?.end, msg);
}
function buildAttrNameError(tag, attr, msg) {
const start = attr.loc?.start;
return buildRangeError(tag, start, start && {
line: start.line,
column: start.column + attr.name.length
}, msg);
}
function buildUnsupportedAttrsError(tag, change, hint) {
const { attributes } = tag.node;
const valueAttr = attributes.find(isValueAttr);
const changeAttr = change ? attributes.find(isValueChangeAttr) : void 0;
const unsupported = attributes.filter((attr) => attr !== valueAttr && attr !== changeAttr);
const [attr] = unsupported;
return buildAttrsError(tag, unsupported, withHint(`The ${coreTagLink(tag)} only supports the ${valueAttrLink}${change ? " and its change handler" : ""}.`, attr.type === "MarkoAttribute" ? hint?.(attr) : void 0));
}
function buildRangeError(tag, start, end, msg) {
return start && end ? tag.hub.buildError({ loc: {
start,
end
} }, msg, Error) : tag.get("name").buildCodeFrameError(msg);
}
function coreTagLink(tag) {
const tagName = getTagName(tag);
const anchor = docsAnchors[tagName] ?? tagName;
return `[\`<${tagName}>\` tag](https://markojs.com/docs/reference/core-tag${anchor && "#" + anchor})`;
}
function withHint(msg, hint) {
return hint ? `${msg} ${hint}` : msg;
}
function isValueAttr(attr) {
return attr.type === "MarkoAttribute" && attr.name === "value";
}
function isValueChangeAttr(attr) {
return attr.type === "MarkoAttribute" && attr.name === "valueChange";
}
//#endregion
//#region src/translator/core/attrs.ts
var attrs_default = {
migrate: (tag) => {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributes)(tag);
assertNoBodyContent(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
(0, _marko_compiler_babel_utils.diagnosticDeprecate)(tag, {
label: "The `attrs` tag is deprecated, prefer destructuring `input` via the `const` tag.",
fix() {
const tagVar = tag.node.var;
if (tagVar && !(tagVar.type === "Identifier" && tagVar.name === "input")) {
const constTag = _marko_compiler.types.markoTag(_marko_compiler.types.stringLiteral("const"), [_marko_compiler.types.markoAttribute("value", _marko_compiler.types.identifier("input"))], _marko_compiler.types.markoTagBody([]));
constTag.var = tagVar;
tag.replaceWith(constTag);
} else tag.remove();
}
});
},
attributes: {},
autocomplete: [{
displayText: "attrs/{ ... }",
description: "Use to receive the attributes passed into this template.",
snippet: "attrs/{ $1 }$2"
}]
};
//#endregion
//#region src/common/constants/accessor-prefix.debug.ts
var accessor_prefix_debug_exports = /* @__PURE__ */ __exportAll({
BranchScopes: () => BranchScopes$3,
ClosureScopes: () => ClosureScopes$1,
ClosureSignalIndex: () => ClosureSignalIndex$1,
ConditionalRenderer: () => ConditionalRenderer$1,
ControlledHandler: () => ControlledHandler$1,
ControlledObserver: () => ControlledObserver$1,
ControlledType: () => ControlledType$1,
ControlledValue: () => ControlledValue$1,
DynamicHTMLLastChild: () => DynamicHTMLLastChild$1,
DynamicHTMLValue: () => DynamicHTMLValue$1,
EventAttributes: () => EventAttributes$1,
IdFallback: () => IdFallback$1,
KeyedScopes: () => KeyedScopes$1,
Lifecycle: () => Lifecycle$1,
Promise: () => Promise$2,
TagVariableChange: () => TagVariableChange$3,
TryBranch: () => TryBranch$3
});
const BranchScopes$3 = "BranchScopes:";
const ClosureScopes$1 = "ClosureScopes:";
const ClosureSignalIndex$1 = "ClosureSignalIndex:";
const ConditionalRenderer$1 = "ConditionalRenderer:";
const ControlledObserver$1 = "ControlledObserver:";
const ControlledHandler$1 = "ControlledHandler:";
const ControlledType$1 = "ControlledType:";
const ControlledValue$1 = "ControlledValue:";
const DynamicHTMLLastChild$1 = "DynamicHTMLLastChild:";
const DynamicHTMLValue$1 = "DynamicHTMLValue:";
const EventAttributes$1 = "EventAttributes:";
const IdFallback$1 = "IdFallback:";
const KeyedScopes$1 = "KeyedScopes:";
const Lifecycle$1 = "Lifecycle:";
const Promise$2 = "Promise:";
const TagVariableChange$3 = "TagVariableChange:";
const TryBranch$3 = "TryBranch:";
//#endregion
//#region src/common/constants/accessor-prop.debug.ts
var accessor_prop_debug_exports = /* @__PURE__ */ __exportAll({
AbortControllers: () => AbortControllers$1,
AbortScopes: () => AbortScopes$1,
AwaitCounter: () => AwaitCounter$1,
BranchAccessor: () => BranchAccessor$1,
BranchRenders: () => BranchRenders$1,
BranchScopes: () => BranchScopes$2,
CatchContent: () => CatchContent$1,
ClosestBranch: () => ClosestBranch$1,
ClosestBranchId: () => ClosestBranchId$1,
DetachedAwait: () => DetachedAwait$1,
EndNode: () => EndNode$1,
Gen: () => Gen$1,
Global: () => Global$1,
Id: () => "#Id",
Load: () => Load$1,
LoopIndex: () => LoopIndex$1,
LoopKey: () => LoopKey$1,
Owner: () => "_",
ParentBranch: () => ParentBranch$1,
PendingEffectScopes: () => PendingEffectScopes$1,
PendingEffects: () => PendingEffects$1,
PendingRenders: () => PendingRenders$1,
PendingScopes: () => PendingScopes$1,
PlaceholderBranch: () => PlaceholderBranch$1,
PlaceholderContent: () => PlaceholderContent$1,
Renderer: () => Renderer$1,
ReturnValue: () => ReturnValue$1,
StartNode: () => StartNode$1,
Subscriptions: () => Subscriptions$1,
TagVariable: () => TagVariable$1,
TagVariableChange: () => TagVariableChange$2,
TryBranch: () => TryBranch$2
});
const Global$1 = "$global";
const AbortControllers$1 = "#AbortControllers";
const AbortScopes$1 = "#AbortScopes";
const AwaitCounter$1 = "#AwaitCounter";
const BranchAccessor$1 = "#BranchAccessor";
const BranchRenders$1 = "#BranchRenders";
const BranchScopes$2 = "#BranchScopes";
const CatchContent$1 = "#CatchContent";
const ClosestBranch$1 = "#ClosestBranch";
const ClosestBranchId$1 = "#ClosestBranchId";
const Gen$1 = "#Gen";
const DetachedAwait$1 = "#DetachedAwait";
const EndNode$1 = "#EndNode";
const Load$1 = "#Load";
const LoopKey$1 = "#LoopKey";
const LoopIndex$1 = "#LoopIndex";
const ParentBranch$1 = "#ParentBranch";
const PendingEffects$1 = "#PendingEffects";
const PendingEffectScopes$1 = "#PendingEffectScopes";
const PendingRenders$1 = "#PendingRenders";
const PendingScopes$1 = "#PendingScopes";
const PlaceholderBranch$1 = "#PlaceholderBranch";
const PlaceholderContent$1 = "#PlaceholderContent";
const Renderer$1 = "#Renderer";
const ReturnValue$1 = "#ReturnValue";
const StartNode$1 = "#StartNode";
const Subscriptions$1 = "#Subscriptions";
const TagVariable$1 = "#TagVariable";
const TagVariableChange$2 = "#TagVariableChange";
const TryBranch$2 = "#TryBranch";
//#endregion
//#region src/html/serializer.ts
const kTouchedIterator = /* @__PURE__ */ Symbol.for("marko.touchedIterator");
const { hasOwnProperty } = {};
Array.prototype;
const Generator = (/* @__PURE__ */ (function* () {})()).constructor;
const AsyncGenerator = (/* @__PURE__ */ (async function* () {})()).constructor;
patchIteratorNext(Generator.prototype);
patchIteratorNext(AsyncGenerator.prototype);
function toAccess(accessor) {
const start = accessor[0];
return start === "[" ? accessor : start === "\"" || start >= "0" && start <= "9" ? "[" + accessor + "]" : "." + accessor;
}
function patchIteratorNext(proto) {
if (proto.next[kTouchedIterator]) return;
const { next } = proto;
proto.next = function(value) {
this[kTouchedIterator] = 1;
return next.call(this, value);
};
proto.next[kTouchedIterator] = true;
}
//#endregion
//#region src/translator/util/optional.ts
var Sorted = class {
compare;
constructor(compare) {
this.compare = compare;
}
add(data, item) {
return data !== void 0 ? Array.isArray(data) ? addSorted(this.compare, data, item) : joinRepeatable(this.compare, data, item) : item;
}
union(a, b) {
if (a !== void 0) {
if (Array.isArray(a)) {
if (b !== void 0) {
if (Array.isArray(b)) return a === b ? a : unionSorted(this.compare, a, b);
else return addSorted(this.compare, a, b);
}
return a;
}
if (b !== void 0) {
if (Array.isArray(b)) return addSorted(this.compare, b, a);
return joinRepeatable(this.compare, b, a);
}
return a;
}
return b;
}
filter(data, cb) {
if (!Array.isArray(data)) return data !== void 0 && cb(data) ? data : void 0;
for (let i = 0; i < data.length; i++) if (!cb(data[i])) {
const kept = [];
for (let j = 0; j < i; j++) kept.push(data[j]);
while (++i < data.length) if (cb(data[i])) kept.push(data[i]);
return kept.length > 1 ? kept : kept[0];
}
return data;
}
leadingRun(data, key, compareKeys, bound) {
return Array.isArray(data) ? slice(data, 0, partitionPoint(data, key, compareKeys, bound)) : data !== void 0 && compareKeys(key(data), bound) < 0 ? data : void 0;
}
range(data, key, compareKeys, bound) {
if (!Array.isArray(data)) return data !== void 0 && compareKeys(key(data), bound) === 0 ? data : void 0;
const start = partitionPoint(data, key, compareKeys, bound);
return slice(data, start, gallop(data, start, key, compareKeys, bound));
}
forEachRun(data, key, compareKeys, fn) {
if (!Array.isArray(data)) {
if (data !== void 0) fn(key(data), data);
return;
}
for (let start = 0, end; start < data.length; start = end) {
const runKey = key(data[start]);
end = gallop(data, start + 1, key, compareKeys, runKey);
fn(runKey, slice(data, start, end));
}
}
reduceRuns(data, key, compareKeys, fn, initial) {
if (!Array.isArray(data)) return data !== void 0 ? fn(initial, key(data), data) : initial;
let acc = initial;
for (let start = 0, end; start < data.length; start = end) {
const runKey = key(data[start]);
end = gallop(data, start + 1, key, compareKeys, runKey);
acc = fn(acc, runKey, slice(data, start, end));
}
return acc;
}
find(data, item) {
if (data !== void 0) {
if (Array.isArray(data)) return findSorted(this.compare, data, item);
else if (this.compare(data, item) === 0) return data;
}
}
has(data, item) {
return this.findIndex(data, item) !== -1;
}
findIndex(data, item) {
if (data !== void 0) {
if (Array.isArray(data)) return findIndexSorted(this.compare, data, item);
else if (this.compare(data, item) === 0) return 0;
}
return -1;
}
intersects(a, b) {
if (a === void 0 || b === void 0) return false;
if (!Array.isArray(a)) return this.findIndex(b, a) !== -1;
if (!Array.isArray(b)) return this.findIndex(a, b) !== -1;
const long = a.length < b.length ? b : a;
const short = long === a ? b : a;
if (isMuchLonger(long, short)) for (let i = 0, j = 0; i < short.length && j < long.length; i++) {
const found = findIndexSortedFrom(this.compare, long, j, short[i], short.length - i);
if (found >= 0) return true;
j = ~found;
}
else for (let i = 0, j = 0; i < a.length && j < b.length;) {
const delta = this.compare(a[i], b[j]);
if (!delta) return true;
if (delta < 0) i++;
else j++;
}
return false;
}
difference(a, b) {
if (a === void 0 || b === void 0) return a;
if (!Array.isArray(a)) return this.findIndex(b, a) === -1 ? a : void 0;
if (!Array.isArray(b)) {
const index = findIndexSorted(this.compare, a, b);
if (index === -1) return a;
if (a.length === 2) return a[1 - index];
const len = a.length - 1;
const result = new Array(len);
for (let i = 0; i < index; i++) result[i] = a[i];
for (let i = index; i < len; i++) result[i] = a[i + 1];
return result;
}
return differenceSorted(this.compare, a, b);
}
isSuperset(superset, subset) {
if (subset === void 0) return true;
if (!Array.isArray(subset)) return this.findIndex(superset, subset) !== -1;
if (!Array.isArray(superset) || subset.length > superset.length) return false;
if (!isMuchLonger(superset, subset)) {
let i = 0;
for (let j = 0; i < subset.length && j < superset.length; j++) {
const delta = this.compare(superset[j], subset[i]);
if (delta > 0) return false;
if (delta === 0) i++;
}
return i === subset.length;
}
for (let i = 0, j = 0; i < subset.length; i++) {
const found = findIndexSortedFrom(this.compare, superset, j, subset[i], subset.length - i);
if (found < 0) return false;
j = found + 1;
}
return true;
}
};
function push(data, item) {
if (data !== void 0) {
if (Array.isArray(data)) {
data.push(item);
return data;
}
return [data, item];
}
return item;
}
function concat(a, b) {
if (a !== void 0) {
if (b !== void 0) {
if (Array.isArray(a)) return a.concat(b);
else if (Array.isArray(b)) return [a, ...b];
else return [a, b];
}
return a;
}
return b;
}
function size(data) {
return data !== void 0 ? Array.isArray(data) ? data.length : 1 : 0;
}
function filter(data, cb) {
if (data !== void 0) {
if (Array.isArray(data)) {
const len = data.length;
let result;
let i = 0;
while (i < len) {
let item = data[i++];
if (cb(item)) {
result = item;
while (i < len) {
item = data[i++];
if (cb(item)) {
result = [result, item];
while (i < len) {
item = data[i++];
if (cb(item)) result.push(item);
}
return result;
}
}
return result;
}
}
return result;
}
if (cb(data)) return data;
}
}
function forEach(data, cb) {
if (data !== void 0) {
if (Array.isArray(data)) {
let i = 0;
for (const item of data) cb(item, i++);
} else cb(data, 0);
}
}
function fromIter(data) {
let one;
let many;
for (const item of data) if (many) many.push(item);
else if (one) many = [one, item];
else one = item;
return many || one;
}
function find(data, cb) {
if (data !== void 0) {
if (Array.isArray(data)) return data.find(cb);
if (cb(data, 0)) return data;
}
}
function some(data, cb) {
return data !== void 0 ? Array.isArray(data) ? data.some(cb) : !!cb(data, 0) : false;
}
function every(data, cb) {
return data !== void 0 ? Array.isArray(data) ? data.every(cb) : !!cb(data, 0) : true;
}
function reduce(data, cb, initial) {
return data !== void 0 ? Array.isArray(data) ? data.reduce(cb, initial) : cb(initial, data, 0) : initial;
}
function reduceWhile(data, cb, initial) {
if (Array.isArray(data)) {
let acc = initial;
for (let i = 0, len = data.length; i < len; i++) {
const next = cb(acc, data[i]);
if (next === void 0) return next;
acc = next;
}
return acc;
}
return data !== void 0 ? cb(initial, data) : initial;
}
function toArray(data, cb) {
return data !== void 0 ? Array.isArray(data) ? data.map(cb) : [cb(data, 0)] : [];
}
function toSet(data) {
return data !== void 0 ? Array.isArray(data) ? new Set(data) : (/* @__PURE__ */ new Set()).add(data) : /* @__PURE__ */ new Set();
}
function mapToString(data, sep, cb) {
if (data !== void 0) {
if (Array.isArray(data)) {
let str = "";
let curSep = "";
for (let i = 0; i < data.length; i++) {
str += curSep + cb(data[i], i);
curSep = sep;
}
return str;
}
return cb(data, 0);
}
return "";
}
function findSorted(compare, data, item) {
let max = data.length;
let pos = 0;
while (pos < max) {
const mid = pos + max >>> 1;
const cur = data[mid];
const compareResult = compare(cur, item);
if (compareResult === 0) return cur;
if (compareResult > 0) max = mid;
else pos = mid + 1;
}
}
function findIndexSorted(compare, data, item) {
let max = data.length;
let pos = 0;
while (pos < max) {
const mid = pos + max >>> 1;
const compareResult = compare(data[mid], item);
if (compareResult === 0) return mid;
if (compareResult > 0) max = mid;
else pos = mid + 1;
}
return -1;
}
function addSorted(compare, data, item) {
const len = data.length;
let max = len;
let pos = 0;
while (pos < max) {
const mid = pos + max >>> 1;
const compareResult = compare(data[mid], item);
if (compareResult === 0) return data;
if (compareResult > 0) max = mid;
else pos = mid + 1;
}
const result = new Array(len + 1);
for (let i = 0; i < pos; i++) result[i] = data[i];
let cur = item;
while (pos < len) {
const next = cur;
cur = data[pos];
result[pos++] = next;
}
result[len] = cur;
return result;
}
function partitionPoint(data, key, compareKeys, bound) {
let max = data.length;
let pos = 0;
while (pos < max) {
const mid = pos + max >>> 1;
if (compareKeys(key(data[mid]), bound) < 0) pos = mid + 1;
else max = mid;
}
return pos;
}
function gallop(data, start, key, compareKeys, bound) {
let pos = start;
let max = start;
for (let step = 1; max < data.length && compareKeys(key(data[max]), bound) <= 0; step *= 2) {
pos = max + 1;
max += step;
}
if (max > data.length) max = data.length;
while (pos < max) {
const mid = pos + max >>> 1;
if (compareKeys(key(data[mid]), bound) <= 0) pos = mid + 1;
else max = mid;
}
return pos;
}
function findIndexSortedFrom(compare, data, start, item, left) {
let pos = start;
let max = start;
if (left * left < data.length - start) max = data.length;
else {
for (let step = 1; max < data.length; step *= 2) {
const compareResult = compare(data[max], item);
if (compareResult === 0) return max;
if (compareResult > 0) break;
pos = max + 1;
max += step;
}
if (max > data.length) max = data.length;
}
while (pos < max) {
const mid = pos + max >>> 1;
const compareResult = compare(data[mid], item);
if (compareResult === 0) return mid;
if (compareResult > 0) max = mid;
else pos = mid + 1;
}
return ~pos;
}
function slice(data, start, end) {
return end - start > 1 ? end - start === data.length ? data : data.slice(start, end) : end > start ? data[start] : void 0;
}
function differenceSorted(compare, a, b) {
if (isMuchLonger(a, b)) {
let kept;
let from = 0;
for (let j = 0, i = 0; j < b.length && i < a.length; j++) {
const found = findIndexSortedFrom(compare, a, i, b[j], b.length - j);
if (found >= 0) {
if (kept) while (from < found) kept.push(a[from++]);
else kept = a.slice(0, found);
from = i = found + 1;
} else i = ~found;
}
if (!kept) return a;
while (from < a.length) kept.push(a[from++]);
return kept;
}
let result;
if (isMuchLonger(b, a)) for (let i = 0, j = 0; i < a.length; i++) {
const found = findIndexSortedFrom(compare, b, j, a[i], a.length - i);
if (found < 0) result = push(result, a[i]);
j = found < 0 ? ~found : found + 1;
}
else for (let i = 0, j = 0; i < a.length; i++) {
let delta = -1;
while (j < b.length && (delta = compare(b[j], a[i])) < 0) j++;
if (delta) result = push(result, a[i]);
}
return size(result) === a.length ? a : result;
}
function unionSorted(compare, a, b) {
const long = a.length < b.length ? b : a;
const short = long === a ? b : a;
if (!isMuchLonger(long, short)) return unionSortedRepeatable(compare, a, b);
const result = [];
let from = 0;
for (let i = 0; i < short.length; i++) {
const item = short[i];
const found = findIndexSortedFrom(compare, long, from, item, short.length - i);
const end = found < 0 ? ~found : found;
while (from < end) result.push(long[from++]);
if (found >= 0) {
result.push(long === a ? long[from] : item);
from++;
} else result.push(item);
}
while (from < long.length) result.push(long[from++]);
return result;
}
function unionSortedRepeatable(compare, a, b) {
const aLen = a.length;
const bLen = b.length;
const result = [];
let aIndex = 0;
let bIndex = 0;
let same = true;
while (aIndex < aLen && bIndex < bLen) {
const aValue = a[aIndex];
const bValue = b[bIndex];
const delta = compare(aValue, bValue);
if (delta === 0) {
aIndex++;
bIndex++;
result.push(aValue);
} else if (delta < 0) {
same = false;
aIndex++;
result.push(aValue);
} else {
same = false;
bIndex++;
result.push(bValue);
}
}
if (same && aLen === bLen) return a;
while (aIndex < aLen) result.push(a[aIndex++]);
while (bIndex < bLen) result.push(b[bIndex++]);
return result;
}
function isMuchLonger(long, short) {
return long.length >= 4 * short.length;
}
function joinRepeatable(compare, a, b) {
const compareResult = compare(a, b);
return compareResult === 0 ? a : compareResult < 0 ? [a, b] : [b, a];
}
function first(data) {
return Array.isArray(data) ? data[0] : data;
}
function last(data) {
return Array.isArray(data) ? data[data.length - 1] : data;
}
function rest(data) {
return Array.isArray(data) ? data.length === 2 ? data[1] : data.slice(1) : void 0;
}
//#endregion
//#region src/translator/util/for-each-identifier.ts
function forEachIdentifier(node, cb) {
switch (node.type) {
case "ObjectPattern":
for (const prop of node.properties) switch (prop.type) {
case "ObjectProperty":
if (prop.value.type === "AssignmentPattern") forEachIdentifier(prop.value.left, cb);
else forEachIdentifier(prop.value, cb);
break;
case "RestElement": forEachIdentifier(prop.argument, cb);
}
break;
case "ArrayPattern":
for (const el of node.elements) if (el != null) switch (el.type) {
case "RestElement":
forEachIdentifier(el.argument, cb);
break;
case "AssignmentPattern":
forEachIdentifier(el.left, cb);
break;
default: forEachIdentifier(el, cb);
}
break;
case "Identifier": cb(node);
}
}
function forEachIdentifierPath(nodePath, cb) {
if (nodePath.isIdentifier()) cb(nodePath);
else if (nodePath.isObjectPattern()) {
for (const prop of nodePath.get("properties")) if (prop.isObjectProperty()) {
const value = prop.get("value");
if (value.isAssignmentPattern()) forEachIdentifierPath(value.get("left"), cb);
else forEachIdentifierPath(value, cb);
} else if (prop.isRestElement()) forEachIdentifierPath(prop.get("argument"), cb);
} else if (nodePath.isArrayPattern()) {
for (const el of nodePath.get("elements")) if (el) {
if (el.isRestElement()) forEachIdentifierPath(el.get("argument"), cb);
else if (el.isAssignmentPattern()) forEachIdentifierPath(el.get("left"), cb);
else forEachIdentifierPath(el, cb);
}
}
}
//#endregion
//#region src/translator/util/constants/compile-stage.ts
const analyze$1 = "analyze";
const translate$1 = "translate";
//#endregion
//#region src/translator/util/get-compile-stage.ts
function isTranslate() {
return getCompileStage() === translate$1;
}
function isAnalyzing(file) {
return getCompileStage(file) === analyze$1;
}
function getCompileStage(file = (0, _marko_compiler_babel_utils.getFile)()) {
return file.___compileStage;
}
//#endregion
//#region src/translator/util/state.ts
function createProgramState(init) {
const map = /* @__PURE__ */ new WeakMap();
return [() => {
let state = map.get((0, _marko_compiler_babel_utils.getProgram)());
if (!state) map.set((0, _marko_compiler_babel_utils.getProgram)(), state = init());
return state;
}, (value) => {
map.set((0, _marko_compiler_babel_utils.getProgram)(), value);
}];
}
function createSectionState(key, init) {
return [(section) => {
const arrayOfSectionData = (0, _marko_compiler_babel_utils.getProgram)().state[key] ??= {};
return arrayOfSectionData[section.id] ??= init && init(section);
}, (section, value) => {
const arrayOfSectionData = (0, _marko_compiler_babel_utils.getProgram)().state[key] ??= {};
arrayOfSectionData[section.id] = value;
}];
}
//#endregion
//#region src/translator/util/traverse.ts
const skip = Symbol("skip");
function traverseReplace(container, key, exit, state) {
const node = container[key];
if (node) {
if (Array.isArray(node)) for (let i = node.length; i--;) traverseReplace(node, i, exit, state);
else {
const keys = _marko_compiler.types.VISITOR_KEYS[node.type];
for (let i = keys.length; i--;) traverseReplace(node, keys[i], exit, state);
const replacement = exit(node, state);
if (replacement) container[key] = replacement;
}
}
}
function traverseContains(node, check) {
return !!traverseFind(node, check);
}
function traverseFind(node, check) {
if (node) {
if (Array.isArray(node)) for (const item of node) {
const found = traverseFind(item, check);
if (found) return found;
}
else {
switch (check(node)) {
case true: return node;
case skip: return;
}
for (const key of _marko_compiler.types.VISITOR_KEYS[node.type]) {
const found = traverseFind(node[key], check);
if (found) return found;
}
}
}
}
function traverseFindAwait(node) {
return traverseFind(node, (child) => {
switch (child.type) {
case "ForOfStatement": return child.await;
case "FunctionDeclaration":
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassMethod":
case "ObjectMethod":
case "ClassPrivateMethod": return skip;
case "AwaitExpression": return true;
}
});
}
function traverse(visit, node, parent, grandParent) {
if (node) {
if (Array.isArray(node)) for (const item of node) traverse(visit, item, parent, grandParent);
else if (visit(node, parent, grandParent) !== skip) for (const key of _marko_compiler.types.VISITOR_KEYS[node.type]) traverse(visit, node[key], node, parent);
}
}
//#endregion
//#region src/translator/util/generate-uid.ts
const kUidCounts = Symbol("uid counts");
const countsForFile = /* @__PURE__ */ new WeakMap();
function generateUid(name = "") {
const file = (0, _marko_compiler_babel_utils.getFile)();
let counts = countsForFile.get(file);
if (!counts) {
counts = (file.path.node.extra ??= {})[kUidCounts] ??= getInitialCounts(file);
if (isTranslate()) counts = new Map(counts);
countsForFile.set(file, counts);
}
name = name.replace(/^[^a-z$_]|[^a-z$_0-9]/gi, "") || "temp";
name = /^\$?(.*?)\d*$/.exec(name)?.[1] || name;
const i = (counts.get(name) || 0) + 1;
const uniqueName = `$${i > 1 ? name + i : name}`;
counts.set(name, i);
return uniqueName;
}
function generateUidIdentifier(name) {
return _marko_compiler.types.identifier(generateUid(name));
}
function declareConstBefore(tag, name, expr) {
const id = generateUidIdentifier(name);
tag.insertBefore(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(id, expr)]));
return id;
}
const [getSharedUIDs] = createProgramState(() => /* @__PURE__ */ new Map());
function ensureSharedUid(name, section) {
const sharedUIDs = getSharedUIDs();
const nameKey = section ? `${section.id}:${name}` : name;
let uniqueName = sharedUIDs.get(nameKey);
if (!uniqueName) {
uniqueName = generateUid(name);
sharedUIDs.set(nameKey, uniqueName);
}
return uniqueName;
}
function hasSharedUid(name) {
return getSharedUIDs().has(name);
}
function getInitialCounts(file) {
const counts = /* @__PURE__ */ new Map();
const program = file.path;
const countName = (name) => {
const match = /^\$(.*?)([1-9]\d*)?$/.exec(name);
if (match) {
const name = match[1];
const count = match[2] ? +match[2] + 1 : 1;
counts.set(name, Math.max(counts.get(name) || 0, count));
}
};
for (const name in program.scope.globals) countName(name);
traverse((node, parent, grandParent) => {
if (node.type === "Identifier" && _marko_compiler.types.isBinding(node, parent, grandParent)) countName(node.name);
}, program.node);
return counts;
}
//#endregion
//#region src/translator/util/get-root.ts
function getMarkoRoot(path) {
let curPath = path;
do
curPath = curPath.parentPath;
while (curPath && !isMarkoRoot(curPath));
return curPath;
}
function getExprRoot(path) {
let curPath = path;
while (!isMarkoRoot(curPath.parentPath)) curPath = curPath.parentPath;
return curPath;
}
function getFnRoot(path) {
let fnPath;
for (let curPath = path; curPath && !isMarkoRoot(curPath); curPath = curPath.parentPath) if (isFunction(curPath)) fnPath = curPath;
else switch (curPath.type) {
case "OptionalCallExpression":
case "CallExpression":
case "NewExpression": fnPath = void 0;
}
return fnPath;
}
function getFnParent(path) {
for (let curPath = path; curPath && !isMarkoRoot(curPath); curPath = curPath.parentPath) if (isFunction(curPath)) return curPath;
}
function getDeclarationRoot(path) {
let declPath;
for (let curPath = path; curPath && !isMarkoRoot(curPath); curPath = curPath.parentPath) if (isFunctionOrVariableDeclaration(curPath)) declPath = curPath;
return declPath;
}
function isMarkoRoot(path) {
switch (path.type) {
case "MarkoTag":
case "MarkoTagBody":
case "MarkoAttribute":
case "MarkoSpreadAttribute":
case "MarkoPlaceholder":
case "MarkoScriptlet":
case "ExportNamedDeclaration":
case "ExportDefaultDeclaration": return true;
default: return false;
}
}
function isFunction(path) {
switch (path.type) {
case "FunctionDeclaration": return !path.node.declare;
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ObjectMethod": return true;
default: return false;
}
}
function isFunctionOrVariableDeclaration(path) {
switch (path.type) {
case "FunctionDeclaration": return !path.node.declare;
case "VariableDeclaration": return true;
default: return false;
}
}
//#endregion
//#region src/translator/util/is-event-or-change-handler.ts
function isEventOrChangeHandler(prop) {
return /^on[-A-Z]|[a-zA-Z_$][a-zA-Z0-9_$]*Change$/.test(prop);
}
//#endregion
//#region src/translator/util/is-invoked-function.ts
function isInvokedFunction(expr) {
let curPath = expr;
while (curPath) {
const { parent, node } = curPath;
switch (parent.type) {
case "OptionalCallExpression":
case "CallExpression": return parent.callee === node;
case "TSNonNullExpression":
curPath = curPath.parentPath;
break;
default: return false;
}
}
return false;
}
//#endregion
//#region src/translator/util/is-static.ts
function isStatic(path) {
return path.isImportDeclaration() || path.isExportDeclaration() || path.isMarkoScriptlet({ static: true });
}
//#endregion
//#region src/translator/util/constants/structure-kind.ts
const Node = "node";
const Text = "text";
const Child = "child";
const ModuleRead = "moduleRead";
const SectionRef = "sectionRef";
const ExportRef = "exportRef";
//#endregion
//#region src/translator/util/is-core-tag.ts
const { taglibId } = runtime_info_default;
const htmlTaglibId = "marko-html";
function isCoreTag(tag) {
if (tag.isMarkoTag()) {
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
if (tagDef) switch (tagDef.taglibId) {
case taglibId: return true;
case htmlTaglibId: switch (tagDef.name) {
case "script":
case "style": return true;
}
}
}
return false;
}
function isCoreTagName(tag, name) {
return isCoreTag(tag) && getTagName(tag) === name;
}
function isConditionTag(tag) {
if (isCoreTag(tag)) switch (getTagName(tag)) {
case "if":
case "else-if":
case "else": return true;
}
return false;
}
//#endregion
//#region src/translator/util/slots.ts
const slotUtil = new Sorted(compareSlots);
function ensureSlot(binding, kind = 0, section, group) {
const owner = getCanonicalBinding(binding);
return findSlot(owner, kind, section, group) || addSlot(kind, section || owner.section, owner, group);
}
function findSlot(binding, kind = 0, section, group) {
const owner = getCanonicalBinding(binding);
return findIn((section || owner.section).slots, owner.uid, kind, group);
}
function ensureSectionSlot(owner, kind, section = owner) {
return findSectionSlot(owner, kind, section) || addSlot(kind, section, owner, void 0);
}
function findSectionSlot(owner, kind, section = owner) {
return findIn(section.slots, getOwnerOrder(owner), kind, void 0);
}
function addSlot(kind, section, owner, group) {
const slot = {
kind,
section,
owner,
group,
reason: void 0,
reasonExprs: void 0
};
section.slots = slotUtil.add(section.slots, slot);
return slot;
}
function findIn(slots, order, kind, group) {
if (slots === void 0) return;
if (!Array.isArray(slots)) return compareSlotTo(slots, order, kind, group) ? void 0 : slots;
let pos = 0;
let max = slots.length;
while (pos < max) {
const mid = pos + max >>> 1;
const slot = slots[mid];
const result = compareSlotTo(slot, order, kind, group);
if (result === 0) return slot;
if (result > 0) max = mid;
else pos = mid + 1;
}
}
function compareSlots(a, b) {
return compareSlotTo(a, getOwnerOrder(b.owner), b.kind, b.group);
}
function compareSlotTo(slot, order, kind, group) {
return getOwnerOrder(slot.owner) - order || slot.kind - kind || (group ? compareReferences(slot.group, group) : 0);
}
function getOwnerOrder(owner) {
return "uid" in owner ? owner.uid : -1 - owner.id;
}
//#endregion
//#region src/translator/util/cyclic-memo.ts
function createCyclicMemo(compute, cycleAnswer) {
const cache = /* @__PURE__ */ new WeakMap();
const computing = /* @__PURE__ */ new Map();
let provisionalAt = Infinity;
return (key) => {
if (cache.has(key)) return cache.get(key);
const at = computing.get(key);
if (at !== void 0) {
if (at < provisionalAt) provisionalAt = at;
return cycleAnswer;
}
const frame = computing.size;
computing.set(key, frame);
const outerProvisionalAt = provisionalAt;
provisionalAt = Infinity;
try {
const result = compute(key);
if (provisionalAt >= frame) cache.set(key, result);
return result;
} finally {
computing.delete(key);
if (provisionalAt >= frame || outerProvisionalAt < provisionalAt) provisionalAt = outerProvisionalAt;
}
};
}
function createCyclicPathMemo(compute, cycleAnswer) {
const keys = /* @__PURE__ */ new WeakMap();
const memo = createCyclicMemo(([key, path]) => compute(key, path), cycleAnswer);
return (key, path) => {
let node = keys.get(key);
if (!node) keys.set(key, node = {});
if (path === true) return memo(node.all ??= [key, path]);
return memo(reduce(path, ensurePropKeys, node).value ??= [key, path]);
};
}
function ensurePropKeys(node, property) {
let next = node.props?.get(property);
if (!next) (node.props ??= /* @__PURE__ */ new Map()).set(property, next = {});
return next;
}
//#endregion
//#region src/translator/util/get-parent-tag.ts
function getParentTag(tag) {
const parent = tag.parent.type === "MarkoTagBody" ? tag.parentPath.parentPath : tag.parentPath;
if (parent.type === "MarkoTag") return parent;
}
function getAttributeTagParent(tag) {
let cur = tag;
while ((0, _marko_compiler_babel_utils.isAttributeTag)(cur) || (0, _marko_compiler_babel_utils.isTransparentTag)(cur)) cur = getParentTag(cur);
return cur;
}
//#endregion
//#region src/translator/util/nested-attribute-tags.ts
const [getAttrTagIdentifiers] = createProgramState(() => /* @__PURE__ */ new WeakMap());
function getAttrTagIdentifier(meta) {
const identifiers = getAttrTagIdentifiers();
let name = identifiers.get(meta);
if (!name) identifiers.set(meta, name = generateUid(meta.name));
return _marko_compiler.types.identifier(name);
}
function getAttrTagPaths(tag) {
return tag.node.body.attributeTags ? tag.get("body").get("body") : tag.get("attributeTags");
}
function analyzeAttributeTags(tag) {
if (tag.node.extra?.attrTagLookup) return tag.node.extra.attrTagLookup;
const attrTags = getAttrTagPaths(tag);
if (!attrTags.length) return;
const tagExtra = tag.node.extra ??= {};
const lookup = tagExtra.attrTagLookup = {};
const attrTagNodesByName = {};
const sampleAttrTagsForControlFlow = /* @__PURE__ */ new Map();
let chainGroup;
for (const child of attrTags) if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const name = getTagName(child);
lookup[name] ||= createAttrTagMeta(name, [name]);
(attrTagNodesByName[name] ||= []).push(child);
analyzeAttributeTags(child);
} else {
let curGroup = isElseTag(child) ? chainGroup : void 0;
for (const [name, isRepeated] of crawlAttrTags(child, attrTagNodesByName)) {
const oldMeta = lookup[name];
if (oldMeta) {
if (!curGroup) curGroup = oldMeta.group;
else if (curGroup !== oldMeta.group) for (const name of oldMeta.group) {
lookup[name].group = curGroup;
curGroup.push(name);
}
}
let attrTagMeta = lookup[name];
if (!attrTagMeta) {
attrTagMeta = lookup[name] = createAttrTagMeta(name, curGroup ||= []);
curGroup.push(name);
}
attrTagMeta.dynamic = true;
if (isRepeated) attrTagMeta.repeated = true;
sampleAttrTagsForControlFlow.set(child, name);
}
chainGroup = curGroup;
}
}
for (const [controlFlowTag, sampleAttrName] of sampleAttrTagsForControlFlow) (controlFlowTag.node.extra ??= {}).attributeTagGroup = lookup[sampleAttrName].group;
for (const name in attrTagNodesByName) {
const attrTagMeta = lookup[name];
if (!attrTagMeta.repeated) {
const attrTagNodes = attrTagNodesByName[name];
if (attrTagNodes.length > 1) attrTagMeta.repeated = !attrTagMeta.dynamic || hasRepeatedDynamicAttrTags(attrTagNodes);
}
}
return lookup;
}
function createAttrTagMeta(name, group) {
return {
name: name.slice(1),
dynamic: false,
repeated: false,
group
};
}
function crawlAttrTags(tag, attrTagNodesByName, attrTagNames = /* @__PURE__ */ new Map(), inLoop = (0, _marko_compiler_babel_utils.isLoopTag)(tag)) {
const attrTags = getAttrTagPaths(tag);
for (const child of attrTags) if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const tagName = getTagName(child);
attrTagNames.set(tagName, inLoop || !!attrTagNames.get(tagName));
(attrTagNodesByName[tagName] ||= []).push(child);
analyzeAttributeTags(child);
} else crawlAttrTags(child, attrTagNodesByName, attrTagNames, inLoop || (0, _marko_compiler_babel_utils.isLoopTag)(child));
}
return attrTagNames;
}
function hasRepeatedDynamicAttrTags(attrTags) {
let conditionRoot;
const seenBranches = /* @__PURE__ */ new Set();
for (const attrTag of attrTags) {
const parentTag = getParentTag(attrTag);
if (seenBranches.has(parentTag) || !isConditionTag(parentTag)) return true;
const curConditionRoot = getConditionRoot(parentTag);
if (curConditionRoot && curConditionRoot !== (conditionRoot ||= curConditionRoot)) return true;
seenBranches.add(parentTag);
}
return false;
}
function isElseTag(tag) {
const tagName = getTagName(tag);
return tagName === "else" || tagName === "else-if";
}
function getConditionRoot(tag) {
if (getTagName(tag) === "if") return tag;
let prev = tag.getPrevSibling();
while (prev.node) {
if (prev.isMarkoTag() && getTagName(prev) === "if") return prev;
prev = prev.getPrevSibling();
}
}
//#endregion
//#region src/translator/util/content-derives.ts
const [getTagContentDerives] = createSectionState("tag-content-derives", () => /* @__PURE__ */ new Map());
function setTagContentDerives(tag, binding, exprs) {
if (binding) getTagContentDerives(getSection(tag)).set(tag, {
binding,
exprs
});
}
function finalizeContentDerives(section) {
for (const [tag, { binding, exprs }] of getTagContentDerives(section)) setContentDerives(tag, tag.node.extra, binding, exprs);
}
function setContentDerives(tag, tagExtra, binding, exprs, properties, skip) {
if (!skip) {
const contentSection = getSectionForBody(tag.get("body"));
if (contentSection) contentSection.derives = {
tag: tagExtra,
binding,
properties: concat(properties, "content"),
exprs
};
}
const attrTagLookup = analyzeAttributeTags(tag);
if (!attrTagLookup) return;
const attrTags = getAttrTagPaths(tag);
for (const child of attrTags) if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const attrTagMeta = attrTagLookup[getTagName(child)];
setContentDerives(child, tagExtra, binding, exprs, concat(properties, attrTagMeta.name));
} else setContentDerives(child, tagExtra, binding, exprs, properties, true);
}
}
//#endregion
//#region src/translator/util/params-tree.ts
function exposeParamsTree(binding, bodyAnalyzed) {
binding.exposed = true;
const props = {
binding,
props: void 0,
rest: void 0
};
if (!binding.reads.size) {
let restAlias;
let aliasCount = 0;
for (const alias of binding.aliases) if (!bodyAnalyzed || isPossiblyRead(alias)) {
restAlias = alias;
if (++aliasCount > 1) break;
}
if (!restAlias) {
props.props = Object.create(null);
for (const [property, alias] of binding.propertyAliases) props.props[property] = exposeParamsTree(alias, bodyAnalyzed);
} else if (aliasCount === 1) {
if (hasSupersetExcludeProperties(binding, restAlias.excludeProperties)) {
props.rest = exposeParamsTree(restAlias, bodyAnalyzed);
props.props = Object.create(null);
forEach(restAlias.excludeProperties, (property) => {
const propAlias = binding.propertyAliases.get(property);
if (propAlias) props.props[property] = exposeParamsTree(propAlias, bodyAnalyzed);
});
}
}
}
const exportNames = (0, _marko_compiler_babel_utils.getProgram)().node.extra.exportNames;
if (isTemplateParam(binding) && !exportNames.params.has(binding)) exportNames.params.set(binding, generateUid(binding.name));
if (isDirectContentBinding(binding) && !exportNames.directContent.has(binding)) exportNames.directContent.set(binding, generateUid(`${binding.name}_direct`));
return props;
}
function isDirectContentBinding(binding) {
if (binding.reads.size !== 1) return false;
const [read] = binding.reads.keys();
return read.nameOnly && read.section === binding.section;
}
function isPossiblyRead(alias) {
if (alias.reads.size) return true;
for (const nested of alias.aliases) if (isPossiblyRead(nested)) return true;
for (const prop of alias.propertyAliases.values()) if (isPossiblyRead(prop)) return true;
return false;
}
function hasSupersetExcludeProperties(binding, excludeProperties) {
if (excludeProperties === void 0) return false;
for (const prop of binding.propertyAliases.keys()) if (!propsUtil.has(excludeProperties, prop)) return false;
return true;
}
function getSettledParamsTree(paramsTree) {
if (!paramsTree || paramsTree.binding.pruned) return;
if (!paramsTree.props) return paramsTree;
const props = Object.create(null);
for (const name in paramsTree.props) {
const prop = getSettledParamsTree(paramsTree.props[name]);
if (prop) props[name] = prop;
}
return {
binding: paramsTree.binding,
props,
rest: getSettledParamsTree(paramsTree.rest)
};
}
function getParamsTreeAt(paramsTree, name) {
return paramsTree === true ? true : paramsTree.props ? paramsTree.props[name] || (paramsTree.rest ? getParamsTreeAt(paramsTree.rest, name) : void 0) : propsUtil.has(paramsTree.binding.excludeProperties, name) ? void 0 : true;
}
function getAllKnownPropNames(paramsTree) {
const keys = paramsTree.props ? Object.keys(paramsTree.props) : [];
if (paramsTree.rest?.props) for (const key of Object.keys(paramsTree.rest.props)) keys.push(key);
return keys;
}
function hasAllKnownProps(paramsTree) {
return paramsTree.props && (!paramsTree.rest || !!paramsTree.rest.props);
}
//#endregion
//#region src/translator/util/marko-config.ts
function isOutputHTML() {
return getMarkoOpts().output === "html";
}
function isOutputDOM() {
return getMarkoOpts().output === "dom";
}
function getMarkoOpts() {
return (0, _marko_compiler_babel_utils.getFile)().markoOpts;
}
function isOptimize() {
return getMarkoOpts().optimize;
}
function getReadyId(file = (0, _marko_compiler_babel_utils.getFile)()) {
const { markoOpts } = file;
if (!markoOpts.linkAssets) return void 0;
return (markoOpts.optimize ? "_" : "ready:") + (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, file.opts.filename);
}
//#endregion
//#region src/translator/util/to-property-name.ts
function getMemberExpressionPropString(expr) {
switch (expr.property.type) {
case "StringLiteral": return expr.property.value;
case "NumericLiteral": return "" + expr.property.value;
case "Identifier":
if (expr.computed) return;
return expr.property.name;
}
}
function getLiteralName(node) {
switch (node.type) {
case "Identifier": return node.name;
case "StringLiteral": return node.value;
}
}
function isValidPropertyIdentifier(name) {
return /^[a-z_$][a-z0-9_$]*$/i.test(name);
}
function toPropertyName(name) {
if (isValidPropertyIdentifier(name)) return _marko_compiler.types.identifier(name);
else if (/^(?:0|[1-9][0-9]*)$/.test(name)) return _marko_compiler.types.numericLiteral(parseInt(name, 10));
return _marko_compiler.types.stringLiteral(name);
}
function toObjectProperty(name, value) {
return _marko_compiler.types.objectProperty(toPropertyName(name), value);
}
function toMemberExpression(object, key, optional) {
const prop = toPropertyName(key);
const computed = prop.type !== "Identifier";
return optional ? _marko_compiler.types.optionalMemberExpression(object, prop, computed, true) : _marko_compiler.types.memberExpression(object, prop, computed);
}
//#endregion
//#region src/translator/util/runtime.ts
const pureDOMFunctions = /* @__PURE__ */ new Set([
"_await_promise",
"_await_content",
"_child_setup",
"_if",
"_if_closure",
"_show",
"_try",
"_dynamic_tag",
"_dynamic_tag_content",
"_content_closures",
"_template",
"_return_setup",
"_closure",
"_closure_get",
"_or",
"_for_closure",
"_for_selector",
"_for_in",
"_for_of",
"_for_of_unkeyed",
"_for_to",
"_for_to_unkeyed",
"_for_until",
"_for_until_unkeyed",
"_hoist",
"_let",
"_let_change",
"_const",
"_load_signal",
"_load_setup",
"_load_template",
"_load_visible_trigger",
"_load_event_trigger",
"_load_idle_trigger",
"_load_media_trigger",
"_load_race_trigger"
]);
const [getRuntimeImports] = createProgramState(() => /* @__PURE__ */ new Map());
function importRuntime(name) {
assertTranslate("importRuntime", name);
const { output } = getMarkoOpts();
const imports = getRuntimeImports();
let localName = imports.get(name);
if (!localName) {
localName = (0, _marko_compiler_babel_utils.importNamed)((0, _marko_compiler_babel_utils.getFile)(), getRuntimePath(output), name).name;
imports.set(name, localName);
}
return _marko_compiler.types.identifier(localName);
}
function registerRuntimeValue(id, value) {
return _marko_compiler.types.assignmentExpression("=", toMemberExpression(importRuntime("_resumed"), id), value);
}
function callRuntime(name, ...args) {
const callExpression = _marko_compiler.types.callExpression(importRuntime(name), trimFalsyArgs(args));
if (isOutputDOM() && pureDOMFunctions.has(name)) return _marko_compiler.types.addComment(callExpression, "leading", "@__PURE__");
return callExpression;
}
function dynamicImport(request, ...handlers) {
const load = _marko_compiler.types.callExpression(_marko_compiler.types.import(), [_marko_compiler.types.stringLiteral(request)]);
const args = trimFalsyArgs(handlers);
return args.length ? _marko_compiler.types.callExpression(_marko_compiler.types.memberExpression(load, _marko_compiler.types.identifier("then")), args) : load;
}
const domRuntimeFeatures = [
"catch",
"controllable",
"controllable-input",
"controllable-open",
"controllable-select",
"controllable-textarea",
"dynamic-tag-script",
"dynamic-tag-var",
"lazy",
"placeholder"
];
const [getImportedFeatures] = createProgramState(() => /* @__PURE__ */ new Set());
function importRuntimeFeature(feature) {
assertTranslate("importRuntimeFeature", feature);
const features = getImportedFeatures();
if (!features.has(feature)) {
features.add(feature);
const program = (0, _marko_compiler_babel_utils.getProgram)();
const decl = getRuntimeFeatureImport(feature);
const lastImport = program.get("body").findLast((stmt) => stmt.isImportDeclaration());
if (lastImport) lastImport.insertAfter(decl);
else program.unshiftContainer("body", decl);
}
}
function getRuntimeFeatureImport(feature) {
return _marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(`${getRuntimePath("dom")}/${feature}.feat`));
}
function getRuntimePath(output) {
const { optimize } = getMarkoOpts();
return `${runtime_info_default.name}/${optimize ? "" : "debug/"}${output === "html" ? "html" : "dom"}`;
}
function assertTranslate(helper, name) {
if (!isTranslate()) throw new Error(`\`${helper}(${JSON.stringify(name)})\` may only be called during the translate stage.`);
}
function trimFalsyArgs(args) {
const filteredArgs = [];
for (let i = args.length; i--;) {
const arg = args[i];
if (arg || filteredArgs.length) filteredArgs[i] = arg || _marko_compiler.types.buildUndefinedNode();
}
return filteredArgs;
}
function getCompatRuntimeFile() {
const markoOpts = getMarkoOpts();
return `marko/${markoOpts.optimize ? "dist" : "src"}/runtime/helpers/tags-compat/${isOutputHTML() ? "html" : "dom"}${markoOpts.optimize ? "" : "-debug"}.${markoOpts.modules === "esm" ? "mjs" : "js"}`;
}
//#endregion
//#region src/common/helpers.ts
const invalidNativeAttrNameReg = /^[^a-z_]|[^a-z0-9._:-]/i;
const invalidAttrNameReg = /^[^a-z_$]|[^a-z0-9._:-]/i;
const knownWrongAttrs = {
className: "class",
classList: "class",
htmlFor: "for",
acceptCharset: "accept-charset",
httpEquiv: "http-equiv",
defaultValue: "value",
defaultChecked: "checked",
dangerouslySetInnerHTML: "$!{html}",
key: "<for by>",
ref: "<tag/ref>",
"v-if": "<if>",
"v-else": "<else>",
"v-else-if": "<else if>",
"v-for": "<for>",
"v-show": "<if>",
"v-model": "value:=state",
"v-bind": "...attrs",
"v-html": "$!{html}",
"v-text": "${text}"
};
function getWrongAttrSuggestion(name) {
if (Object.hasOwn(knownWrongAttrs, name)) return knownWrongAttrs[name];
const colon = name.indexOf(":");
if (colon > 0) {
const rest = name.slice(colon + 1);
switch (name.slice(0, colon)) {
case "class": return `class={ ${rest}: condition }`;
case "style": return `style={ ${rest}: value }`;
case "on":
case "v-on": return `on${rest.charAt(0).toUpperCase()}${rest.slice(1)}`;
case "bind":
case "v-model": return `${rest}:=state`;
case "v-bind": return rest;
}
}
}
function stringifyClassEntry(name, value) {
return value ? name : "";
}
function stringifyStyleEntry(name, value) {
return value || value === 0 ? escapeStyleAttr(name) + ":" + escapeStyleAttr(value + "") : "";
}
const unsafeStyleAttrReg = /[\\;]/g;
const replaceUnsafeStyleAttr = (c) => c === ";" ? "\\3B " : "\\\\";
function escapeStyleAttr(str) {
return unsafeStyleAttrReg.test(str) ? str.replace(unsafeStyleAttrReg, replaceUnsafeStyleAttr) : str;
}
function escapeStyleValue(str) {
let closers = "";
const result = str.replace(/[\\"'{};<>]|\/(?=\*)/g, (c) => c === "<" ? "\\3C " : c === ";" ? "\\3B " : c === "{" ? "\\7B " : "\\" + c);
for (const c of result) if (c === "(") closers = ")" + closers;
else if (c === "[") closers = "]" + closers;
else if (c === closers[0]) closers = closers.slice(1);
return result + closers;
}
const toDelimitedString = function toDelimitedString(val, delimiter, stringify) {
let str = "";
let sep = "";
let part;
if (val) {
if (typeof val !== "object") str += val;
else if (Array.isArray(val)) for (const v of val) {
part = toDelimitedString(v, delimiter, stringify);
if (part) {
str += sep + part;
sep = delimiter;
}
}
else for (const name in val) {
part = stringify(name, val[name]);
if (part) {
str += sep + part;
sep = delimiter;
}
}
}
return str;
};
function isEventHandler(name) {
return /^on[A-Z-]/.test(name);
}
function getEventType(name) {
return name[2] === "-" ? name.slice(3) : name.slice(2).toLowerCase();
}
function isNullishOrFalse(value) {
return value == null || value === false;
}
const decodeAccessor = (num) => (num + (num < 26 ? 10 : num < 962 ? 334 : 11998)).toString(36);
//#endregion
//#region src/common/constants/accessor-prefix.ts
var accessor_prefix_exports = /* @__PURE__ */ __exportAll({
BranchScopes: () => "A",
ClosureScopes: () => "B",
ClosureSignalIndex: () => "C",
ConditionalRenderer: () => "D",
ControlledHandler: () => "E",
ControlledObserver: () => "N",
ControlledType: () => "F",
ControlledValue: () => "G",
DynamicHTMLLastChild: () => "H",
DynamicHTMLValue: () => "R",
EventAttributes: () => "I",
IdFallback: () => "J",
KeyedScopes: () => "O",
Lifecycle: () => "K",
Promise: () => "L",
TagVariableChange: () => "M",
TryBranch: () => "Q"
});
//#endregion
//#region src/common/constants/accessor-prop.ts
var accessor_prop_exports = /* @__PURE__ */ __exportAll({
AbortControllers: () => "A",
AbortScopes: () => "B",
AwaitCounter: () => "O",
BranchAccessor: () => "C",
BranchRenders: () => "BR",
BranchScopes: () => "D",
CatchContent: () => "E",
ClosestBranch: () => "F",
ClosestBranchId: () => "G",
DetachedAwait: () => "V",
EndNode: () => "K",
Gen: () => "H",
Global: () => "$",
Id: () => "L",
Load: () => "X",
LoopIndex: () => "I",
LoopKey: () => "M",
Owner: () => "_",
ParentBranch: () => "N",
PendingEffectScopes: () => "JS",
PendingEffects: () => "J",
PendingRenders: () => "W",
PendingScopes: () => "Y",
PlaceholderBranch: () => "P",
PlaceholderContent: () => "Q",
Renderer: () => "R",
ReturnValue: () => "RV",
StartNode: () => "S",
Subscriptions: () => "Z",
TagVariable: () => "T",
TagVariableChange: () => "U",
TryBranch: () => "PT"
});
//#endregion
//#region src/translator/util/get-accessor-enums.ts
function getAccessorPrefix() {
return isOptimize() ? accessor_prefix_exports : accessor_prefix_debug_exports;
}
function getAccessorProp() {
return isOptimize() ? accessor_prop_exports : accessor_prop_debug_exports;
}
//#endregion
//#region src/translator/util/scope-accessor.ts
function getSlotAccessor(slot) {
switch (slot.kind) {
case 0: return getScopeAccessor(slot.owner);
case 1: return getPrefixedScopeAccessor(slot.owner, getAccessorPrefix().TagVariableChange);
case 2: return getPrefixedScopeAccessor(slot.owner, getAccessorPrefix().ClosureScopes);
case 3: return getPrefixedScopeAccessor(slot.owner, getAccessorPrefix().ClosureSignalIndex);
case 7: return getAccessorProp().Owner;
case 8: return getAccessorProp().TagVariableChange;
case 10: return getSectionInstancesAccessor(slot.owner);
}
}
function getScopeOffsetAccessorLiteral(nodeBinding, encoded) {
return encoded && isOptimize() ? _marko_compiler.types.numericLiteral(getReservedId(nodeBinding, 1)) : _marko_compiler.types.stringLiteral(getScopeOffsetAccessor(nodeBinding));
}
function getScopeOffsetAccessor(nodeBinding) {
const id = getReservedId(nodeBinding, 1);
return isOptimize() ? decodeAccessor(id) : `#scopeOffset/${id}`;
}
function getReservedId(binding, offset) {
return getCanonicalBinding(binding).id + offset;
}
function getScopeAccessorLiteral(binding, encoded, includeId) {
const canonicalBinding = getCanonicalBinding(binding);
return encoded && isOptimize() && canonicalBinding.type !== 5 ? _marko_compiler.types.numericLiteral(canonicalBinding.id) : _marko_compiler.types.stringLiteral(getScopeAccessor(binding, encoded, includeId));
}
function getScopeAccessor(binding, encoded, includeId) {
const canonicalBinding = getCanonicalBinding(binding);
if (canonicalBinding.type === 5) return canonicalBinding.scopeAccessor ?? canonicalBinding.name;
else if (isOptimize()) return encoded ? canonicalBinding.id + "" : decodeAccessor(canonicalBinding.id);
const name = reservedDebugAccessors.has(canonicalBinding.name) ? `${canonicalBinding.name}/${canonicalBinding.id}` : canonicalBinding.name;
if (includeId || canonicalBinding.type === 0) return `${name}/${canonicalBinding.id}`;
return canonicalBinding.scopeAccessor ?? name;
}
const reservedDebugAccessors = new Set(Object.values(accessor_prop_debug_exports));
function getLocalsScopeAccessor(binding) {
return getScopeAccessor(binding, false, true);
}
function getPrefixedScopeAccessor(binding, prefix) {
const canonicalBinding = getCanonicalBinding(binding);
if (isOptimize()) switch (prefix) {
case getAccessorPrefix().TagVariableChange: return decodeAccessor(getReservedId(canonicalBinding, 1));
case getAccessorPrefix().ClosureScopes: return decodeAccessor(getClosureAccessorId(canonicalBinding));
case getAccessorPrefix().ClosureSignalIndex: return prefix + decodeAccessor(getClosureAccessorId(canonicalBinding));
}
else if (prefix === getAccessorPrefix().ClosureScopes || prefix === getAccessorPrefix().ClosureSignalIndex) return prefix + getDebugClosureAccessor(binding);
return prefix + getScopeAccessor(binding);
}
function getClosureAccessorLiteral(binding) {
return isOptimize() ? _marko_compiler.types.numericLiteral(getClosureAccessorId(binding)) : _marko_compiler.types.stringLiteral(getDebugClosureAccessor(binding));
}
function getDebugClosureAccessor(binding) {
return `${getScopeAccessor(binding)}/${getClosureAccessorId(binding)}`;
}
function getClosureAccessorId(binding) {
const id = getCanonicalBinding(binding).closureId;
/* v8 ignore next 5 -- analyze reserves an id for every closure binding */
if (id === void 0) throw new Error(`No closure accessor id was reserved for "${binding.name}".`);
return id;
}
function getSectionInstancesAccessor(section) {
return isOptionalBranch(section) ? getAccessorPrefix().BranchScopes + getScopeAccessor(section.branch.nodeBinding) : getAccessorPrefix().ClosureScopes + section.id;
}
function getSectionInstancesAccessorLiteral(section) {
return _marko_compiler.types.stringLiteral(getSectionInstancesAccessor(section));
}
//#endregion
//#region src/translator/util/scope-read.ts
let scopeIdentifier;
let localsIdentifier;
function createScopeIdentifiers() {
scopeIdentifier = isOutputDOM() ? generateUidIdentifier("scope") : null;
localsIdentifier = isOutputDOM() ? generateUidIdentifier("locals") : null;
}
function getScopeExpression(section, targetSection) {
let scope = scopeIdentifier ?? _marko_compiler.types.identifier("undefined");
const diff = section.depth - targetSection.depth;
for (let i = 0; i < diff; i++) scope = _marko_compiler.types.memberExpression(scope, _marko_compiler.types.identifier(getAccessorProp().Owner));
if (diff < 0) throw new Error("Unable to find scope for reference.");
return scope;
}
function createScopeReadExpression(reference, section = reference.section) {
const expr = toMemberExpression(getScopeExpression(section, reference.section), getScopeAccessor(reference));
if (section === reference.section && reference.type !== 0) {
const exprExtra = expr.extra ??= {};
exprExtra.read = createResolvedRead(reference, void 0);
exprExtra.section = section;
}
return expr;
}
//#endregion
//#region src/translator/util/section-renderer.ts
function getSectionRendererIdentifier(section) {
return isSectionRendererElided(section) ? void 0 : _marko_compiler.types.identifier(section.name);
}
function isSectionRendererElided(section) {
return section.dropped || !!section.derives && !(section.derives.tag.tagNameNullable && section.derives.properties === "content") && !some(section.derives.binding, (binding) => isPropertyPathRead(binding, section.derives.properties));
}
function isPropertyPathRead(binding, properties) {
if (binding.pruned) return false;
else if (binding.pruned === void 0) throw new Error("Binding must be pruned before checking properties");
if (binding.reads.size || !properties) return true;
const property = first(properties);
const propBinding = binding.propertyAliases.get(property);
if (propBinding && isPropertyPathRead(propBinding, rest(properties))) return true;
for (const alias of binding.aliases) if (isPropertyPathRead(alias, properties)) return true;
return false;
}
//#endregion
//#region src/translator/util/setup-work.ts
const [getSetupInfo] = createSectionState("setupWork", () => ({
always: false,
exprs: /* @__PURE__ */ new Set()
}));
function addSetupExpr(section, node) {
getSetupInfo(section).exprs.add(node.extra ??= {});
}
function addSetupWork(section) {
getSetupInfo(section).always = true;
}
function finalizeSetupWork() {
forEachSection((section) => {
if (hasOwnSetupWork(section)) section.hasSetupWork = true;
});
forEachSection((section) => {
if (section.hasSetupWork || section.readsOwner) setCallSectionsSetup(section);
});
}
function setCallSectionsSetup(body) {
forEach(body.callSections, (callSection) => {
if (!callSection.hasSetupWork) {
callSection.hasSetupWork = true;
setCallSectionsSetup(callSection);
}
});
}
function hasOwnSetupWork(section) {
const info = getSetupInfo(section);
if (info.always || section.referencedClosures || callsOtherTemplateSetup(section)) return true;
for (const expr of info.exprs) {
const extra = getCanonicalExtra(expr);
if (!extra.dropped && !getReferencedBindings(extra)) return true;
}
return false;
}
//#endregion
//#region src/translator/util/for-selector.ts
function getForSelectorKey(bodySection, closure) {
const { selector } = bodySection;
if (selector?.closures.has(getCanonicalBinding(closure))) return selector.key;
}
function isForSelectorValue(binding) {
return some(binding.closureSections, (section) => !!section.selector?.closures.has(binding));
}
function detectForSelector(bodySection, keyBinding) {
let closures;
for (const expr of keyBinding.reads.keys()) {
if (expr.section !== bodySection) continue;
forEach(getReferencedBindings(expr), (closure) => {
const canonical = getCanonicalBinding(closure);
if (closure.type !== 5 && isDirectClosure(bodySection, closure) && !closures?.has(canonical) && onlyComparesKey(closure, canonical, bodySection, keyBinding)) (closures ||= /* @__PURE__ */ new Set()).add(canonical);
});
}
if (closures) bodySection.selector = {
key: keyBinding,
closures
};
}
function onlyComparesKey(closure, canonical, bodySection, keyBinding) {
let found = false;
for (let chain = closure; chain; chain = chain.aliasOf) for (const [expr, reads] of chain.reads) {
if (expr.section !== bodySection) continue;
let other = false;
forEach(reads, (read) => {
const resolved = read.extra.read;
if (!resolved) return;
if (resolvesTo(resolved, canonical)) {
const keyRead = read.comparedTo?.extra?.read;
if (resolved.getter || !readsKey(keyRead, keyBinding)) other = true;
else found = true;
} else other ||= resolvesThrough(resolved, canonical);
});
if (other) return false;
}
return found;
}
function resolvesTo(read, canonical) {
const binding = getPropertyAlias(read.binding, read.props);
return !!binding && getCanonicalBinding(binding) === canonical;
}
function resolvesThrough(read, canonical) {
let binding = read.binding;
let through = false;
forEach(read.props, (prop) => {
if (binding) {
through ||= getCanonicalBinding(binding) === canonical;
binding = binding.propertyAliases.get(prop);
}
});
return through;
}
function readsKey(read, keyBinding) {
if (!read || read.getter) return false;
const binding = getPropertyAlias(read.binding, read.props);
return !!binding && getCanonicalBinding(binding) === getCanonicalBinding(keyBinding);
}
//#endregion
//#region src/translator/util/get-declared-binding-expression.ts
function getDeclaredBindingExpression(binding, inPlace = false) {
const canonicalBinding = getCanonicalBinding(binding);
if (canonicalBinding.localOf) return getDeclaredBindingExpression(canonicalBinding.localOf, inPlace);
const { aliasOf: aliased, property, declaredAlias } = canonicalBinding;
if (binding.declared) return _marko_compiler.types.identifier(binding.name);
if (canonicalBinding.declared || isRest(canonicalBinding)) return _marko_compiler.types.identifier(canonicalBinding.name);
if (declaredAlias && !isRest(declaredAlias) && !getNearestDeclared(canonicalBinding)) return _marko_compiler.types.identifier(declaredAlias.name);
if (!aliased) return _marko_compiler.types.identifier(canonicalBinding.name);
if (property !== void 0) {
const alias = getDeclaredAlias(aliased);
if (alias && !propsUtil.has(alias.excludeProperties, property)) return toMemberExpression(_marko_compiler.types.identifier(alias.name), alias.restOffset ? `${+property - alias.restOffset}` : property, !inPlace && alias.nullable);
return toMemberExpression(getDeclaredBindingExpression(aliased, inPlace), property, !inPlace && aliased.nullable);
}
return getDeclaredBindingExpression(aliased, inPlace);
}
//#endregion
//#region src/translator/util/with-previous-location.ts
function withPreviousLocation(newNode, originalNode) {
newNode.start = originalNode.start;
newNode.loc = originalNode.loc;
newNode.end = originalNode.end;
return newNode;
}
//#endregion
//#region src/translator/util/read-replacement.ts
function getReadReplacement(node, signal) {
const { extra } = node;
if (!extra || extra.assignment) return;
const { read, binding } = extra;
if (!read) {
if (binding && node.type === "Identifier" && node.name !== binding.name) node.name = binding.name;
return;
}
if (read.getter?.invoked) return;
const base = isOutputDOM() ? getDOMReadBase(read, extra.section, signal) : getHTMLReadBase(node, read);
if (!base) return;
const expr = reduce(read.props, addMember, base);
if (node.type === "Identifier" && expr.type === "Identifier") {
node.name = expr.name;
return;
}
return getChainReplacement(node, expr, isOutputDOM() ? size(read.props) : Infinity);
}
function getDOMReadBase(read, section, signal) {
const { binding, props, getter } = read;
if (read.localFn) return isRegisteredFnExtra(read.localFn) ? toMemberExpression(localsIdentifier, getLocalsScopeAccessor(binding)) : _marko_compiler.types.identifier(binding.name);
if (props === void 0) {
const inlined = getSignals(section).get(binding)?.inline?.value;
if (inlined) return _marko_compiler.types.cloneNode(inlined, true);
}
if (signal?.referencedBindings === binding && !signal.storesValue) return getSignalValueIdentifier(signal);
if (getter?.hoisted) return binding.aliasOf ? callRuntime("_hoist_read_error") : _marko_compiler.types.callExpression(getBindingGetterIdentifier(binding, getter.hoisted), [getScopeExpression(section, getter.hoisted)]);
if (props === void 0 && binding.type === 0) return getter && _marko_compiler.types.callExpression(getBindingGetterIdentifier(binding, binding.section), [getScopeExpression(section, binding.section)]);
if (!isOptimize() && read.inOwnBody && isChildReturnVar(binding)) return callRuntime("_assert_init", section ? getScopeExpression(section, binding.section) : scopeIdentifier, getScopeAccessorLiteral(binding));
return createScopeReadExpression(binding, section);
}
function isChildReturnVar(binding) {
return !!getAliasRoot(binding).returnedBy;
}
function getHTMLReadBase(node, { binding, getter }) {
if (getter?.hoisted) return binding.aliasOf ? callRuntime("_hoist_read_error") : getBindingGetterIdentifier(binding, getter.hoisted);
if (binding.type === 0) return binding.getters.has(binding.section) ? getBindingGetterIdentifier(binding, binding.section) : void 0;
let root = node;
while (root.type === "MemberExpression" || root.type === "OptionalMemberExpression") root = root.object;
const rootBinding = root.extra?.binding;
if (rootBinding?.declared && !rootBinding.pruned) {
root.name = rootBinding.name;
return;
}
return getDeclaredBindingExpression(binding, true);
}
function getChainReplacement(node, expr, depth) {
let replaceMember;
let cur = node;
while (depth-- > 0 && (cur.type === "MemberExpression" || cur.type === "OptionalMemberExpression") && (expr.type === "MemberExpression" || expr.type === "OptionalMemberExpression") && getMemberExpressionPropString(cur) === getMemberExpressionPropString(expr)) {
replaceMember = cur;
cur = cur.object;
expr = expr.object;
}
if (!replaceMember) return withPreviousLocation(expr, node);
if (replaceMember.type === "OptionalMemberExpression") replaceMember.optional = true;
replaceMember.object = withPreviousLocation(expr, replaceMember.object);
}
function addMember(expr, prop) {
return toMemberExpression(expr, prop);
}
//#endregion
//#region src/translator/util/simplify-fn.ts
function replaceMethodNode(node, replacement) {
switch (node.type) {
case "ClassMethod": return _marko_compiler.types.classProperty(node.key, replacement, void 0, void 0, node.computed, node.static);
case "ClassPrivateMethod": return _marko_compiler.types.classPrivateProperty(node.key, replacement, void 0, node.static);
case "ObjectMethod": return _marko_compiler.types.objectProperty(node.key, replacement, node.computed);
}
}
/**
* Given any arbitrary function type will normalize method like functions into expressions.
*/
function simplifyFunction(fn) {
switch (fn.type) {
case "FunctionDeclaration":
case "FunctionExpression":
case "ArrowFunctionExpression": return fn;
default: return _marko_compiler.types.functionExpression(null, fn.params, fn.body, fn.generator, fn.async);
}
}
//#endregion
//#region src/translator/util/to-only-or-block.ts
function toOnlyExpressionOrBlock(stmts) {
if (stmts.length === 1 && _marko_compiler.types.isExpressionStatement(stmts[0])) return stmts[0].expression;
return _marko_compiler.types.blockStatement(stmts);
}
function toOnlyStatementOrBlock(body) {
if (body.length === 1) return body[0];
return _marko_compiler.types.blockStatement(body);
}
//#endregion
//#region src/translator/util/translate-var.ts
function translateVar(tag, initialValue, kind = "const", statements) {
const { node: { var: tagVar } } = tag;
if (!tagVar) return;
const varBinding = tagVar.extra?.binding;
if (!varBinding || varBinding.aliasOf) {
const section = getSection(tag);
let sectionDeclares = false;
forEachIdentifier(tagVar, (id) => {
const binding = id.extra.binding;
if (binding.pruned) return;
if (binding.declared) {
if (binding.section === section) sectionDeclares = true;
else translateAliasInSection(tag, id, binding, kind);
} else if (isRest(binding)) translateRest(tag, id, binding, kind);
});
if (!sectionDeclares) return;
removeUndeclared(tagVar, section);
initialValue = getDeclaredBindingExpression(initialValue.extra.binding, false);
}
forEachIdentifierPath(tag.get("var"), (id) => {
if (id.node === tagVar) return;
const idExtra = id.node.extra;
if (!idExtra) return;
const binding = idExtra.binding;
if (!binding?.aliasOf) return;
if (binding.assignments && binding.property !== void 0) {
const changeName = binding.property + "Change";
const changeBinding = binding.aliasOf.propertyAliases.get(changeName);
if (changeBinding && changeName !== changeBinding.name) {
const pattern = getDestructurePattern(id);
if (pattern) pattern.unshiftContainer("properties", _marko_compiler.types.objectProperty(toPropertyName(changeName), _marko_compiler.types.identifier(changeBinding.name)));
}
}
});
const declaration = _marko_compiler.types.variableDeclaration(kind, [_marko_compiler.types.variableDeclarator(tagVar, initialValue)]);
if (statements) statements.push(declaration);
else tag.insertBefore(declaration);
}
function isTagVarAssigned(tag) {
return !!(tag.node.var.type === "Identifier" && tag.scope.getBinding(tag.node.var.name)?.constantViolations.length);
}
function buildVarChange(target, value, varBinding) {
const changeArgs = [target, value];
if (!isOptimize()) changeArgs.push(_marko_compiler.types.stringLiteral(varBinding.name));
return _marko_compiler.types.callExpression(importRuntime("_var_change"), changeArgs);
}
function removeUndeclared(pattern, section) {
switch (pattern.type) {
case "Identifier": {
const binding = pattern.extra.binding;
return binding.declared && binding.section === section;
}
case "ObjectPattern":
pattern.properties = pattern.properties.filter((prop) => removeUndeclared(prop.type === "RestElement" ? prop.argument : prop.value, section));
return pattern.properties.length > 0;
case "ArrayPattern": {
let kept = 0;
pattern.elements = pattern.elements.map((element, i) => {
if (element && removeUndeclared(element.type === "RestElement" ? element.argument : element, section)) {
kept = i + 1;
return element;
}
return null;
});
pattern.elements.length = kept;
return kept > 0;
}
}
return false;
}
function translateAliasInSection(tag, id, alias, kind) {
const aliased = alias.aliasOf;
const value = getDeclaredBindingExpression(aliased);
getSectionTarget(tag, alias.section).insertBefore(_marko_compiler.types.variableDeclaration(kind, [_marko_compiler.types.variableDeclarator(id, alias.property === void 0 ? value : toMemberExpression(value, alias.property, aliased.nullable))]));
}
function translateRest(tag, id, rest, kind) {
const source = getCanonicalBinding(rest.aliasOf);
const from = getDeclaredAlias(source) || source;
let target = tag;
let inPlace = true;
if (rest.section !== getSection(tag) && findSlot(rest)?.reason) {
target = getSectionTarget(tag, rest.section);
inPlace = false;
}
const value = getDeclaredBindingExpression(from, inPlace);
target.insertBefore(_marko_compiler.types.variableDeclaration(kind, [_marko_compiler.types.variableDeclarator(getRestPattern(rest, id, from, false), inPlace ? value : withRestFallback(rest, from, value))]));
}
function getRestPattern(rest, id, from, shorthand) {
const restElement = _marko_compiler.types.restElement(id);
if (rest.restOffset !== void 0) return _marko_compiler.types.arrayPattern([...new Array(rest.restOffset - (from.restOffset || 0)).fill(null), restElement]);
return _marko_compiler.types.objectPattern([...toArray(rest.excludeProperties, shorthand ? (name) => name === id.name ? toExcludedProperty(name) : toShorthandExcludedProperty(name) : toExcludedProperty), restElement]);
}
function withRestFallback(rest, from, value) {
return from.nullable ? _marko_compiler.types.logicalExpression("||", value, rest.restOffset !== void 0 ? _marko_compiler.types.arrayExpression([]) : _marko_compiler.types.objectExpression([])) : value;
}
function getSectionTarget(tag, section) {
let target = tag;
let cur = tag.parentPath;
while (cur.node.extra?.section !== section) {
target = cur;
cur = cur.parentPath;
}
return cur.parentPath ? cur : target;
}
function toExcludedProperty(name) {
return _marko_compiler.types.objectProperty(toPropertyName(name), generateUidIdentifier(name));
}
function toShorthandExcludedProperty(name) {
if (!_marko_compiler.types.isValidIdentifier(name)) return toExcludedProperty(name);
const id = _marko_compiler.types.identifier(name);
return _marko_compiler.types.objectProperty(id, id, false, true);
}
function getDestructurePattern(id) {
let cur = id;
while (cur) {
if (cur.node.type === "ObjectPattern") return cur;
cur = cur.parentPath;
}
}
//#endregion
//#region src/translator/util/with-comment.ts
function withLeadingComment(node, value) {
if (value) {
const comment = {
type: "CommentBlock",
value: ` ${value} `
};
node.leadingComments = node.leadingComments ? [...node.leadingComments, comment] : [comment];
}
return node;
}
//#endregion
//#region src/translator/util/sources.ts
const ALWAYS = {
state: void 0,
param: void 0,
global: void 0,
always: true
};
const globalSources = {
state: void 0,
param: void 0,
global: true,
always: void 0
};
function sharesSources(a, b) {
return !!a.sources && !!b.sources && (bindingUtil.intersects(a.sources.state, b.sources.state) || bindingUtil.intersects(a.sources.param, b.sources.param));
}
function createSources(state, param, global, always) {
/* v8 ignore next 6 -- every caller passes at least one source */
if (!(state || param || global || always)) throw new Error("Cannot create sources that reference no state, param or $global.");
return {
state,
param,
global,
always
};
}
function withSources(sources, state, param) {
return state || param || sources.global || sources.always ? createSources(state, param, sources.global, sources.always) : void 0;
}
const sourcesUtil = new Sorted(compareSources);
function compareSources(a, b) {
let delta;
if (a.always !== b.always) return a.always ? 1 : -1;
if (a.global !== b.global) return a.global ? 1 : -1;
if (a.param) {
if (!b.param) return 1;
if (delta = compareReferences(a.param, b.param)) return delta;
} else if (b.param) return -1;
if (a.state) {
if (!b.state) return 1;
if (delta = compareReferences(a.state, b.state)) return delta;
} else if (b.state) return -1;
return 0;
}
function mergeSources(a, b) {
if (!a) return b;
if (!b) return a;
if (a.state === b.state && a.param === b.param && a.global === b.global && a.always === b.always) return a;
return createSources(bindingUtil.union(a.state, b.state), unionParamSources(a.param, b.param), a.global || b.global, a.always || b.always);
}
function unionParamSources(a, b) {
const merged = bindingUtil.union(a, b);
if (merged === a || merged === b) return merged;
return bindingUtil.filter(merged, (binding) => !someUpToAliasRoot(binding.aliasOf, isInParams, merged));
}
function isInParams(binding, params) {
return bindingUtil.has(params, binding);
}
function isSupersetSources(a, b) {
if (!b.sources) return true;
if (!a.sources) return false;
return bindingUtil.isSuperset(a.sources.state, b.sources.state) && bindingUtil.isSuperset(a.sources.param, b.sources.param);
}
//#endregion
//#region src/translator/util/write-guard.ts
function isSameReason(a, b) {
return a === b || (a && b ? a.always && b.always || compareSources(a, b) === 0 : false);
}
const [getSectionGuards] = createSectionState("sectionGuards", (section) => ({
if: createGuardHoists(),
guard: createGuardHoists(),
declarators: [_marko_compiler.types.variableDeclarator(scopeReasonIdentifier(section), callRuntime("_scope_reason"))]
}));
function buildGroupMask(groups) {
let mask = 0;
let maskNames = "";
let dynamic;
const props = [];
let needsObject = false;
let any = false;
for (let i = 0; i < groups.length; i++) {
const { value, names } = groups[i];
if (value === void 0) continue;
any = true;
if (value === 0) continue;
if (i >= 15) needsObject = true;
else if (typeof value === "number") {
mask |= value << 1 + 2 * i;
if (names) maskNames += maskNames ? ` | ${names}` : names;
} else {
const shifted = _marko_compiler.types.binaryExpression("<<", value, withLeadingComment(_marko_compiler.types.numericLiteral(1 + 2 * i), names));
dynamic = dynamic ? _marko_compiler.types.binaryExpression("|", dynamic, shifted) : shifted;
}
props.push(_marko_compiler.types.objectProperty(withLeadingComment(_marko_compiler.types.numericLiteral(i), names), typeof value === "number" ? _marko_compiler.types.numericLiteral(value) : value));
}
if (needsObject) return _marko_compiler.types.objectExpression(props);
if (!any) return;
const literal = mask ? withLeadingComment(_marko_compiler.types.numericLiteral(mask), maskNames) : void 0;
return literal && dynamic ? _marko_compiler.types.binaryExpression("|", literal, dynamic) : literal || dynamic || _marko_compiler.types.numericLiteral(0);
}
function getScopeReasonStatement(section) {
return hasConditionalReason(section) ? _marko_compiler.types.variableDeclaration("const", getSectionGuards(section).declarators) : _marko_compiler.types.expressionStatement(callRuntime("_scope_reason"));
}
function getWriteReason(binding) {
return findSlot(binding)?.reason;
}
function getBranchWriteReason(section) {
return findSectionSlot(section, 9)?.reason;
}
function getWriteGuard(section, reason, omitUnconditional) {
if (!isDynamicWriteGuard(section, reason)) {
if (!reason) return _marko_compiler.types.numericLiteral(0);
return omitUnconditional ? void 0 : withLeadingComment(_marko_compiler.types.numericLiteral(1), getDebugNames(reason.always ? void 0 : reason.state));
}
return orEachParamGroup(reason.param, true);
}
function getWriteGuardForAny(section, reasons, omitUnconditional) {
if (!Array.isArray(reasons)) return getWriteGuard(section, reasons, omitUnconditional);
for (const reason of reasons) if (!isConditionalReason(reason)) return omitUnconditional ? void 0 : withLeadingComment(_marko_compiler.types.numericLiteral(1), getDebugNames(reason.state));
let expr;
for (const reason of reasons) expr = orGuard(expr, getWriteGuard(section, reason, false));
return expr;
}
function getExprIfWritten(section, reason, expr) {
if (!isDynamicWriteGuard(section, reason)) return reason && expr;
return andGuard(orEachParamGroup(reason.param, false), expr);
}
function orEachParamGroup(params, isGuard) {
return reduceParamGroups(params, isGuard ? orWriteGuard : orWriteIf, void 0);
}
function orWriteGuard(expr, section, group) {
return orGuard(expr, getOrHoistSectionGuard(section, group, true));
}
function orWriteIf(expr, section, group) {
return orGuard(expr, getOrHoistSectionGuard(section, group, false));
}
function orGuard(guard, other) {
return guard ? _marko_compiler.types.logicalExpression("||", guard, other) : other;
}
function andGuard(guard, expr) {
return guard ? _marko_compiler.types.logicalExpression("&&", guard, expr) : expr;
}
function getOrHoistSectionGuard(section, params, isGuard) {
if (!section.paramReasonGroups) return scopeReasonIdentifier(section);
const state = getSectionGuards(section);
const tracking = isGuard ? state.guard : state.if;
const index = getParamReasonGroupIndex(section, params);
const name = tracking.names.get(index);
if (name) return _marko_compiler.types.identifier(name);
const guard = callRuntime(isGuard ? "_write_guard" : "_write_if", scopeReasonIdentifier(section), withLeadingComment(_marko_compiler.types.numericLiteral(index), getDebugNames(params)));
const pending = tracking.pending.get(index);
if (!pending) {
const expr = _marko_compiler.types.parenthesizedExpression(guard);
tracking.pending.set(index, expr);
return expr;
}
const hoisted = generateUid(`${isGuard ? "wg" : "wi"}__${getDebugNamesAsIdentifier(params)}`);
tracking.names.set(index, hoisted);
tracking.pending.delete(index);
state.declarators.push(_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(hoisted), guard));
pending.expression = _marko_compiler.types.identifier(hoisted);
return _marko_compiler.types.parenthesizedExpression(_marko_compiler.types.identifier(hoisted));
}
function isDynamicWriteGuard(section, reason) {
return isConditionalReason(reason) && !isCrossSection(section, reason);
}
function isCrossSection(section, reason) {
return some(reason.param, (param) => !isSameOrAncestorSection(param.section, section));
}
function createGuardHoists() {
return {
names: /* @__PURE__ */ new Map(),
pending: /* @__PURE__ */ new Map()
};
}
function hasConditionalReason(section) {
if (section.paramReasonGroups || isConditionalReason(section.reason)) return true;
return some(section.slots, isConditionalSlot);
}
function isConditionalSlot(slot) {
return isConditionalReason(slot.reason);
}
function scopeReasonIdentifier(section) {
return _marko_compiler.types.identifier(ensureSharedUid(`scope${section.id}_reason`, section));
}
//#endregion
//#region src/translator/util/build-string-expression.ts
function buildStringExpression(parts, useIife) {
const strs = [""];
const exprs = [];
for (const part of parts) joinPart(strs, exprs, part);
const curStr = strs[exprs.length];
if (exprs.length) {
if (exprs.length === 1 && !curStr && !strs[0]) return exprs[0];
const quasis = [];
for (const str of strs) quasis.push(toTemplateElement(str));
if (useIife) {
const args = [];
const params = [];
const body = _marko_compiler.types.templateLiteral(quasis, exprs.map((expr) => {
if (expr.type !== "Identifier") return expr;
const param = _marko_compiler.types.identifier(`_w${params.length}`);
params.push(param);
args.push(expr);
return param;
}));
const iife = _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression(params, body), args);
_marko_compiler.types.addComment(iife, "leading", "@__PURE__");
return iife;
}
return _marko_compiler.types.templateLiteral(quasis, exprs);
} else if (curStr) return _marko_compiler.types.stringLiteral(curStr);
}
function appendLiteral(arr, str) {
arr[arr.length - 1] += str;
}
function toTemplateElement(value, tail) {
return _marko_compiler.types.templateElement({ raw: escapeTemplateRaw(value) }, tail);
}
function escapeTemplateRaw(raw) {
return raw.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$(?=\{)/g, "\\$");
}
function joinPart(strs, exprs, part) {
if (typeof part === "string") appendLiteral(strs, part);
else if (part.type === "StringLiteral") appendLiteral(strs, part.value);
else if (part.type === "TemplateLiteral") {
const { quasis, expressions } = part;
for (let i = 0; i < expressions.length; i++) {
appendLiteral(strs, quasis[i].value.cooked ?? "");
joinPart(strs, exprs, expressions[i]);
}
appendLiteral(strs, quasis[expressions.length].value.cooked ?? "");
} else {
exprs.push(part);
strs.push("");
}
}
//#endregion
//#region src/translator/util/writer.ts
const [getWrites] = createSectionState("writes", () => [""]);
const [getTrailerWrites] = createSectionState("trailerWrites", () => [""]);
function writeTo$1(path, trailer) {
const section = getSection(path);
const get = trailer ? getTrailerWrites : getWrites;
return (strs, ...exprs) => {
const exprsLen = exprs.length;
const writes = get(section);
appendLiteral(writes, strs[0]);
for (let i = 0; i < exprsLen; i++) writes.push(exprs[i], strs[i + 1]);
};
}
function consumeHTML(path) {
const section = getSection(path);
const writes = getWrites(section);
const trailers = getTrailerWrites(section);
const writeResult = buildStringExpression(writes.map(unwrapWrite));
const trailerResult = buildStringExpression(trailers);
writes.length = 0;
writes[0] = "";
trailers.length = 0;
trailers[0] = "";
if (writeResult && trailerResult) return _marko_compiler.types.expressionStatement(_marko_compiler.types.sequenceExpression([callRuntime("_html", writeResult), callRuntime("_trailers", trailerResult)]));
else if (writeResult) return _marko_compiler.types.expressionStatement(callRuntime("_html", writeResult));
else if (trailerResult) return _marko_compiler.types.expressionStatement(callRuntime("_trailers", trailerResult));
}
function flushBefore(path) {
const expr = consumeHTML(path);
if (expr) path.insertBefore(expr)[0].skip();
}
function flushInto(path) {
const target = path.isProgram() ? path : path.get("body");
const expr = consumeHTML(target);
if (expr) target.node.body.push(expr);
return target;
}
function markNode(path, nodeBinding, reason, deferred) {
if (nodeBinding.type !== 0) throw path.buildCodeFrameError("POTENTIAL MARKO BUG: Tried to mark a node that was not determined to need a mark during analyze.");
if (isOutputHTML()) {
if (reason) {
const section = getSection(path);
writeTo$1(path, deferred)`${callRuntime("_el_resume", getScopeIdIdentifier(section), getScopeAccessorLiteral(nodeBinding), getWriteGuard(section, reason, true))}`;
}
}
}
function unwrapWrite(write) {
return typeof write === "function" ? write() || "" : write;
}
//#endregion
//#region src/translator/util/signals.ts
const [getSignals] = createSectionState("signals", () => /* @__PURE__ */ new Map());
const [getClosureSignalBuilder, _setClosureSignalBuilder] = createSectionState("queue");
function setClosureSignalBuilder(tag, hop, build = (_closure, render) => buildClosureHop(hop, render)) {
_setClosureSignalBuilder(getSectionForBody(tag.get("body")), build);
}
function buildClosureHop(hop, render) {
const accessor = getScopeAccessorLiteral(hop.nodeBinding, true);
return hop.kind === "if" ? callRuntime("_if_closure", accessor, _marko_compiler.types.numericLiteral(hop.index), render) : callRuntime("_for_closure", accessor, render);
}
const [getOwnerResumedByMarker, setOwnerResumedByMarker] = createSectionState("ownerResumedByMarker");
function setSectionOwnerResumedByMarker(section) {
setOwnerResumedByMarker(section, true);
}
function getContentClosureValues(bodySection) {
const contentClosures = bindingUtil.filter(getDynamicTagContentClosures(bodySection), mayBeUnwritten);
if (!contentClosures) return;
const scope = generateUidIdentifier("scope");
const closures = Array.isArray(contentClosures) ? contentClosures : [contentClosures];
const ownerAccessor = getAccessorProp().Owner;
const levels = [];
for (let i = closures.length, section = bodySection.parent; i;) {
const props = [];
while (i && closures[i - 1].section === section) {
const closure = closures[--i];
props.push(toObjectProperty(getScopeAccessor(closure), getDeclaredBindingExpression(closure)));
}
if (i) props.push(toObjectProperty(ownerAccessor, _marko_compiler.types.callExpression(scope, [getScopeIdIdentifier(section.parent)])));
levels.push(_marko_compiler.types.objectExpression(props));
section = section.parent;
}
return {
scope,
levels: levels.reverse()
};
}
function mayBeUnwritten(closure) {
return !isUnconditionalReason(getWriteReason(closure));
}
const [getScopeProperties] = createSectionState("scopeProperties", () => /* @__PURE__ */ new Map());
function writeSlot(slot, expression) {
const reason = slot?.reason;
if (reason) {
const accessor = getSlotAccessor(slot);
getScopeProperties(slot.section).set(accessor, {
expression,
reason
});
return accessor;
}
}
const [getSectionDebugVars] = createSectionState("sectionDebugVars", () => /* @__PURE__ */ new Map());
function setSectionDebugVar(section, accessor, name, loc) {
if (!isOptimize()) getSectionDebugVars(section).set(accessor, loc ? [name, getDebugLoc(loc)] : [name]);
}
const [getSectionWriteScopeBuilder, setSectionWriteScopeBuilder] = createSectionState("sectionWriteScopeBuilder");
function addWriteScopeBuilder(section, builder) {
const prev = getSectionWriteScopeBuilder(section);
setSectionWriteScopeBuilder(section, prev ? (expr) => builder(prev(expr)) : builder);
}
const htmlDynamicClosureInstancesIdentifier = /* @__PURE__ */ new WeakMap();
const [getHTMLSectionStatements] = createSectionState("htmlScopeStatements", () => []);
const [getSectionReturnValueIdentifier, setReturnValueIdentifier] = createSectionState("returnValue");
const [getBindingGetterIdMap] = createSectionState("bindingGetterIdMap", () => /* @__PURE__ */ new Map());
function getBindingGetterIdentifier(binding, getterSection) {
const section = getterSection || binding.section;
const idsMap = getBindingGetterIdMap(section);
let identifier = idsMap.get(binding);
if (!identifier) idsMap.set(binding, identifier = generateUidIdentifier(`${section.name ? `${section.name}__` : ""}${binding.originalName ?? binding.name}_getter`));
return identifier;
}
function getSignal(section, referencedBindings, name) {
if (referencedBindings && !Array.isArray(referencedBindings)) {
if (referencedBindings.type === 5) return getSignal(section, void 0);
if (referencedBindings.section !== section) {
const canonicalReference = getCanonicalBinding(referencedBindings);
if (canonicalReference !== referencedBindings) return getSignal(section, canonicalReference);
}
}
const signals = getSignals(section);
let signal = signals.get(referencedBindings);
if (!signal) {
const signalName = name ?? (referencedBindings ? getDebugNamesAsIdentifier(referencedBindings) : "setup");
const exportName = referencedBindings ? !Array.isArray(referencedBindings) && referencedBindings.section === section && (0, _marko_compiler_babel_utils.getProgram)().node.extra.exportNames.params.get(referencedBindings) : !section.parent && (0, _marko_compiler_babel_utils.getProgram)().node.extra.exportNames.setup;
signals.set(referencedBindings, signal = {
identifier: exportName ? _marko_compiler.types.identifier(exportName) : generateUidIdentifier(section.name ? `${section.name}__${signalName}` : signalName),
referencedBindings,
section,
values: [],
intersections: void 0,
forwards: void 0,
render: [],
effect: [],
hasHTMLEffect: false,
build: void 0,
export: !!exportName,
storesValue: !!(referencedBindings && (Array.isArray(referencedBindings) || referencedBindings.type === 0 || referencedBindings.type === 1 || referencedBindings.section !== section || referencedBindings.closureSections || referencedBindings.hoists || referencedBindings.localOf)),
forceStore: false,
inline: void 0,
extraArgs: void 0,
prependStatements: void 0,
buildAssignment: void 0
});
if (isOutputHTML()) return signal;
else if (!referencedBindings) signal.build = () => buildSignalFn(signal);
else if (Array.isArray(referencedBindings)) {
const meta = section.intersections.get(referencedBindings);
subscribe(meta.source || referencedBindings, signal);
if (meta.source) {
const sourceSignal = getSignal(section, meta.source);
forEach(referencedBindings, (member) => {
const memberSignal = getSignal(section, member);
const inline = member.type === 4 && !member.aliasOf && !member.propertyAliases.size && member.reads.size === 1 && sourceSignal.values.find((v) => v.signal === memberSignal);
if (inline) memberSignal.inline = inline;
else memberSignal.storesValue = memberSignal.forceStore = true;
});
}
signal.build = () => buildIntersection(section, referencedBindings, buildSignalFn(signal));
} else if (referencedBindings.section !== section && sectionUtil.has(referencedBindings.closureSections, section)) signal.build = () => {
const closure = referencedBindings;
const render = buildSignalFn(signal);
const closureSignalBuilder = getClosureSignalBuilder(section);
if (closureSignalBuilder && !isDynamicClosure(section, closure)) return closureSignalBuilder(closure, render);
return callRuntime("_closure_get", getClosureAccessorLiteral(closure), render, isInParentSection(closure, section) ? void 0 : _marko_compiler.types.arrowFunctionExpression([scopeIdentifier], getScopeExpression(section, closure.section)), isChangeableDynamicClosure(section, closure) ? _marko_compiler.types.stringLiteral(getResumeRegisterId(section, closure, "subscribe")) : void 0);
};
}
return signal;
}
function isChangeableDynamicClosure(section, closure) {
const { sources } = closure;
return !!sources && isDynamicClosure(section, closure) && (!sources.state || some(sources.state, hasResumableAssignment));
}
function initValue(binding, isLet = false) {
const section = binding.section;
const signal = getSignal(section, binding);
if (binding.hasLazyReads) signal.forceStore = true;
signal.build = () => {
if (isPureMemberForwarder(binding)) return;
const fn = buildSignalFn(signal);
if (!signal.forceStore && (isDirectAlias(binding) || !signal.storesValue && !someAlias(binding, aliasStoresValue, binding, true) || !signalHasWork(signal))) return fn;
return callRuntime(isLet ? signal.extraArgs ? "_let_change" : "_let" : "_const", getScopeAccessorLiteral(binding, true, isLet), fn);
};
binding.aliases.forEach(initAliasValue);
binding.propertyAliases.forEach(initAliasValue);
return signal;
}
function initAliasValue(alias) {
if (alias.type !== 5) initValue(alias);
}
function aliasStoresValue(alias, binding) {
return alias !== binding && getSignal(alias.section, alias).storesValue;
}
function signalHasWork(signal) {
if (signal.extraArgs || signal.forceStore || signal.render.length || signal.effect.length || signal.hasHTMLEffect || signal.values.length || signal.intersections) return true;
const binding = signal.referencedBindings;
if (binding) {
if (!Array.isArray(binding) && (binding.closureSections || binding.type === 0 || binding.section === signal.section && (binding.hoists || binding.aliases.size || hasNonConstantPropertyAlias(binding)))) return true;
} else if (signal.section.referencedClosures) return true;
return false;
}
function isPureMemberForwarder(binding) {
if (binding.property === void 0 || binding.reads.size || binding.exposed || binding.aliases.size || binding.assignments || isForSelectorValue(binding) || findSlot(binding)?.reason || getSignal(binding.section, binding).storesValue) return false;
return hasNonConstantPropertyAlias(binding);
}
function pushMemberForwards(signal, value, alias) {
if (isPureMemberForwarder(alias)) {
for (const [key, child] of alias.propertyAliases) if (child.type !== 5) pushMemberForwards(signal, toMemberExpression(_marko_compiler.types.cloneNode(value, true), key, alias.nullable), child);
} else pushForward(signal, getSignal(alias.section, alias), value);
}
function pushForward(signal, target, value) {
signal.forwards = push(signal.forwards, target);
signal.render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(target.identifier, [
scopeIdentifier,
value,
...getTranslatedExtraArgs(target)
])));
}
function buildIntersection(section, intersection, fn) {
const { source, id, returnedBy } = section.intersections.get(intersection);
if (source) return fn;
return callRuntime("_or", _marko_compiler.types.numericLiteral(id), fn, returnedBy || intersection.length > 2 ? _marko_compiler.types.numericLiteral(intersection.length - 1) : void 0, returnedBy && getScopeOffsetAccessorLiteral(returnedBy, true));
}
function buildSignalFn(signal) {
const section = signal.section;
const binding = signal.referencedBindings;
const isValue = binding && !Array.isArray(binding) && binding.section === section;
const assertsHoists = isValue && binding.hoists && !isOptimize();
if (isValue) {
for (const alias of binding.aliases) {
const aliasSignal = getSignal(alias.section, alias);
if (signalHasWork(aliasSignal)) {
let value = createScopeReadExpression(binding);
if (isRest(alias)) {
const aliasId = _marko_compiler.types.identifier(alias.name);
value = _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([getRestPattern(alias, aliasId, binding, true)], aliasId), [withRestFallback(alias, binding, value)]);
}
pushForward(signal, aliasSignal, value);
}
}
for (const [key, alias] of binding.propertyAliases) if (alias.type !== 5) pushMemberForwards(signal, toMemberExpression(createScopeReadExpression(binding), key, binding.nullable), alias);
if (assertsHoists) signal.render.push(_marko_compiler.types.expressionStatement(callRuntime("_assert_hoist", createScopeReadExpression(binding))));
}
for (const value of signal.values) {
if (value.signal.inline) continue;
signal.render.push(_marko_compiler.types.expressionStatement(signalHasWork(value.signal) ? _marko_compiler.types.callExpression(value.signal.identifier, [
scopeIdentifier,
...value.value ? [value.value] : [],
...getTranslatedExtraArgs(value.signal)
]) : withLeadingComment(value.value, getDebugNames(value.signal.referencedBindings))));
}
forEach(signal.intersections, (intersection) => {
pushScopeCall(signal.render, intersection.identifier);
});
if (isValue && binding.sources) {
let dynamicClosureArgs;
let dynamicClosureSignalIdentifier;
forEach(binding.closureSections, (closureSection) => {
if (isDynamicClosure(closureSection, binding)) {
if (!dynamicClosureArgs) {
dynamicClosureArgs = [];
dynamicClosureSignalIdentifier = generateUidIdentifier(signal.identifier.name + "__closure");
pushScopeCall(signal.render, dynamicClosureSignalIdentifier);
}
dynamicClosureArgs.push(getSignal(closureSection, binding).identifier);
} else pushScopeCall(signal.render, getSignal(closureSection, binding).identifier);
});
if (dynamicClosureSignalIdentifier) (signal.prependStatements ||= []).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(dynamicClosureSignalIdentifier, callRuntime("_closure", ...dynamicClosureArgs))]));
}
if (signal.effect.length) pushScopeCall(signal.render, getSignalEffectIdentifier(signal));
if (isValue && findSlot(binding)?.reason) signal.storesValue = true;
if (!signal.storesValue) {
const call = isValue && getOnlyCall(signal.render);
if (call && call.callee.type === "Identifier" && call.arguments.length === 2 && call.arguments[0] === scopeIdentifier && isOwnValueRead(call.arguments[1], binding)) return call.callee;
return _marko_compiler.types.arrowFunctionExpression(isValue ? [scopeIdentifier, getSignalValueIdentifier(signal)] : [scopeIdentifier], toOnlyExpressionOrBlock(signal.render));
}
return toScopeFn(signal.render);
}
function toScopeFn(render) {
const call = getOnlyCall(render);
if (call && call.arguments.length === 1 && call.arguments[0] === scopeIdentifier) {
if (call.callee.type === "MemberExpression" && call.callee.property.type === "Identifier" && call.callee.property.name === getAccessorProp().Owner) return call.callee.object;
return call.callee;
}
return _marko_compiler.types.arrowFunctionExpression([scopeIdentifier], _marko_compiler.types.blockStatement(render));
}
function getOnlyCall(render) {
if (render.length === 1) {
const [first] = render;
if (first.type === "ExpressionStatement" && first.expression.type === "CallExpression") return first.expression;
}
}
function pushScopeCall(render, callee) {
render.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(callee, [scopeIdentifier])));
}
function getSignalEffectIdentifier(signal) {
return _marko_compiler.types.identifier(`${signal.identifier.name}__script`);
}
const hasTranslatedExtraArgs = /* @__PURE__ */ new WeakSet();
const emptyExtraArgs = [];
function getTranslatedExtraArgs(signal) {
if (signal.extraArgs) {
if (!hasTranslatedExtraArgs.has(signal)) {
hasTranslatedExtraArgs.add(signal);
traverseReplace(signal, "extraArgs", replaceRenderNode);
}
return signal.extraArgs;
}
return emptyExtraArgs;
}
function getSignalValueIdentifier(signal) {
const canonicalBinding = getCanonicalBinding(signal.referencedBindings);
return _marko_compiler.types.identifier(canonicalBinding.name);
}
function isOwnValueRead(node, binding) {
const extra = node.extra;
const read = extra?.read;
return !!read && !extra.assignment && read.binding === binding && read.props === void 0 && !read.getter?.invoked;
}
function subscribe(references, intersection) {
if (references) forEach(references, (binding) => {
if (binding.type !== 5) {
const source = getCanonicalBinding(binding);
const providerSignal = getSignal(intersection.section, source);
providerSignal.storesValue = true;
providerSignal.intersections = push(providerSignal.intersections, intersection);
}
});
}
function trimEmptyArgs(args) {
const len = args.length;
let finalLen = void 0;
for (let i = len; i--;) {
const arg = args[i];
if (!arg) {
args[i] = _marko_compiler.types.numericLiteral(0);
continue;
}
if (_marko_compiler.types.isNullLiteral(arg) || _marko_compiler.types.isUnaryExpression(arg) && arg.operator === "void") {
args[i] = _marko_compiler.types.numericLiteral(0);
continue;
}
if (_marko_compiler.types.isArrowFunctionExpression(arg) && _marko_compiler.types.isBlockStatement(arg.body)) {
const body = arg.body.body;
if (body.length === 0) {
args[i] = _marko_compiler.types.numericLiteral(0);
continue;
}
if (body.length === 1 && _marko_compiler.types.isExpressionStatement(body[0])) arg.body = body[0].expression;
}
if (finalLen === void 0) finalLen = i + 1;
}
args.length = finalLen || 0;
return args;
}
function addStatement(type, targetSection, referencedBindings, statement, isPure) {
const signal = getSignal(targetSection, referencedBindings);
const statements = signal[type] ??= [];
if (Array.isArray(statement)) statements.push(...statement);
else statements.push(_marko_compiler.types.isExpression(statement) ? _marko_compiler.types.expressionStatement(statement) : statement);
if (!isPure || type === "effect") signal.storesValue = true;
}
function addTagStatement(tag, statement) {
if (isOutputHTML()) tag.insertBefore(statement);
else addStatement("render", getSection(tag), getReferencedBindings(tag.node.attributes[0]?.value.extra), statement);
tag.remove();
}
function addValue(targetSection, referencedBindings, signal, value) {
const parentSignal = getSignal(targetSection, referencedBindings);
parentSignal.values.push({
signal,
value
});
if (_marko_compiler.types.isFunction(value) && value.extra && getReferencedBindingsInFunction(value.extra)) parentSignal.storesValue = true;
}
function buildResumeRegisterKey(section, referencedBindings, type) {
let name = "";
if (referencedBindings) {
if (typeof referencedBindings === "string") name += `*${referencedBindings}`;
else name = reduce(referencedBindings, (name, binding) => appendBindingKey(name, binding, section), name);
}
return `${section.id}${name}${type ? "/" + type : ""}`;
}
function getResumeRegisterId(section, referencedBindings, type) {
const { markoOpts, opts: { filename } } = (0, _marko_compiler_babel_utils.getFile)();
const key = buildResumeRegisterKey(section, referencedBindings, type);
return (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, filename, key);
}
function writeSignals(section) {
const seen = /* @__PURE__ */ new Set();
const written = /* @__PURE__ */ new Set();
writeGetters(section);
for (const signal of getSignals(section).values()) writeSignal(signal);
function writeSignal(signal) {
if (seen.has(signal)) return;
seen.add(signal);
for (const value of signal.values) {
writeSignal(value.signal);
traverseReplace(value, "value", replaceRenderNode);
}
forEach(signal.intersections, writeSignal);
let effectDeclarator;
if (signal.effect.length) {
traverseReplace(signal, "effect", replaceEffectNode);
const effectIdentifier = getSignalEffectIdentifier(signal);
const effectFn = _marko_compiler.types.arrowFunctionExpression([scopeIdentifier], toOnlyExpressionOrBlock(signal.effect));
effectDeclarator = _marko_compiler.types.variableDeclarator(effectIdentifier, callRuntime("_script", _marko_compiler.types.stringLiteral(getResumeRegisterId(section, signal.referencedBindings)), effectFn));
}
let signalDeclaration;
if (signal.build) {
let value = signal.build();
const buildsEagerForward = _marko_compiler.types.isIdentifier(value) || _marko_compiler.types.isCallExpression(value) && _marko_compiler.types.isIdentifier(value.arguments.at(-1));
if (!value || !signal.register && !signal.referenced && _marko_compiler.types.isFunction(value) && _marko_compiler.types.isBlockStatement(value.body) && !value.body.body.length) return;
if (_marko_compiler.types.isCallExpression(value)) trimEmptyArgs(value.arguments);
if (signal.register) value = callRuntime("_var_resume", _marko_compiler.types.stringLiteral(getResumeRegisterId(section, signal.referencedBindings, "var")), value);
if (buildsEagerForward) forEach(signal.forwards, writeSignal);
const signalDeclarator = _marko_compiler.types.variableDeclarator(signal.identifier, value);
signalDeclaration = !section.parent && !signal.referencedBindings && (_marko_compiler.types.isFunctionExpression(value) || _marko_compiler.types.isArrowFunctionExpression(value)) ? _marko_compiler.types.functionDeclaration(signal.identifier, value.params, _marko_compiler.types.isExpression(value.body) ? _marko_compiler.types.blockStatement([_marko_compiler.types.expressionStatement(value.body)]) : value.body) : _marko_compiler.types.variableDeclaration("const", [signalDeclarator]);
if (signal.export) signalDeclaration = _marko_compiler.types.exportNamedDeclaration(signalDeclaration);
}
traverseReplace(signal, "render", replaceRenderNode, signal);
const signalStatements = signal.prependStatements || [];
if (effectDeclarator) signalStatements.push(_marko_compiler.types.variableDeclaration("const", [effectDeclarator]));
if (signalDeclaration) signalStatements.push(signalDeclaration);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(...signalStatements);
written.add(signal);
}
return written;
}
function writeGetters(section) {
forEach(section.bindings, (binding) => {
for (const [hoistSection, hasReference] of binding.getters) {
const getterIdentifier = getBindingGetterIdentifier(binding, hoistSection);
const accessors = [getScopeAccessorLiteral(binding, true)];
if (hoistSection) forEachAncestorSection(binding.section, hoistSection, pushInstancesAccessor, accessors);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(getterIdentifier, hoistSection ? hasReference ? callRuntime("_hoist_resume", _marko_compiler.types.stringLiteral(getResumeRegisterId(hoistSection, binding, "hoist")), ...accessors) : callRuntime("_hoist", ...accessors) : callRuntime("_el", _marko_compiler.types.stringLiteral(getResumeRegisterId(section, binding)), ...accessors))]));
}
});
}
function pushInstancesAccessor(section, accessors) {
const instancesAccessor = getSectionInstancesAccessorLiteral(section);
const { branch } = section;
accessors.push(branch?.index !== void 0 && section.parent.children.some((child) => child !== section && child.branch?.nodeBinding === branch.nodeBinding) ? _marko_compiler.types.arrayExpression([
instancesAccessor,
_marko_compiler.types.stringLiteral(getAccessorPrefix().ConditionalRenderer + getScopeAccessor(branch.nodeBinding)),
_marko_compiler.types.numericLiteral(branch.index)
]) : instancesAccessor);
}
function writeRegisteredFns() {
const registeredFns = getRegisteredFns();
const statements = [];
for (const registeredFn of registeredFns) {
let fn;
if (registeredFn.referencedBindings || registeredFn.referencesScope || registeredFn.referencedLocals) {
let params;
let prologue;
if (registeredFn.referencedLocals) {
params = [localsIdentifier];
if (registeredFn.referencedBindings || registeredFn.referencesScope) prologue = [_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(scopeIdentifier, _marko_compiler.types.memberExpression(localsIdentifier, _marko_compiler.types.identifier(getAccessorProp().Owner)))])];
} else params = [scopeIdentifier];
const body = toReturnedFunction(registeredFn.node, prologue);
fn = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(registeredFn.id), _marko_compiler.types.arrowFunctionExpression(params, body.length === 1 && body[0].type === "ReturnStatement" ? body[0].argument : _marko_compiler.types.blockStatement(body)))]);
} else if (registeredFn.node.type === "FunctionDeclaration" && registeredFn.node.id?.name === registeredFn.id) fn = registeredFn.node;
else fn = _marko_compiler.types.functionDeclaration(_marko_compiler.types.identifier(registeredFn.id), registeredFn.node.params, registeredFn.node.body.type === "BlockStatement" ? registeredFn.node.body : _marko_compiler.types.blockStatement([_marko_compiler.types.returnStatement(registeredFn.node.body)]), registeredFn.node.generator, registeredFn.node.async);
statements.push(fn);
}
for (const registeredFn of registeredFns) statements.push(_marko_compiler.types.expressionStatement(registerRuntimeValue(registeredFn.registerId, _marko_compiler.types.identifier(registeredFn.id))));
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(...statements);
}
function toReturnedFunction(rawFn, prologue) {
const fn = simplifyFunction(rawFn);
if (prologue) {
if (fn.body.type !== "BlockStatement") fn.body = _marko_compiler.types.blockStatement([_marko_compiler.types.returnStatement(fn.body)]);
fn.body.body.unshift(...prologue);
}
return fn.type === "FunctionDeclaration" ? [fn, _marko_compiler.types.returnStatement(fn.id)] : [_marko_compiler.types.returnStatement(fn)];
}
function addHTMLEffectCall(section, referencedBindings) {
const signal = getSignal(section, referencedBindings);
signal.hasHTMLEffect = signal.storesValue = true;
}
function writeHTMLResumeStatements(path) {
const bodyPath = flushInto(path);
const section = getSectionForBody(bodyPath);
if (!section) return;
const body = bodyPath.node.body;
const allSignals = Array.from(getSignals(section).values());
const scopeIdIdentifier = getScopeIdIdentifier(section);
const markerGuard = getWriteGuardForAny(section, getNodeReasons(section), true);
const sectionReason = section.reason;
forEach(section.referencedClosures, (closure) => {
if (closure.sources && closure.type !== 5) {
if (isDynamicClosure(section, closure)) {
const closureSignal = getSignal(closure.section, closure);
let identifier = htmlDynamicClosureInstancesIdentifier.get(closureSignal);
if (!identifier) {
htmlDynamicClosureInstancesIdentifier.set(closureSignal, identifier = generateUidIdentifier(closureSignal.identifier.name + "__closures"));
getHTMLSectionStatements(closure.section).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(identifier, _marko_compiler.types.newExpression(_marko_compiler.types.identifier("Set"), []))]));
writeSlot(findSlot(closure, 2), identifier);
}
const closureIndex = getDynamicClosureIndex(closure, section);
if (closureIndex) writeSlot(findSlot(closure, 3, section), _marko_compiler.types.numericLiteral(closureIndex));
const closureScopesReason = findSlot(closure, 2)?.reason;
const subscribeArg = isConditionalReason(closureScopesReason) && !isSameReason(closureScopesReason, sectionReason) ? getExprIfWritten(closure.section, closureScopesReason, identifier) : identifier;
const changeable = isChangeableDynamicClosure(section, closure);
addWriteScopeBuilder(section, (expr) => {
const resumeId = changeable && _marko_compiler.types.stringLiteral(getResumeRegisterId(section, closure, "subscribe"));
return callRuntime("_subscribe", subscribeArg, expr, resumeId, resumeId && markerGuard);
});
}
}
});
for (let i = allSignals.length; i--;) if (allSignals[i].hasHTMLEffect) {
const signalRefs = allSignals[i].referencedBindings;
body.push(_marko_compiler.types.expressionStatement(callRuntime("_script", scopeIdIdentifier, _marko_compiler.types.stringLiteral(getResumeRegisterId(section, signalRefs)), markerGuard)));
}
const debug = !isOptimize();
const writeScopeBuilder = getSectionWriteScopeBuilder(section);
const pendingProperties = getScopeProperties(section);
const scopeProperties = [];
const ifWritten = (reason, expr) => {
if (isSameReason(sectionReason, reason)) return expr;
return getExprIfWritten(section, reason, expr);
};
let debugVars;
const writeBinding = (binding) => {
const reason = getWriteReason(binding);
if (!reason) return;
const accessor = getScopeAccessor(binding);
pendingProperties.delete(accessor);
scopeProperties.push(toObjectProperty(accessor, ifWritten(reason, getDeclaredBindingExpression(binding))));
if (debug) {
const { root, access } = getDebugAccess(binding, false, toAccess);
const locExpr = root.loc && _marko_compiler.types.stringLiteral(getDebugLoc(root.loc));
(debugVars ||= []).push(toObjectProperty(getScopeAccessor(binding), root !== binding ? _marko_compiler.types.arrayExpression(locExpr ? [_marko_compiler.types.stringLiteral(root.name + access), locExpr] : [_marko_compiler.types.stringLiteral(root.name + access)]) : locExpr || _marko_compiler.types.numericLiteral(0)));
}
};
forEach(section.bindings, (binding) => {
if (binding.type !== 0) writeBinding(binding);
});
if (section.parent) {
const ownerAccessor = getAccessorProp().Owner;
const ownerReason = findSectionSlot(section, 7)?.reason;
if (ownerReason) {
pendingProperties.delete(ownerAccessor);
if (!getOwnerResumedByMarker(section)) scopeProperties.push(toObjectProperty(ownerAccessor, ifWritten(ownerReason, callRuntime("_scope_with_id", getScopeIdIdentifier(section.parent)))));
}
}
for (const [key, { expression, reason }] of pendingProperties) scopeProperties.push(toObjectProperty(key, ifWritten(reason, expression)));
if (sectionReason) {
for (const prop of scopeProperties) if (prop.key.type === "Identifier" && prop.value.type === "Identifier" && prop.key.name === prop.value.name) prop.shorthand = true;
const writeScopeArgs = [scopeIdIdentifier, _marko_compiler.types.objectExpression(scopeProperties)];
if (debug) {
writeScopeArgs.push(_marko_compiler.types.stringLiteral((0, _marko_compiler_babel_utils.getFile)().opts.filenameRelative), section.loc && section.loc.start.line != null ? _marko_compiler.types.stringLiteral(getDebugLoc(section.loc)) : _marko_compiler.types.numericLiteral(0));
for (const [accessor, varLoc] of getSectionDebugVars(section)) (debugVars ||= []).push(toObjectProperty(accessor, _marko_compiler.types.valueToNode(varLoc)));
if (debugVars) writeScopeArgs.push(_marko_compiler.types.objectExpression(debugVars));
}
const writeCall = writeScopeBuilder ? writeScopeBuilder(callRuntime("_scope", ...writeScopeArgs)) : callRuntime("_scope", ...writeScopeArgs);
body.push(_marko_compiler.types.expressionStatement(getExprIfWritten(section, sectionReason, writeCall)));
}
if (!isOptionalBranch(section) && (section.hasAbortSignal || !!section.referencedClosures || sectionReason && some(section.bindings, isLetBinding)) && markerGuard) {
const call = callRuntime("_resume_branch", scopeIdIdentifier);
const link = section.hasAbortSignal ? call : getExprIfWritten(section, sectionReason, call);
if (link) body.push(_marko_compiler.types.expressionStatement(markerGuard.type === "NumericLiteral" ? link : _marko_compiler.types.logicalExpression("||", markerGuard, link)));
}
const additionalStatements = getHTMLSectionStatements(section);
if (body.length || additionalStatements.length) body.unshift(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(scopeIdIdentifier, callRuntime("_scope_id"))]), ...additionalStatements);
if (debug) forEach(section.bindings, (binding) => {
if (binding.hoists && binding.type !== 0) body.push(_marko_compiler.types.expressionStatement(callRuntime("_assert_hoist", _marko_compiler.types.identifier(binding.name))));
});
const returnIdentifier = getSectionReturnValueIdentifier(section);
if (returnIdentifier !== void 0) body.push(_marko_compiler.types.returnStatement(returnIdentifier));
}
function getSetup(section) {
return getSignals(section).get(void 0);
}
function replaceRenderNode(node, signal) {
return replaceAssignedNode(node) || replaceBindingReadNode$1(node, signal) || replaceRegisteredFunctionNode$1(node);
}
function replaceEffectNode(node) {
return replaceAssignedNode(node) || replaceBindingReadNode$1(node);
}
function replaceBindingReadNode$1(node, signal) {
switch (node.type) {
case "Identifier":
case "MemberExpression":
case "OptionalMemberExpression": return getReadReplacement(node, signal);
case "CallExpression":
case "OptionalCallExpression": {
const { extra } = node.callee;
if (extra?.read) {
const { binding, getter } = extra.read;
if (binding.type === 0 && !getter) {
const replacement = createScopeReadExpression(binding, extra.section);
return isOptimize() ? replacement : callRuntime("_el_read", replacement);
} else if (getter?.hoisted) node.callee = _marko_compiler.types.callExpression(getBindingGetterIdentifier(binding, getter.hoisted), [getScopeExpression(extra.section, getter.hoisted)]);
}
break;
}
}
}
const updateExpressions = /* @__PURE__ */ new WeakSet();
function replaceAssignedNode(node) {
switch (node.type) {
case "ExpressionStatement":
if (node.expression.type === "BinaryExpression" && updateExpressions.delete(node.expression)) node.expression = node.expression.left;
if (node.expression.type === "CallExpression" && updateExpressions.delete(node.expression)) {
node.expression.callee = node.expression.arguments[0];
node.expression.arguments = [node.expression.arguments[1]];
}
break;
case "UpdateExpression": {
const { extra } = node.argument;
if (isAssignedBindingExtra(extra)) {
let builtAssignment = getBuildAssignment(extra)?.(extra.section, _marko_compiler.types.binaryExpression(node.operator === "++" ? "+" : "-", _marko_compiler.types.unaryExpression("+", createScopeReadExpression(extra.assignment, extra.section)), _marko_compiler.types.numericLiteral(1)));
if (builtAssignment) {
if (!node.prefix) {
builtAssignment = _marko_compiler.types.binaryExpression(node.operator === "++" ? "-" : "+", builtAssignment, _marko_compiler.types.numericLiteral(1));
updateExpressions.add(builtAssignment);
}
return builtAssignment;
}
}
break;
}
case "AssignmentExpression": switch (node.left.type) {
case "Identifier": {
const { extra } = node.left;
if (isAssignedBindingExtra(extra)) {
const { operator } = node;
const shortCircuits = operator === "||=" || operator === "&&=" || operator === "??=";
const readAssigned = () => createScopeReadExpression(extra.assignment, extra.section);
const builtAssignment = getBuildAssignment(extra)?.(extra.section, operator === "=" || shortCircuits ? node.right : _marko_compiler.types.binaryExpression(operator.slice(0, -1), readAssigned(), node.right));
if (builtAssignment) return shortCircuits ? _marko_compiler.types.logicalExpression(operator.slice(0, -1), readAssigned(), builtAssignment) : builtAssignment;
}
return extra?.assignment && withLeadingComment(node.right, getDebugName(extra.assignment));
}
case "ArrayPattern":
case "ObjectPattern": {
let params;
let assignments;
forEachIdentifier(node.left, (id) => {
const { extra } = id;
if (isAssignedBindingExtra(extra)) {
const buildAssignment = getBuildAssignment(extra);
if (buildAssignment) {
const uid = generateUid(id.name);
const builtAssignment = buildAssignment(extra.section, _marko_compiler.types.identifier(uid));
if (builtAssignment) {
id.name = uid;
(params ||= []).push(_marko_compiler.types.identifier(uid));
(assignments ||= []).push(builtAssignment);
return;
}
}
}
if (extra?.assignment) (params ||= []).push(_marko_compiler.types.identifier(id.name));
});
if (assignments || params) {
const resultId = generateUid("result");
return _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.identifier(resultId), ...params || []], _marko_compiler.types.sequenceExpression([
_marko_compiler.types.assignmentExpression("=", node.left, _marko_compiler.types.identifier(resultId)),
...assignments || [],
_marko_compiler.types.identifier(resultId)
])), [node.right]);
}
break;
}
}
}
}
function getChangeHandlerRead(binding, section) {
return binding.pruned && binding.property !== void 0 && binding.aliasOf ? toMemberExpression(getChangeHandlerRead(binding.aliasOf, section), binding.property, false) : createScopeReadExpression(binding, section);
}
function getBuildAssignment(extra) {
const { assignmentTo, assignment } = extra;
if (assignmentTo) return (section, value) => {
const replacement = callRuntime("_call", getChangeHandlerRead(assignmentTo, section), value);
updateExpressions.add(replacement);
return replacement;
};
return getSignal(assignment.section, assignment).buildAssignment;
}
const [getRegisteredFns] = createProgramState(() => []);
function replaceRegisteredFunctionNode$1(node) {
switch (node.type) {
case "ClassMethod":
case "ClassPrivateMethod":
case "ObjectMethod": {
const replacement = registerFnExpression(node);
return replacement && replaceMethodNode(node, replacement);
}
case "ArrowFunctionExpression":
case "FunctionExpression": return registerFnExpression(node);
case "FunctionDeclaration": {
const replacement = registerFnExpression(node);
return replacement && _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(node.id, replacement)]);
}
}
}
function registerFnExpression(node) {
const { extra } = node;
if (isRegisteredFnExtra(extra)) {
const id = extra.name;
const referencesScope = extra.referencesScope;
const referencedBindings = getReferencedBindingsInFunction(extra);
const referencedLocals = extra.referencedLocalBindingsInFunction;
getRegisteredFns().push({
id,
node,
registerId: extra.registerId,
section: extra.section,
referencesScope,
referencedBindings,
referencedLocals
});
if (referencedLocals) {
const properties = [];
if (referencesScope || referencedBindings) properties.push(_marko_compiler.types.objectProperty(_marko_compiler.types.identifier(getAccessorProp().Owner), scopeIdentifier));
forEach(referencedLocals, (binding) => {
properties.push(toObjectProperty(getLocalsScopeAccessor(binding), getDeclaredBindingExpression(binding)));
});
return _marko_compiler.types.callExpression(_marko_compiler.types.identifier(id), [_marko_compiler.types.objectExpression(properties)]);
} else if (referencesScope || referencedBindings) return _marko_compiler.types.callExpression(_marko_compiler.types.identifier(id), [scopeIdentifier]);
else return _marko_compiler.types.identifier(id);
}
}
function appendBindingKey(name, binding, section) {
return `${name}_${binding.name}#${binding.section === section ? "" : binding.section.id + ":"}${binding.id}`;
}
function isLetBinding(binding) {
return binding.type === 1;
}
function getDebugLoc({ start }) {
return `${start.line}:${start.column + 1}`;
}
//#endregion
//#region src/translator/util/tag-import.ts
const triggerRegExp = /\s*([\w-]+)\s*([^?|]+?)?\s*(?:\?([^|]*?))?\s*(?:\||$)/g;
const derivedImports = /* @__PURE__ */ new WeakSet();
function importOrSelfReferenceName(file, request, name, nameHint) {
if (isCircularRequest(file, request)) return _marko_compiler.types.identifier(name);
return (0, _marko_compiler_babel_utils.importNamed)(file, request, name, nameHint);
}
function isCircularRequest(file, request) {
const { filename } = file.opts;
return request === filename || request[0] === "." && path.default.resolve(filename, "..", request) === filename;
}
function trackTagImport(tagImport) {
const tags = (0, _marko_compiler_babel_utils.getFile)().metadata.marko.tags;
if (!tags.includes(tagImport)) tags.push(tagImport);
}
function getImportFacts(importDecl) {
const { node } = importDecl;
const extra = node.extra ??= {};
if (!derivedImports.has(node)) {
derivedImports.add(node);
const tagImport = (0, _marko_compiler_babel_utils.resolveTagImport)(importDecl, node.source.value);
if (tagImport) extra.tagImport = tagImport;
const loadAttrPath = getLoadAttr(importDecl);
const loadImport = loadAttrPath && getLoadImportConfig(loadAttrPath.get("value"));
if (loadImport && getMarkoOpts().linkAssets) extra.loadImport = loadImport;
}
return extra;
}
function getLoadAttr(importDecl) {
return importDecl.node.attributes?.length ? importDecl.get("attributes").find((p) => getLiteralName(p.node.key) === "load") : void 0;
}
function getLoadImportConfig(attrValue) {
const raw = attrValue.node.value;
if (raw === "render") return { render: true };
const triggers = [];
for (const match of raw.matchAll(triggerRegExp)) {
const type = parseTriggerType(match[1]);
const selector = match[2];
const query = match[3];
if (!type) throw attrValue.buildCodeFrameError(`Unknown trigger type "${match[1]}". Supported triggers are "visible", "idle", "media", and "on*".`);
if (type === "render") throw attrValue.buildCodeFrameError("The \"render\" trigger must be used alone.");
if (type === "idle") {
if (selector) throw attrValue.buildCodeFrameError(`Selector is not supported for the "idle" trigger.`);
} else if (!selector) throw attrValue.buildCodeFrameError(type === "media" ? `A media query is required for the "media" trigger. (e.g. "media(max-width:768px)")` : `A selector is required for the "${type}" trigger. (e.g. "${type}.my-element")`);
const trigger = selector ? {
type,
selector
} : { type };
if (query) {
const params = new URLSearchParams(query);
switch (type) {
case "visible": {
let rootMargin;
for (const [key, value] of params) {
if (key !== "rootMargin") throw attrValue.buildCodeFrameError(`Unknown param "${key}" for the "visible" trigger. Supported params: "rootMargin".`);
rootMargin = value;
}
if (rootMargin) trigger.options = { rootMargin };
break;
}
case "idle": {
let timeout;
for (const [key, value] of params) {
if (key !== "timeout") throw attrValue.buildCodeFrameError(`Unknown param "${key}" for the "idle" trigger. Supported params: "timeout".`);
timeout = Number(value);
}
if (timeout) trigger.options = { timeout };
break;
}
default: throw attrValue.buildCodeFrameError(`Params are not supported for the "${type}" trigger.`);
}
}
triggers.push(trigger);
}
if (!triggers.length) throw attrValue.buildCodeFrameError("The \"load\" attribute requires \"render\" or at least one trigger (e.g. \"visible.my-element\").");
return {
render: false,
triggers
};
}
function parseTriggerType(type) {
switch (type) {
case "idle":
case "media":
case "render":
case "visible": return type;
default: return isEventHandler(type) ? `on-${getEventType(type)}` : void 0;
}
}
//#endregion
//#region src/translator/util/tag-name-type.ts
const kTagNameDynamic = Symbol("tag name dynamic");
const MARKO_FILE_REG = /^<.*>$|\.marko$/;
const TAG_NAME_IDENTIFIER_REG$1 = /^[A-Z][a-zA-Z0-9_$]*$/;
function analyzeTagNameType(tag) {
const extra = tag.node.extra ??= {};
if (extra.tagNameType === void 0) {
const name = tag.get("name");
if (name.isStringLiteral()) {
extra.tagNameType = name.node.value[0] === "@" ? 3 : (0, _marko_compiler_babel_utils.isNativeTag)(tag) ? 0 : 1;
extra.tagNameNullable = extra[kTagNameDynamic] = false;
} else if (name.isTemplateLiteral() && name.node.quasis.length === 1) {
extra.tagNameType = 0;
extra.tagNameNullable = extra[kTagNameDynamic] = false;
} else if (name.isIdentifier()) {
analyzeExpressionTagName(name, extra);
extra[kTagNameDynamic] = !extra.tagNameImported;
} else {
analyzeExpressionTagName(name, extra);
extra[kTagNameDynamic] = true;
}
if (!extra[kTagNameDynamic] && extra.tagNameType === 1 && !isCoreTag(tag)) {
const childFile = (0, _marko_compiler_babel_utils.loadFileForTag)(tag);
if ((0, _marko_compiler_babel_utils.getTagDef)(tag)?.renderer || childFile?.ast.program.extra.featureType === "class") {
extra.tagNameType = 2;
extra[kTagNameDynamic] = true;
extra.featureType = "class";
if (childFile?.ast.program.extra?.hydratesTags) (0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
} else if (!childFile) {
extra.tagNameType = 2;
extra[kTagNameDynamic] = true;
const tagName = name.node.value;
extra.tagNameUnresolved = !(TAG_NAME_IDENTIFIER_REG$1.test(tagName) && tag.scope.hasBinding(tagName));
} else if (childFile !== (0, _marko_compiler_babel_utils.getFile)() && isAnalyzing(childFile)) {
extra.tagNameType = 2;
extra[kTagNameDynamic] = true;
}
}
}
return extra[kTagNameDynamic] ? 2 : extra.tagNameType;
}
function analyzeExpressionTagName(name, extra) {
const pending = [name];
const seen = /* @__PURE__ */ new Set();
let path;
let type;
let nullable = false;
let tagNameImported;
let tagNameLoad;
let tagNameTemplates = [];
while ((path = pending.pop()) && type !== 2) {
if (seen.has(path.node)) continue;
seen.add(path.node);
if (path.isConditionalExpression()) {
pending.push(path.get("consequent"));
if (path.node.alternate) pending.push(path.get("alternate"));
} else if (path.isLogicalExpression()) {
if (path.node.operator === "&&") nullable = true;
else pending.push(path.get("left"));
pending.push(path.get("right"));
} else if (path.isAssignmentExpression()) pending.push(path.get("right"));
else if (path.isBinaryExpression()) type = path.node.operator !== "+" || type === void 0 || type === 0 ? 0 : 2;
else if (path.isStringLiteral() || path.isTemplateLiteral()) type = type === void 0 || type === 0 ? 0 : 2;
else if (path.isNullLiteral()) nullable = true;
else if (path.isIdentifier()) {
if (path.node.name === "undefined") {
nullable = true;
continue;
}
const binding = path.scope.getBinding(path.node.name);
if (!binding) {
type = 2;
continue;
}
if (binding.kind === "module") {
const declPath = binding.path.parentPath;
const decl = declPath.node;
if (MARKO_FILE_REG.test(decl.source.value) && decl.specifiers.some((it) => _marko_compiler.types.isImportDefaultSpecifier(it))) {
const { tagImport, loadImport } = getImportFacts(declPath);
const resolvedImport = tagImport;
if (tagNameTemplates) {
const childFile = (0, _marko_compiler_babel_utils.loadFileForImport)((0, _marko_compiler_babel_utils.getFile)(), resolvedImport);
const childExtra = childFile?.ast.program.extra;
if (!childExtra || isAnalyzing(childFile)) tagNameTemplates = void 0;
else if (!tagNameTemplates.includes(childExtra)) tagNameTemplates.push(childExtra);
}
if (type === void 0) {
type = 1;
tagNameImported = resolvedImport;
tagNameLoad = loadImport;
} else if (type === 0) {
type = 2;
tagNameImported = void 0;
} else if (tagNameImported !== resolvedImport) tagNameImported = void 0;
} else type = 2;
continue;
}
const bindingTag = binding.path;
if (bindingTag.isMarkoTag() && binding.kind === "local") {
const bindingTagName = bindingTag.get("name").node.value;
if (bindingTagName === "const") {
pending.push(bindingTag.get("attributes")[0].get("value"));
continue;
}
if (bindingTagName === "let") {
type = 2;
continue;
}
}
type = 2;
} else type = 2;
}
extra.tagNameType = type ?? 2;
extra.tagNameNullable = nullable;
if (type === 1) {
extra.tagNameTemplates = tagNameTemplates;
if (tagNameImported && !nullable) {
extra.tagNameImported = tagNameImported;
extra.tagNameLoad = tagNameLoad;
}
}
}
function getTagRelativePath(tag) {
const { node } = tag;
const file = (0, _marko_compiler_babel_utils.getFile)();
let relativePath;
if (_marko_compiler.types.isStringLiteral(node.name)) {
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
const template = node.extra?.featureType === "class" && tagDef?.renderer || (0, _marko_compiler_babel_utils.getTagTemplate)(tag);
relativePath = template && (0, _marko_compiler_babel_utils.resolveRelativePath)(file, template, tagDef);
} else if (node.extra?.tagNameImported) relativePath = node.extra.tagNameImported;
if (!relativePath) throw tagNotFoundError(tag);
return relativePath;
}
const staticHint = "To declare module level JavaScript, prefix the statement with `static`.";
const knownWrongTags = /* @__PURE__ */ new Map([
["slot", "To render content passed to this tag, use a [dynamic tag](https://markojs.com/docs/reference/language#dynamic-tags): `<${input.content}/>`."],
["state", "Reactive state is declared with the [`<let>` tag](https://markojs.com/docs/reference/core-tag#let): `<let/name=initialValue>`."],
["fragment", "Marko templates and tag bodies may have multiple root nodes; no fragment wrapper is needed."],
["async", staticHint],
["class", staticHint],
["declare", staticHint],
["enum", staticHint],
["function", staticHint],
["interface", staticHint],
["type", staticHint]
]);
/**
* A known wrong tag that resolves to nothing, eg `interface P { id: number }`,
* whose body lands in attribute position before tag resolution would run.
*/
function isUnresolvedKnownWrongTag(tag) {
const tagName = getTagName(tag);
return !!tagName && knownWrongTags.has(tagName) && !(0, _marko_compiler_babel_utils.getTagDef)(tag);
}
function tagNotFoundError(tag) {
const tagName = getTagName(tag);
if (tagName && tag.scope.hasBinding(tagName)) return tag.get("name").buildCodeFrameError(`Local variables must be in a [dynamic tag](https://markojs.com/docs/reference/language#dynamic-tags) unless they are PascalCase. Use \`<\${${tagName}}/>\` or rename to \`${tagName.charAt(0).toUpperCase() + tagName.slice(1)}\`.`);
let didYouMean = "";
const knownWrongTagHint = tagName && knownWrongTags.get(tagName);
const proseText = tagName && getProseText(tag);
if (knownWrongTagHint) didYouMean = ` ${knownWrongTagHint}`;
else if (proseText) didYouMean = ` If this line is meant to be text, prefix it with \`--\` (e.g. \`-- ${proseText}\`) or wrap it in an element such as \`<p>${proseText}</p>\`.`;
else if (tagName) didYouMean = getSimilarTagHint(tagName);
return tag.get("name").buildCodeFrameError(`Unable to find entry point for [custom tag](https://markojs.com/docs/reference/custom-tag#relative-custom-tags) \`<${tagName ?? getTagNameHint(tag.node)}>\`.${didYouMean}`);
}
const wordReg = /^[A-Za-z]+$/;
function getProseText(tag) {
const { node } = tag;
const tagName = getTagName(tag);
if (!tagName || !wordReg.test(tagName) || node.var || node.body.params.length || node.body.body.length || !node.attributes.length || !isConciseModeTag(node)) return;
return collectProseWords(node, tagName);
}
function isConciseModeTag(node) {
const tagLoc = node.loc;
const nameLoc = node.name.loc;
if (!tagLoc || !nameLoc) return false;
return tagLoc.start.line === nameLoc.start.line && tagLoc.start.column === nameLoc.start.column;
}
function collectProseWords(node, tagName) {
let text = tagName;
for (const attr of node.attributes) {
if (attr.type !== "MarkoAttribute" || attr.default || !wordReg.test(attr.name) || attr.value.type !== "BooleanLiteral" || attr.value.value !== true) return;
text += " " + attr.name;
}
return text;
}
function getSimilarTagHint(tagName) {
const lookup = (0, _marko_compiler_babel_utils.getTaglibLookup)((0, _marko_compiler_babel_utils.getFile)());
if (lookup.getTag(tagName)) return "";
const lowerTagName = tagName.toLowerCase();
let closestTag;
let closestDistance = 4;
for (const name in lookup.merged.tags) {
const lengthDelta = Math.abs(name.length - tagName.length);
if (lengthDelta < closestDistance) {
if (!lengthDelta && name.toLowerCase() === lowerTagName) return ` Tag names are case-sensitive: did you mean \`<${name}>\`?`;
const nameDistance = (0, fastest_levenshtein.distance)(tagName, name);
if (nameDistance < closestDistance) {
closestTag = name;
closestDistance = nameDistance;
}
}
}
return closestTag ? ` Did you mean \`<${closestTag}>\`?` : "";
}
//#endregion
//#region src/translator/util/tag-facts.ts
const noContentFacts = { content: null };
const coreTagFacts = {
attrs: noContentFacts,
class: noContentFacts,
client: noContentFacts,
const: noContentFacts,
debug: noContentFacts,
define: noContentFacts,
effect: noContentFacts,
export: noContentFacts,
id: noContentFacts,
import: noContentFacts,
let: noContentFacts,
lifecycle: noContentFacts,
log: noContentFacts,
return: noContentFacts,
script: noContentFacts,
server: noContentFacts,
static: noContentFacts,
if: {
content: 1,
controlFlow: true
},
"else-if": {
content: null,
controlFlow: true
},
else: {
content: null,
controlFlow: true
},
for: {
content: 1,
controlFlow: true
},
await: {
content: 1,
controlFlow: true
},
try: {
content: 1,
controlFlow: true
},
show: {
content: 1,
controlFlow: true,
inlineBody: true
},
"html-comment": {
content: 0,
inlineBody: true,
textBody: true
},
"html-script": {
content: 3,
inlineBody: true,
textBody: true
},
"html-style": {
content: 3,
inlineBody: true,
textBody: true
},
style: {
content: getStyleContentType,
inlineBody: true,
textBody: true
}
};
const dynamicContentFacts = { content: 1 };
const nativeTagFacts = {
content: 3,
inlineBody: true
};
const textOnlyNativeTagFacts = {
content: 3,
inlineBody: true,
textBody: true
};
const pageElementFacts = {
content: 3,
inlineBody: true,
pageElement: true
};
const discardsWrapperChildrenFacts = {
content: 3,
inlineBody: true,
discardsWrapperChildren: true
};
const nativeElementFacts = /* @__PURE__ */ new Map([
["html", pageElementFacts],
["head", pageElementFacts],
["body", pageElementFacts],
["table", discardsWrapperChildrenFacts],
["thead", discardsWrapperChildrenFacts],
["tbody", discardsWrapperChildrenFacts],
["tfoot", discardsWrapperChildrenFacts],
["tr", discardsWrapperChildrenFacts],
["colgroup", discardsWrapperChildrenFacts],
["select", discardsWrapperChildrenFacts],
["optgroup", discardsWrapperChildrenFacts]
]);
const controllableElements = /* @__PURE__ */ new Map([
["input", {
attrs: [
"checked",
"checkedChange",
"checkedValue",
"checkedValueChange",
"value",
"valueChange"
],
spreadHelper: "_controllable_input",
feature: "controllable-input"
}],
["select", {
attrs: ["value", "valueChange"],
spreadHelper: "_controllable_select",
feature: "controllable-select"
}],
["textarea", {
attrs: ["value", "valueChange"],
spreadHelper: "_controllable_textarea",
feature: "controllable-textarea"
}],
["details", {
attrs: ["open", "openChange"],
spreadHelper: "_controllable_open",
feature: "controllable-open"
}],
["dialog", {
attrs: ["open", "openChange"],
spreadHelper: "_controllable_open",
feature: "controllable-open"
}]
]);
const controllableAttrs = new Set(Array.from(controllableElements.values(), (element) => element.attrs).flat());
function getTagFacts(tag) {
if (isCoreTag(tag)) return coreTagFacts[tag.node.name.value];
switch (analyzeTagNameType(tag)) {
case 0: return _marko_compiler.types.isStringLiteral(tag.node.name) && nativeElementFacts.get(tag.node.name.value) || (isTextOnlyNativeTag(tag) ? textOnlyNativeTagFacts : nativeTagFacts);
case 3: return noContentFacts;
default: return dynamicContentFacts;
}
}
function getTagContentType(tag) {
const { content } = getTagFacts(tag);
return typeof content === "function" ? content(tag.node) : content;
}
function isInTextBody(child) {
const body = child.parentPath;
return body.isMarkoTagBody() && !!getTagFacts(body.parentPath).textBody;
}
function isControllableAttr(name) {
return controllableAttrs.has(name);
}
function isTextOnlyNativeTag(tag) {
const def = (0, _marko_compiler_babel_utils.getTagDef)(tag);
return !!(def && def.html && (def.name === "title" || def.parseOptions?.text));
}
function getStyleContentType(tag) {
return tag.body.body.some(isMarkoPlaceholder) ? 3 : null;
}
function isMarkoPlaceholder(node) {
return _marko_compiler.types.isMarkoPlaceholder(node);
}
//#endregion
//#region src/translator/util/is-only-child-in-parent.ts
const kOnlyChildInParent = Symbol("only child in parent");
function getOnlyChildParentTagName(tag) {
const extra = tag.node.extra;
if (extra[kOnlyChildInParent] !== void 0) return extra[kOnlyChildInParent];
const parentTag = getParentTag(tag);
return extra[kOnlyChildInParent] = parentTag && analyzeTagNameType(parentTag) === 0 && parentTag.node.name.type === "StringLiteral" && !getTagFacts(parentTag).pageElement && isOnlyChild(tag) ? parentTag.node.name.value : false;
}
function isOnlyChild(tag) {
for (const sibling of tag.parentPath.get("body")) if (sibling.node !== tag.node && getNodeContentType(sibling, "startType") !== null) return false;
return true;
}
//#endregion
//#region src/translator/util/branch-tag.ts
function initBranchSection(bodySection, branchExpr, branch) {
bodySection.branchExpr = branchExpr;
bodySection.branch = branch;
}
function resumeOwnerByMarkerWhenUnconditional(bodySection, nodeBinding) {
const branchExprReason = findSlot(nodeBinding, 4)?.reason;
if (isStateReason(branchExprReason) && some(branchExprReason.state, hasResumableAssignment) && isUnconditionalReason(getBranchWriteReason(bodySection)) && isUnconditionalReason(getWriteReason(nodeBinding))) setSectionOwnerResumedByMarker(bodySection);
}
function getBranchResumeArgs(tag, branchReasons, singleNode) {
const tagSection = getSection(tag);
const nodeBinding = tag.node.extra.nodeBinding;
const scopeId = getScopeIdIdentifier(tagSection);
const accessor = getScopeAccessorLiteral(nodeBinding);
const endArgs = buildBranchEndArgs(tagSection, nodeBinding, getOnlyChildParentTagName(tag), singleNode);
const [markerGuard] = endArgs;
return [
scopeId,
accessor,
getWriteGuardForAny(tagSection, branchReasons, !markerGuard),
...endArgs
];
}
function buildBranchEndArgs(tagSection, nodeBinding, onlyChildParentTagName, singleNode) {
const markerReason = getWriteReason(nodeBinding);
const skipParentEnd = !!onlyChildParentTagName && !!markerReason;
if (skipParentEnd) getBranchEndTags().add(nodeBinding);
const branchExprGuard = skipParentEnd ? getWriteGuard(tagSection, findSlot(nodeBinding, 4)?.reason, false) : singleNode ? _marko_compiler.types.numericLiteral(0) : void 0;
return [
getWriteGuard(tagSection, markerReason, !branchExprGuard),
branchExprGuard,
skipParentEnd ? _marko_compiler.types.stringLiteral(`</${onlyChildParentTagName}>`) : singleNode ? _marko_compiler.types.numericLiteral(0) : void 0,
singleNode ? _marko_compiler.types.numericLiteral(1) : void 0
];
}
const [getBranchEndTags] = createProgramState(() => /* @__PURE__ */ new Set());
function isEndTagWrittenByBranch(nodeBinding) {
return !!nodeBinding && getBranchEndTags().has(nodeBinding);
}
function isSingleNodeBranch(bodySection) {
return !!(bodySection?.content?.singleChild && bodySection.content.startType === 3);
}
function buildForRuntimeCall(type, attrs, params, statements) {
return _marko_compiler.types.expressionStatement(callRuntime(forTypeToRuntime(type), ...getBaseArgsInForTag(type, attrs), _marko_compiler.types.arrowFunctionExpression(params, _marko_compiler.types.blockStatement(statements))));
}
function getForType(tag) {
for (const attr of tag.attributes) if (attr.type === "MarkoAttribute") switch (attr.name) {
case "of":
case "in":
case "to":
case "until": return attr.name;
}
}
function forTypeToRuntime(type) {
switch (type) {
case "of": return "forOf";
case "in": return "forIn";
case "to": return "forTo";
case "until": return "forUntil";
}
}
function forTypeToBranchRuntime(type) {
switch (type) {
case "of": return "_for_of";
case "in": return "_for_in";
case "to": return "_for_to";
case "until": return "_for_until";
}
}
function forTypeToUnkeyedBranchRuntime(type) {
switch (type) {
case "to": return "_for_to_unkeyed";
case "until": return "_for_until_unkeyed";
default: return "_for_of_unkeyed";
}
}
function getBaseArgsInForTag(type, attrs) {
switch (type) {
case "in": return [attrs.in];
case "of": return [attrs.of];
case "to": return [
attrs.to,
attrs.from || _marko_compiler.types.numericLiteral(0),
attrs.step || _marko_compiler.types.numericLiteral(1)
];
case "until": return [
attrs.until,
attrs.from || _marko_compiler.types.numericLiteral(0),
attrs.step || _marko_compiler.types.numericLiteral(1)
];
}
}
//#endregion
//#region src/translator/util/get-known-attr-values.ts
function getKnownAttrValues(tag) {
const attrs = {};
for (const attr of tag.attributes) if (attr.type === "MarkoAttribute") attrs[attr.name] = attr.value;
return attrs;
}
//#endregion
//#region src/translator/util/translate-attrs.ts
const contentProps = /* @__PURE__ */ new WeakSet();
function translateAttrs(tag, paramsTree = true, skip, statements = [], contentKey = "content") {
const contentProperties = [];
const attrTagLookup = tag.node.extra?.attrTagLookup;
const seen = toSet(skip);
if (attrTagLookup) {
for (const name in attrTagLookup) {
const attrTagMeta = attrTagLookup[name];
if (!seen.has(attrTagMeta.name) && getParamsTreeAt(paramsTree, attrTagMeta.name)) {
seen.add(attrTagMeta.name);
if (attrTagMeta.dynamic) {
statements.push(_marko_compiler.types.variableDeclaration("let", [_marko_compiler.types.variableDeclarator(getAttrTagIdentifier(attrTagMeta))]));
contentProperties.push(toObjectProperty(attrTagMeta.name, getAttrTagIdentifier(attrTagMeta)));
}
}
}
const attrTags = getAttrTagPaths(tag);
for (let i = 0; i < attrTags.length; i++) {
const child = attrTags[i];
if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const attrTagMeta = attrTagLookup[getTagName(child)];
if (propsUtil.has(skip, attrTagMeta.name)) continue;
if (attrTagMeta.dynamic) i = addDynamicAttrTagStatements(attrTags, i, attrTagLookup, statements, paramsTree, contentKey);
else {
const translatedAttrTag = translateAttrs(child, getParamsTreeAt(paramsTree, attrTagMeta.name), void 0, statements, contentKey);
addAttrTag(contentProperties, attrTagMeta, _marko_compiler.types.objectExpression(translatedAttrTag.properties));
}
} else i = addDynamicAttrTagStatements(attrTags, i, attrTagLookup, statements, paramsTree, contentKey);
}
}
}
if (!seen.has(contentKey) && getParamsTreeAt(paramsTree, contentKey)) {
const contentExpression = buildContent$1(tag.get("body"));
if (contentExpression) {
const contentProp = _marko_compiler.types.objectProperty(_marko_compiler.types.identifier(contentKey), contentExpression);
seen.add(contentKey);
contentProps.add(contentProp);
contentProperties.push(contentProp);
}
}
const { attributes } = tag.node;
const attrProperties = [];
const knownSpread = getSingleKnownSpread(paramsTree, attributes);
for (let i = attributes.length; i--;) {
const attr = attributes[i];
const { value } = attr;
if (_marko_compiler.types.isMarkoSpreadAttribute(attr) && knownSpread) {
if (!getCanonicalBinding(knownSpread).pruned) attrProperties.push(_marko_compiler.types.spreadElement(getDeclaredBindingExpression(knownSpread, true)));
} else if (!value.extra?.dropped) {
if (_marko_compiler.types.isMarkoSpreadAttribute(attr)) attrProperties.push(_marko_compiler.types.spreadElement(value));
else if (!seen.has(attr.name) && getParamsTreeAt(paramsTree, attr.name)) {
seen.add(attr.name);
attrProperties.push(toObjectProperty(attr.name, value));
}
}
}
return {
properties: attrProperties.reverse().concat(contentProperties),
statements
};
}
function getTranslatedBodyContentProperty(props) {
for (const prop of props) if (contentProps.has(prop)) return prop;
}
function addDynamicAttrTagStatements(attrTags, index, attrTagLookup, statements, paramsTree, contentKey = "content") {
const tag = attrTags[index];
if (tag.isMarkoTag() && !tag.node.extra.dropped) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(tag)) {
const attrTagMeta = attrTagLookup[getTagName(tag)];
const attrTagTree = getParamsTreeAt(paramsTree, attrTagMeta.name);
if (attrTagTree && attrTagMeta.dynamic) {
const translatedAttrTag = translateAttrs(tag, attrTagTree, void 0, statements, contentKey);
statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", getAttrTagIdentifier(attrTagMeta), appendAttrTag(attrTagMeta.repeated && getAttrTagIdentifier(attrTagMeta), _marko_compiler.types.objectExpression(translatedAttrTag.properties)))));
}
} else switch (getTagName(tag)) {
case "if": return translateIfAttrTag(attrTags, index, attrTagLookup, statements, paramsTree, contentKey);
case "for": return translateForAttrTag(attrTags, index, attrTagLookup, statements, paramsTree, contentKey);
}
}
return index;
}
function addAttrTag(properties, { name, repeated }, props) {
const prev = repeated && findObjectProperty(name, properties);
if (prev) prev.value = appendAttrTag(prev.value, props);
else properties.push(toObjectProperty(name, appendAttrTag(void 0, props)));
}
function appendAttrTag(prev, props) {
return prev ? callRuntime("attrTags", prev, props) : callRuntime("attrTag", props);
}
/** Unwraps a lone spread to the spread argument itself, so the result may alias
* a caller binding; anything the runtime writes to needs its own object. */
function propsToExpression(props) {
return props.length === 1 && _marko_compiler.types.isSpreadElement(props[0]) ? props[0].argument : _marko_compiler.types.objectExpression(props);
}
function translateForAttrTag(attrTags, index, attrTagLookup, statements, paramsTree, contentKey) {
const forTag = attrTags[index];
const bodyStatements = [];
addAllAttrTagsAsDynamic(forTag, attrTagLookup, bodyStatements, paramsTree, contentKey);
statements.push(buildForRuntimeCall(getForType(forTag.node), getKnownAttrValues(forTag.node), forTag.node.body.params, bodyStatements));
return index;
}
function translateIfAttrTag(attrTags, index, attrTagLookup, statements, paramsTree, contentKey) {
const ifTag = attrTags[index];
const consequentStatements = [];
let ifStatement = _marko_compiler.types.ifStatement(getConditionTestValue(ifTag), _marko_compiler.types.blockStatement(consequentStatements));
statements.push(ifStatement);
addAllAttrTagsAsDynamic(ifTag, attrTagLookup, consequentStatements, paramsTree, contentKey);
let nextIndex = index + 1;
while (nextIndex < attrTags.length) {
const nextTag = attrTags[nextIndex];
if (nextTag.isMarkoTag()) switch (getTagName(nextTag)) {
case "else-if":
case "else": {
const testValue = getConditionTestValue(nextTag);
const alternateStatements = [];
addAllAttrTagsAsDynamic(nextTag, attrTagLookup, alternateStatements, paramsTree, contentKey);
if (testValue) {
ifStatement.alternate = ifStatement = _marko_compiler.types.ifStatement(testValue, _marko_compiler.types.blockStatement(alternateStatements));
nextIndex++;
continue;
} else {
ifStatement.alternate = _marko_compiler.types.blockStatement(alternateStatements);
break;
}
}
}
break;
}
return nextIndex - 1;
}
function addAllAttrTagsAsDynamic(tag, attrTagLookup, statements, paramsTree, contentKey) {
const attrTags = getAttrTagPaths(tag);
for (let i = 0; i < attrTags.length; i++) i = addDynamicAttrTagStatements(attrTags, i, attrTagLookup, statements, paramsTree, contentKey);
}
function findObjectProperty(name, props) {
for (const prop of props) if (prop.type === "ObjectProperty") switch (prop.key.type) {
case "StringLiteral":
if (prop.key.value === name) return prop;
break;
case "Identifier": if (prop.key.name === name) return prop;
}
return false;
}
function getConditionTestValue({ node: { attributes } }) {
return attributes.length === 1 ? attributes[0].value : void 0;
}
function buildContent$1(body) {
const bodySection = body.node.extra?.section;
if (bodySection) {
if (isOutputHTML()) {
const serialized = getRendererReason(bodySection);
body.node.body.unshift(getScopeReasonStatement(bodySection));
return callRuntime(serialized ? "_content_resume" : "_content", _marko_compiler.types.stringLiteral(getResumeRegisterId(bodySection, "content")), _marko_compiler.types.arrowFunctionExpression(body.node.params, _marko_compiler.types.blockStatement(body.node.body)), getScopeIdIdentifier(getSection(getAttributeTagParent(body.parentPath))), serialized && getRegisteredLocals(bodySection));
} else {
const renderer = getSectionRendererIdentifier(bodySection);
if (renderer) {
const localClosureValues = getLocalClosureValues(bodySection);
return _marko_compiler.types.callExpression(renderer, localClosureValues ? [scopeIdentifier, localClosureValues] : [scopeIdentifier]);
}
}
}
}
function getRegisteredLocals(bodySection) {
const contentClosureValues = getContentClosureValues(bodySection);
const localClosureValues = getLocalClosureValues(bodySection);
if (contentClosureValues || localClosureValues) return _marko_compiler.types.arrowFunctionExpression(contentClosureValues ? [contentClosureValues.scope] : [], _marko_compiler.types.arrayExpression([...localClosureValues ? [localClosureValues] : [], ...contentClosureValues?.levels || []]));
}
function getLocalClosureValues(bodySection) {
if (bodySection.localClosures) return _marko_compiler.types.objectExpression(toArray(bodySection.localClosures, (closure) => toObjectProperty(getScopeAccessor(closure, true), getDeclaredBindingExpression(closure))));
}
function getSingleKnownSpread(paramsTree, attributes) {
if (paramsTree === true || !hasAllKnownProps(paramsTree)) return;
let binding;
for (let i = attributes.length; i--;) {
const attr = attributes[i];
if (attr.type === "MarkoSpreadAttribute") {
const spreadFrom = attr.value.extra?.spreadFrom;
if (binding || !spreadFrom || Array.isArray(spreadFrom)) return;
binding = spreadFrom;
} else if (binding && !propsUtil.has(binding.excludeProperties, attr.name)) return;
}
return binding;
}
//#endregion
//#region src/translator/util/known-tag.ts
const [getKnownTags] = createSectionState("known tags", () => []);
const kChildSection = Symbol("known tag child section");
const kParamsTree = Symbol("known tag params tree");
const kKnownExprs = Symbol("known tag exprs");
const [getRecursiveTags] = createProgramState(() => []);
function knownTagAnalyze(tag, childSection, childParamsTree) {
analyzeAttributeTags(tag);
const section = ensureSection(tag);
const tagBody = tag.get("body");
const tagExtra = tag.node.extra ??= {};
tagExtra.childScopeBinding = createBinding("#childScope", 0, section);
ensureBodySection(tagBody);
trackParamsReferences(tagBody, 2);
getKnownTags(section).push(tagExtra);
tagExtra[kChildSection] = childSection;
const varBinding = trackVarReferences(tag, 4);
const recursive = isSameOrAncestorSection(childSection, section);
let exprs;
if (childSection.program === section.program) {
childSection.callSections = sectionUtil.add(childSection.callSections, section);
if (recursive) getRecursiveTags().push(tag);
else exprs = analyzeKnownTagParams(tag, exposeChildParamsTree(childSection));
} else exprs = analyzeKnownTagParams(tag, childParamsTree);
if (varBinding) {
if (!recursive) assertReturns(tag, childSection);
addSetupWork(section);
const mutatesTagVar = isTagVarAssigned(tag);
const varExpr = recursive || (tagExtra.defineBodySection ? childSection.returnValueExpr : mapParamReasonToExpr(exprs, getReturnParams(childSection)));
const { childScopeBinding } = tagExtra;
varBinding.returnedBy = childScopeBinding;
reserveId(childScopeBinding, 1);
setDerivedFrom(varBinding, varExpr);
if (mutatesTagVar || varExpr === true) addAlwaysReason(childScopeBinding);
if (varExpr !== true) addReasonExprs(ensureSlot(childScopeBinding), varExpr);
}
}
function analyzeRecursiveTags() {
for (const tag of getRecursiveTags()) {
const childSection = tag.node.extra[kChildSection];
assertTerminates(tag, childSection);
if (tag.node.var) assertReturns(tag, childSection);
analyzeKnownTagParams(tag, exposeChildParamsTree(childSection));
}
}
function assertTerminates(tag, childSection) {
const callers = /* @__PURE__ */ new Set([getSection(tag)]);
for (const caller of callers) {
if (caller === childSection) throw tag.get("name").buildCodeFrameError(`A ${childSection === (0, _marko_compiler_babel_utils.getProgram)().node.extra.section ? "template" : "`<define>`"} that renders itself outside a branch never terminates. Render \`<${getTagNameHint(tag.node)}>\` inside a branch that eventually stops, such as \`<if>\`.`);
forEach(caller.callSections, (callSection) => {
callers.add(callSection);
});
}
}
function exposeChildParamsTree(childSection) {
return childSection.params && exposeParamsTree(childSection.params, true);
}
function analyzeKnownTagParams(tag, paramsTree) {
const tagExtra = tag.node.extra;
const attrExprs = /* @__PURE__ */ new Set([tagExtra]);
tagExtra[kParamsTree] = paramsTree;
const exprs = tagExtra[kKnownExprs] = analyzeParams(tagExtra, getSection(tag), tag, paramsTree, attrExprs);
setTagContentDerives(tag, paramsTree?.props?.[0]?.binding, exprs);
addReasonExprs(ensureSlot(tagExtra.childScopeBinding), fromIter(attrExprs));
return exprs;
}
function getReturnParams(section) {
const sources = getSourcesForExpr(section.returnValueExpr);
return sources && (sources.always || !!sources.state || sources.param);
}
function assertReturns(tag, childSection) {
if (!childSection.returnValueExpr) throw tag.get("var").buildCodeFrameError(`The \`${getTagNameHint(tag.node)}\` tag does not [\`<return>\`](https://markojs.com/docs/reference/core-tag#return) a value, so it does not support a [tag variable](https://markojs.com/docs/reference/language#tag-variables). Remove the variable, or add a \`<return>\` to the tag.`);
}
function isChildScopeResumed(tagExtra) {
return !!findSlot(tagExtra.childScopeBinding)?.reason;
}
function getRenderArgs(tag, properties) {
const args = tag.node.arguments;
const renderArgs = args?.length && !args.every(isDroppedNode) ? args.map(toRenderArg) : [];
if (!renderArgs.length || properties.length) renderArgs.push(propsToExpression(properties));
return renderArgs;
}
function isDroppedNode(node) {
return !!node.extra?.dropped;
}
function toRenderArg(arg) {
return isDroppedNode(arg) ? _marko_compiler.types.buildUndefinedNode() : arg;
}
function knownTagTranslateHTML(tag, tagIdentifier) {
const { node } = tag;
const tagExtra = node.extra;
const childSection = tagExtra[kChildSection];
const paramsTree = getSettledParamsTree(tagExtra[kParamsTree]);
writeHTMLResumeStatements(tag);
const tagVar = node.var;
const section = getSection(tag);
const attrsTree = paramsTree?.props?.[tag.node.arguments?.length || 0];
const { properties, statements } = paramsTree && !paramsTree.props || attrsTree ? translateAttrs(tag, attrsTree) : {
properties: [],
statements: []
};
const childScopeBinding = tagExtra.childScopeBinding;
let varStatement;
if (isChildScopeResumed(tagExtra)) {
const peekScopeId = generateUidIdentifier(childScopeBinding?.name);
statements.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(peekScopeId, callRuntime("_peek_scope_id"))]));
writeSlot(findSlot(childScopeBinding), callRuntime("_existing_scope", peekScopeId));
if (tagVar) varStatement = _marko_compiler.types.expressionStatement(callRuntime("_var", getScopeIdIdentifier(section), getScopeOffsetAccessorLiteral(childScopeBinding), peekScopeId, _marko_compiler.types.stringLiteral(getResumeRegisterId(section, tagVar.extra?.binding, "var"))));
}
if (childSection.paramReasonGroups) {
const childGroupMask = buildChildGroupMask(section, childScopeBinding, childSection.paramReasonGroups);
if (childGroupMask) tag.insertBefore(_marko_compiler.types.expressionStatement(callRuntime("_set_scope_reason", childGroupMask)));
}
if (tagVar) {
translateVar(tag, _marko_compiler.types.callExpression(tagIdentifier, getRenderArgs(tag, properties)), "let", statements);
if (varStatement) statements.push(varStatement);
} else statements.push(_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(tagIdentifier, getRenderArgs(tag, properties))));
for (const replacement of tag.replaceWithMultiple(statements)) replacement.skip();
}
function knownTagTranslateDOM(tag, getBindingIdentifier, callSetup) {
const tagSection = getSection(tag);
const { node } = tag;
const extra = node.extra;
const paramsTree = getSettledParamsTree(extra[kParamsTree]);
const childScopeBinding = extra.childScopeBinding;
if (node.var) {
const varBinding = node.var.extra.binding;
const signal = initValue(varBinding);
signal.register = isChildScopeResumed(extra);
signal.referenced = true;
signal.buildAssignment = (valueSection, value) => buildVarChange(createScopeReadExpression(childScopeBinding, valueSection), value, varBinding);
addStatement("render", tagSection, void 0, callRuntime("_var", scopeIdentifier, getScopeAccessorLiteral(childScopeBinding, true), signal.identifier));
}
callSetup?.(tagSection, childScopeBinding);
if (paramsTree) writeParamsToSignals(tag, paramsTree, getTagName(tag) || "tag", {
tagSection,
getBindingIdentifier,
childScopeBinding
});
}
function addKnownTagReasons(section) {
for (const tagExtra of getKnownTags(section)) {
const { childScopeBinding } = tagExtra;
const knownExprs = tagExtra[kKnownExprs];
const childSection = tagExtra[kChildSection];
if (knownExprs && childScopeBinding && childSection.paramReasonGroups) for (const group of childSection.paramReasonGroups) addReason(ensureSlot(childScopeBinding, 5, section, group), getSourcesForExprs(mapParamReasonToExpr(knownExprs, group)));
}
}
function callsOtherTemplateSetup(section) {
for (const tagExtra of getKnownTags(section)) {
const childSection = tagExtra[kChildSection];
if (tagExtra.tagNameLoad || childSection.program !== section.program && childSection.hasSetupWork) return true;
}
return false;
}
function buildChildGroupMask(section, childScopeBinding, reasonGroups) {
return buildGroupMask(reasonGroups.map((group) => {
const reason = findSlot(childScopeBinding, 5, section, group)?.reason;
const guard = reason && getWriteGuard(section, reason, false);
return {
value: !guard ? void 0 : guard.type === "NumericLiteral" ? guard.value : guard,
names: getDebugNames(group)
};
}));
}
function analyzeParams(rootTagExtra, section, tag, paramsTree, rootAttrExprs) {
const paramsExpr = {};
if (!paramsTree) {
dropAllTagNodes(tag.node);
return paramsExpr;
}
if (!readsParamsByName(tag, paramsTree)) {
paramsExpr.value = setDerivedFromTag(section, tag, paramsTree.binding, paramsExpr);
return paramsExpr;
}
const known = paramsExpr.known = {};
let i = 0;
if (tag.node.arguments) for (const arg of tag.node.arguments) {
const argTree = paramsTree.props[i];
if (argTree) {
const argValueExtra = arg.extra ??= {};
known[i] = { value: argValueExtra };
rootAttrExprs.add(argValueExtra);
addSetupExpr(section, arg);
setDerivedFrom(argTree.binding, argValueExtra, paramsExpr);
} else dropNodes(arg);
i++;
}
const attrsTree = paramsTree.props[i];
if (attrsTree) known[i] = analyzeAttrs(rootTagExtra, section, tag, attrsTree, rootAttrExprs, paramsExpr);
else {
const args = tag.node.arguments;
tag.node.arguments = null;
dropAllTagNodes(tag.node);
tag.node.arguments = args;
}
return paramsExpr;
}
function analyzeAttrs(rootTagExtra, section, tag, paramsTree, rootAttrExprs, rootExprs) {
const inputExpr = {};
if (!paramsTree.props) {
inputExpr.value = setDerivedFromTag(section, tag, paramsTree.binding, rootExprs);
return inputExpr;
}
const known = inputExpr.known = {};
const attrTagLookup = analyzeAttributeTags(tag);
const seen = /* @__PURE__ */ new Set();
const remaining = new Set(getAllKnownPropNames(paramsTree));
const dropReferenceNodes = [];
let restReferenceNodes;
if (attrTagLookup) {
const nodeReferencesByGroup = /* @__PURE__ */ new Map();
const analyzeDynamicAttrTagChildGroup = (group, child) => {
const referenceNodes = [];
const collectAttrTag = (attrTag) => collectAttrTagReferenceNodes(attrTag, attrTagLookup, paramsTree, referenceNodes, dropReferenceNodes);
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) collectAttrTag(child.node);
else getAllTagReferenceNodes(child.node, referenceNodes, collectAttrTag);
const groupReferences = nodeReferencesByGroup.get(group);
if (groupReferences) groupReferences.referenceNodes = groupReferences.referenceNodes.concat(referenceNodes);
else nodeReferencesByGroup.set(group, {
firstTag: child,
referenceNodes
});
};
for (const attrTagName in attrTagLookup) seen.add(attrTagLookup[attrTagName].name);
const attrTags = getAttrTagPaths(tag);
for (const child of attrTags) if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const attrTagMeta = attrTagLookup[getTagName(child)];
const childAttrTree = getParamsTreeAt(paramsTree, attrTagMeta.name);
if (!childAttrTree) dropAttrTag(child.node, dropReferenceNodes);
else if (attrTagMeta.dynamic) analyzeDynamicAttrTagChildGroup(attrTagMeta.group, child);
else if (childAttrTree === true) {
getAllTagReferenceNodes(child.node, restReferenceNodes ||= []);
known[attrTagMeta.name] = { value: rootTagExtra };
} else if (childAttrTree.props && !(attrTagMeta.repeated && childAttrTree.rest)) {
if (remaining.delete(attrTagMeta.name)) known[attrTagMeta.name] = analyzeAttrs(rootTagExtra, section, child, childAttrTree, rootAttrExprs, rootExprs);
else dropAttrTag(child.node, dropReferenceNodes);
} else analyzeDynamicAttrTagChildGroup(attrTagMeta.group, child);
} else {
const group = child.node.extra.attributeTagGroup;
if (hasGroupReads(group, attrTagLookup, paramsTree)) analyzeDynamicAttrTagChildGroup(group, child);
else dropAttrTag(child.node, dropReferenceNodes);
}
}
for (const [group, { firstTag: { node }, referenceNodes }] of nodeReferencesByGroup) {
let bindings;
let hasRest = false;
const trees = getGroupParamsTrees(group, attrTagLookup, paramsTree);
for (const [, tree] of trees) if (tree === true) hasRest = true;
else bindings = bindingUtil.add(bindings, tree.binding);
if (hasRest) {
const groupKnownValue = { value: rootTagExtra };
restReferenceNodes ||= [];
for (const node of referenceNodes) restReferenceNodes.push(node);
forEach(bindings, (binding) => {
setDerivedFrom(binding, rootTagExtra, rootExprs);
});
for (const [attrTagMeta, tree] of trees) if (tree !== true) remaining.delete(attrTagMeta.name);
for (const name of group) {
const attrTagMeta = attrTagLookup[name];
known[attrTagMeta.name] = groupKnownValue;
}
continue;
}
const groupExtra = mergeReferences(section, node, referenceNodes);
const groupKnownValue = { value: groupExtra };
rootAttrExprs.add(groupExtra);
forEach(bindings, (binding) => {
setDerivedFrom(binding, groupExtra, rootExprs);
});
for (const name of group) {
const attrTagMeta = attrTagLookup[name];
remaining.delete(attrTagMeta.name);
known[attrTagMeta.name] = groupKnownValue;
}
}
}
const contentTree = getParamsTreeAt(paramsTree, "content");
if (!contentTree) dropContent(tag.node.body);
else if (!seen.has("content")) {
if (getSectionForBody(tag.get("body"))) {
seen.add("content");
if (contentTree === true) known.content = { value: rootTagExtra };
else {
remaining.delete("content");
known.content = { value: void 0 };
addSetupWork(section);
}
}
}
let knownSpread;
let spreadReferenceNodes;
const { attributes } = tag.node;
for (let i = attributes.length; i--;) {
const attr = attributes[i];
if (_marko_compiler.types.isMarkoAttribute(attr)) {
const attrTree = getParamsTreeAt(paramsTree, attr.name);
if (!attrTree || seen.has(attr.name)) {
dropReferenceNodes.push(attr.value);
continue;
}
seen.add(attr.name);
if (spreadReferenceNodes) spreadReferenceNodes.push(attr.value);
else if (attrTree === true) {
(restReferenceNodes ||= []).push(attr.value);
known[attr.name] = { value: rootTagExtra };
} else {
const attrExtra = attr.value.extra ??= {};
remaining.delete(attr.name);
known[attr.name] = { value: attrExtra };
rootAttrExprs.add(attrExtra);
addSetupExpr(section, attr.value);
setDerivedFrom(attrTree.binding, attrExtra, rootExprs);
if (!isOwnBinding(attrTree.binding) && isInvokeOnlyBinding(attrTree.binding)) attrExtra.invokeOnly = true;
}
} else if (spreadReferenceNodes) spreadReferenceNodes.push(attr.value);
else {
knownSpread = getSingleKnownSpread(paramsTree, attributes);
if (knownSpread) dropNodes(attr.value);
else (spreadReferenceNodes = restReferenceNodes || []).push(attr.value);
}
}
if (knownSpread) for (const prop of remaining) {
const propBinding = ensurePropertyAlias(knownSpread, prop);
const propExtra = { section };
const attrTree = getParamsTreeAt(paramsTree, prop);
known[prop] = { value: propExtra };
rootAttrExprs.add(propExtra);
addRead(propExtra, propExtra, propBinding, section, void 0);
setDerivedFrom(attrTree === true ? paramsTree.rest.binding : attrTree.binding, propExtra, rootExprs);
}
else if (spreadReferenceNodes) {
if (remaining.size || paramsTree.rest && !paramsTree.rest.props) {
inputExpr.value = mergeReferences(section, tag.node, spreadReferenceNodes);
setDerivedFrom(paramsTree.rest?.binding || paramsTree.binding, inputExpr.value, rootExprs);
} else dropNodes(spreadReferenceNodes);
} else {
if (restReferenceNodes) {
inputExpr.value = mergeReferences(section, tag.node, restReferenceNodes);
setDerivedFrom(paramsTree.rest.binding, inputExpr.value, rootExprs);
}
if (remaining.size) addSetupWork(section);
if (paramsTree.rest && !paramsTree.rest.props) addSetupExpr(section, tag.node);
}
dropNodes(dropReferenceNodes);
return inputExpr;
}
function readsParamsByName(tag, paramsTree) {
return !!paramsTree.props && !paramsTree.rest && !tag.node.arguments?.some(isSpreadArgument);
}
function isSpreadArgument(arg) {
return arg.type === "SpreadElement";
}
function setDerivedFromTag(section, tag, binding, rootExprs) {
const extra = mergeTagReferences(section, tag.node);
setDerivedFrom(binding, extra, rootExprs);
return extra;
}
function dropAllTagNodes(tag) {
const nodes = [];
dropContent(tag.body);
dropNodes(getAllTagReferenceNodes(tag, nodes, (attrTag) => dropAttrTag(attrTag, nodes)));
}
function collectAttrTagReferenceNodes(attrTag, attrTagLookup, paramsTree, referenceNodes, dropReferenceNodes) {
const attrTagTree = getParamsTreeAt(paramsTree, attrTagLookup[attrTag.name.value].name);
if (attrTagTree) {
if (!getParamsTreeAt(attrTagTree, "content")) dropContent(attrTag.body);
getAllTagReferenceNodes(attrTag, referenceNodes, (nestedAttrTag) => collectAttrTagReferenceNodes(nestedAttrTag, attrTag.extra.attrTagLookup, attrTagTree, referenceNodes, dropReferenceNodes));
} else dropAttrTag(attrTag, dropReferenceNodes);
}
function dropAttrTag(tag, dropReferenceNodes) {
dropReferenceNodes.push(tag);
if (!tag.body.attributeTags) dropContent(tag.body);
getAllTagReferenceNodes(tag, dropReferenceNodes, (attrTag) => dropAttrTag(attrTag, dropReferenceNodes));
}
function writeParamsToSignals(tag, paramsTree, hint, info) {
if (!readsParamsByName(tag, paramsTree)) {
const referencedBindings = getReferencedBindings(tag.node.extra);
const tagInputIdentifier = info.getBindingIdentifier(paramsTree.binding, `${hint}_params`);
const translatedAttrs = translateAttrs(tag);
if (translatedAttrs.statements.length) addStatement("render", info.tagSection, referencedBindings, translatedAttrs.statements);
writeToSignal(info, tagInputIdentifier, referencedBindings, _marko_compiler.types.arrayExpression(getRenderArgs(tag, translatedAttrs.properties)));
return;
}
let i = 0;
if (tag.node.arguments) for (const arg of tag.node.arguments) {
const argTree = paramsTree.props[i];
if (argTree) writeToSignal(info, info.getBindingIdentifier(argTree.binding, `${hint}_param_${i}`), getReferencedBindings(arg.extra), arg, true);
i++;
}
const attrsTree = paramsTree.props[i];
if (attrsTree) writeAttrsToSignals(tag, attrsTree, `${hint}_input`, info);
}
function applyAttrObject(tag, paramsTree, tagInputIdentifier, info) {
const referencedBindings = getReferencedBindings(tag.node.extra);
const statements = [];
let translatedProps;
if ((0, _marko_compiler_babel_utils.isAttributeTag)(tag)) {
const attrTagName = getTagName(tag);
for (const attrTag of tag.parentPath.get("attributeTags")) if (attrTag.isMarkoTag() && getTagName(attrTag) === attrTagName) translatedProps = appendAttrTag(translatedProps, _marko_compiler.types.objectExpression(translateAttrs(attrTag, paramsTree, void 0, statements).properties));
} else translatedProps = propsToExpression(translateAttrs(tag, paramsTree, void 0, statements).properties);
if (statements.length) addStatement("render", info.tagSection, referencedBindings, statements);
writeToSignal(info, tagInputIdentifier, referencedBindings, translatedProps, true);
}
function writeAttrsToSignals(tag, paramsTree, hint, info) {
if (!paramsTree.props) {
applyAttrObject(tag, paramsTree, info.getBindingIdentifier(paramsTree.binding, hint), info);
return;
}
const attrTagLookup = analyzeAttributeTags(tag);
const seen = /* @__PURE__ */ new Set();
const tagReferencedBindings = getReferencedBindings(tag.node.extra);
const remaining = new Set(getAllKnownPropNames(paramsTree));
const contentProps = [];
if (attrTagLookup) {
const attrTags = tag.get("attributeTags");
const statementsByGroup = /* @__PURE__ */ new Map();
const translateDynamicAttrTagChildInGroup = (group, index) => {
const child = attrTags[index];
let statements = statementsByGroup.get(group)?.statements;
if (!statements) {
statements = [];
statementsByGroup.set(group, {
referencedBindings: getReferencedBindings(child.node.extra),
statements
});
}
return addDynamicAttrTagStatements(attrTags, index, attrTagLookup, statements, paramsTree);
};
for (const attrTagName in attrTagLookup) {
const attrTagMeta = attrTagLookup[attrTagName];
seen.add(attrTagMeta.name);
if (attrTagMeta.dynamic && getParamsTreeAt(paramsTree, attrTagMeta.name) === true) contentProps.push(toObjectProperty(attrTagMeta.name, getAttrTagIdentifier(attrTagMeta)));
}
for (let i = 0; i < attrTags.length; i++) {
const child = attrTags[i];
if (child.isMarkoTag()) {
if ((0, _marko_compiler_babel_utils.isAttributeTag)(child)) {
const attrTagMeta = attrTagLookup[getTagName(child)];
const childAttrTree = getParamsTreeAt(paramsTree, attrTagMeta.name);
if (!childAttrTree) {} else if (attrTagMeta.dynamic) i = translateDynamicAttrTagChildInGroup(attrTagMeta.group, i);
else if (childAttrTree === true) {
const statements = [];
const translatedAttrs = translateAttrs(child, true, void 0, statements);
addStatement("render", info.tagSection, tagReferencedBindings, statements);
addAttrTag(contentProps, attrTagMeta, _marko_compiler.types.objectExpression(translatedAttrs.properties));
} else if (attrTagMeta.repeated && (!childAttrTree.props || childAttrTree.rest)) {
if (remaining.delete(attrTagMeta.name)) applyAttrObject(child, childAttrTree, info.getBindingIdentifier(childAttrTree.binding, `${hint}_${attrTagMeta.name}`), info);
} else {
remaining.delete(attrTagMeta.name);
writeAttrsToSignals(child, childAttrTree, `${hint}_${attrTagMeta.name}`, info);
}
} else {
const group = child.node.extra.attributeTagGroup;
if (hasGroupReads(group, attrTagLookup, paramsTree)) i = translateDynamicAttrTagChildInGroup(group, i);
else if (getTagName(child) === "if") while (++i < attrTags.length) {
const nextTag = attrTags[i];
switch (nextTag.isMarkoTag() && getTagName(nextTag)) {
case "else":
case "else-if": continue;
}
i--;
break;
}
}
}
}
for (const [group, { referencedBindings, statements }] of statementsByGroup) {
const trees = getGroupParamsTrees(group, attrTagLookup, paramsTree);
const hasRest = trees.some(([, tree]) => tree === true);
addStatement("render", info.tagSection, hasRest ? tagReferencedBindings : referencedBindings, [_marko_compiler.types.variableDeclaration("let", trees.map(([attrTagMeta]) => _marko_compiler.types.variableDeclarator(getAttrTagIdentifier(attrTagMeta)))), ...statements]);
for (const [attrTagMeta, tree] of trees) if (tree !== true) {
remaining.delete(attrTagMeta.name);
writeToSignal(info, info.getBindingIdentifier(tree.binding, `${hint}_${attrTagMeta.name}`), hasRest ? tagReferencedBindings : referencedBindings, getAttrTagIdentifier(attrTagMeta));
}
}
}
const contentTree = getParamsTreeAt(paramsTree, "content");
if (!seen.has("content") && contentTree) {
const bodySection = getSectionForBody(tag.get("body"));
if (bodySection) {
seen.add("content");
const bodyValue = _marko_compiler.types.callExpression(getSectionRendererIdentifier(bodySection), [scopeIdentifier]);
if (contentTree === true) contentProps.push(toObjectProperty("content", bodyValue));
else {
remaining.delete("content");
const directContent = !bodySection.params;
writeToSignal(info, info.getBindingIdentifier(contentTree.binding, `${hint}_content`, directContent), void 0, bodyValue, true);
}
}
}
let knownSpread;
let hasSpread = false;
const attrProps = [];
const staticAttrs = [];
const { attributes } = tag.node;
for (let i = attributes.length; i--;) {
const attr = attributes[i];
if (_marko_compiler.types.isMarkoAttribute(attr)) {
const attrTree = getParamsTreeAt(paramsTree, attr.name);
if (!attrTree || seen.has(attr.name)) continue;
seen.add(attr.name);
if (hasSpread || attrTree === true) attrProps.push(toObjectProperty(attr.name, attr.value));
else staticAttrs.push(attr);
} else if (hasSpread) attrProps.push(_marko_compiler.types.spreadElement(attr.value));
else {
knownSpread = getSingleKnownSpread(paramsTree, attributes);
if (!knownSpread) {
hasSpread = true;
attrProps.push(_marko_compiler.types.spreadElement(attr.value));
}
}
}
const inputProps = attrProps.reverse().concat(contentProps);
for (let i = staticAttrs.length; i--;) {
const attr = staticAttrs[i];
const attrSignal = getSignalIdentifier(info, paramsTree, hint, attr.name);
remaining.delete(attr.name);
writeToSignal(info, attrSignal, getReferencedBindings(attr.value.extra), attr.value, true);
}
if (knownSpread) for (const prop of remaining) {
const propSignal = getSignalIdentifier(info, paramsTree, hint, prop);
const propBinding = getPropertyAlias(knownSpread, prop);
writeToSignal(info, propSignal, propBinding, createScopeReadExpression(propBinding, info.tagSection), true);
}
else if (hasSpread && (remaining.size || paramsTree.rest && !paramsTree.rest.props)) {
const spreadExpr = propsToExpression(inputProps);
let spreadId = spreadExpr;
if (!isSimpleReference(spreadExpr)) {
spreadId = generateUidIdentifier(`${hint}_spread`);
addStatement("render", info.tagSection, tagReferencedBindings, [_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(spreadId, spreadExpr)])]);
}
for (const name of remaining) writeToSignal(info, getSignalIdentifier(info, paramsTree, hint, name), tagReferencedBindings, toMemberExpression(_marko_compiler.types.cloneNode(spreadId, true), name));
if (paramsTree.rest && !paramsTree.rest.props) {
const props = [];
const restId = _marko_compiler.types.identifier(paramsTree.rest.binding.name);
forEach(paramsTree.rest.binding.excludeProperties, (name) => {
const propId = toPropertyName(name);
const shorthand = propId.type === "Identifier" && _marko_compiler.types.isValidIdentifier(name);
props.push(_marko_compiler.types.objectProperty(propId, shorthand ? propId : generateUidIdentifier(name), false, shorthand));
});
props.push(_marko_compiler.types.restElement(restId));
writeToSignal(info, info.getBindingIdentifier(paramsTree.rest.binding, hint + "_$rest"), tagReferencedBindings, _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.objectPattern(props)], restId), [spreadId]), true);
}
} else {
for (const name of remaining) writeToSignal(info, getSignalIdentifier(info, paramsTree, hint, name), void 0);
if (paramsTree.rest && !paramsTree.rest.props) writeToSignal(info, info.getBindingIdentifier(paramsTree.rest.binding, hint + "_$rest"), tagReferencedBindings, _marko_compiler.types.objectExpression(inputProps), true);
}
}
function writeToSignal(info, signal, referencedBindings, value, isPure) {
const scope = createScopeReadExpression(info.childScopeBinding, info.tagSection);
addStatement("render", info.tagSection, referencedBindings, _marko_compiler.types.callExpression(signal, value ? [scope, value] : [scope]), isPure);
}
function getSignalIdentifier(info, paramsTree, hint, name) {
return info.getBindingIdentifier(getParamsTreeAt(paramsTree, name).binding, `${hint}_${name}`);
}
function isSimpleReference(expr) {
switch (expr.type) {
case "Identifier": return true;
case "MemberExpression": return !expr.computed && isSimpleReference(expr.object);
default: return false;
}
}
function hasGroupReads(group, attrTagLookup, paramsTree) {
return group.some((name) => !!getParamsTreeAt(paramsTree, attrTagLookup[name].name));
}
function getGroupParamsTrees(group, attrTagLookup, paramsTree) {
const trees = [];
for (const name of group) {
const attrTagMeta = attrTagLookup[name];
const tree = getParamsTreeAt(paramsTree, attrTagMeta.name);
if (tree) trees.push([attrTagMeta, tree]);
}
return trees;
}
//#endregion
//#region src/translator/util/module-registrations.ts
const kRegisteredExports = Symbol("registered exports");
const [getReferencesByFn] = createProgramState(() => /* @__PURE__ */ new Map());
const [getReferencesByImport] = createProgramState(() => /* @__PURE__ */ new Map());
function trackFunction(fn, fnExtra, markoRoot) {
reserveExportRegisterId(fnExtra, fn, markoRoot);
if (isStatic(markoRoot)) {
const refs = getStaticDeclRefs(fn);
if (refs.size) getReferencesByFn().set(fnExtra, refs);
} else getReferencesByFn().set(fnExtra, /* @__PURE__ */ new Set([fnExtra.exprRoot]));
}
function canIgnoreRegister(markoRoot, exprRoot) {
return markoRoot.isMarkoPlaceholder() || markoRoot.isMarkoScriptlet() && (!markoRoot.node.static || markoRoot.node.target === "server") || markoRoot.isMarkoTag() && markoRoot.node.name == exprRoot.node;
}
function addFunctionReasons() {
for (const [fnExtra, exprExtras] of getReferencesByFn()) {
const reason = resolveReason(exprExtras);
if (reason) fnExtra.reason = mergeSources(fnExtra.reason, reason);
}
}
function finalizeRegistrations() {
const programExtra = (0, _marko_compiler_babel_utils.getProgram)().node.extra;
for (const fnExtra of getReferencesByFn().keys()) if (fnExtra.reason) {
registerFunction(fnExtra);
programExtra.isInteractive ||= isUnconditionalReason(fnExtra.reason);
}
for (const [{ node, local, registered, fnRoots }, exprExtras] of getReferencesByImport()) {
const reason = fnRoots ? resolveTemplateReason(exprExtras) : resolveReason(exprExtras);
if (reason) {
if (!fnRoots || !isTemplateShipped(fnRoots, exprExtras)) {
const extra = node.extra ??= {};
extra.registeredImports ??= /* @__PURE__ */ new Map();
extra.registeredImports.set(local, registered);
}
programExtra.isInteractive ||= isUnconditionalReason(reason);
}
}
}
/**
* Tracks a template imported as a default export. The server writes a template
* only as a binding's value, so the importing template registers it when one may.
*/
function trackImportedTemplate(importDecl, local, templateFile) {
trackImport(importDecl, local, {
registerId: templateFile.metadata.marko.id,
exportName: "default",
filename: templateFile.opts.filename
}, /* @__PURE__ */ new Set());
}
/**
* Tracks an export imported from another template that registers under an id,
* if it does. The importing template registers it (under that id) when client
* code reads its own references.
*/
function trackImport(importDecl, local, registered, fnRoots) {
const binding = registered && importDecl.scope.getBinding(local);
if (!binding) return;
const refs = /* @__PURE__ */ new Set();
addBindingRefs(binding, refs, /* @__PURE__ */ new Set(), fnRoots);
if (refs.size) getReferencesByImport().set({
node: importDecl.node,
local,
registered,
fnRoots
}, refs);
}
/**
* Finds the id reserved for an export, following `export ... from` hops. Each
* template only records the exports it declares, so this resolves on demand:
* a template in an import cycle is read while it is still analyzing, and would
* hand out an incomplete map if the ids were pushed ahead of time.
*/
function resolveRegisteredExport(file, exportName, seen = /* @__PURE__ */ new Set()) {
const key = `${file.opts.filename}\0${exportName}`;
if (seen.has(key)) return;
seen.add(key);
const registered = file.ast.program.extra?.[kRegisteredExports]?.get(exportName);
if (registered) return registered;
for (const child of file.ast.program.body) {
if (child.type !== "ExportNamedDeclaration" && child.type !== "ExportAllDeclaration" || !child.source || (child.exportKind || "value") !== "value") continue;
const sourceFile = (0, _marko_compiler_babel_utils.loadFileForImport)(file, child.source.value);
if (!sourceFile) continue;
if (child.type === "ExportAllDeclaration") {
const resolved = resolveRegisteredExport(sourceFile, exportName, seen);
if (resolved) return resolved;
continue;
}
for (const specifier of child.specifiers) {
if (specifier.type !== "ExportSpecifier" || (specifier.exportKind || "value") !== "value" || getLiteralName(specifier.exported) !== exportName) continue;
const resolved = resolveRegisteredExport(sourceFile, specifier.local.name, seen);
if (resolved) return resolved;
}
}
}
/**
* Writes the registrations for module scoped functions: the ones this template
* exports and registers itself, and the ones it imports from a template that
* reserved a register id without registering it; and for templates it imports.
*/
function writeModuleRegistrations(program) {
const file = (0, _marko_compiler_babel_utils.getFile)();
const statements = [];
const seen = /* @__PURE__ */ new Set();
for (const child of program.node.body) {
const registeredImports = _marko_compiler.types.isImportDeclaration(child) && child.extra?.registeredImports;
if (registeredImports) for (const [local, registered] of registeredImports) {
if (seen.has(registered.registerId)) continue;
seen.add(registered.registerId);
if (isOutputHTML()) {
if (registered.exportName !== "default") statements.push(buildRegistration(local, registered.registerId));
} else (0, _marko_compiler_babel_utils.importDefault)(file, resolveRegisterModule(file, registered));
}
else if (child.type === "ExportNamedDeclaration") addExportRegistrations(child, seen, statements);
}
program.node.body.push(...statements);
}
function resolveReason(exprExtras) {
let reason;
for (const exprExtra of exprExtras) {
const extra = getCanonicalExtra(exprExtra);
if (!exprExtra.consumed || extra.retained) reason = mergeSources(reason, landsRetained(extra) ? ALWAYS : getReasonForExpr(extra));
}
return reason;
}
function resolveTemplateReason(exprExtras) {
let reason;
for (const exprExtra of exprExtras) {
const extra = getCanonicalExtra(exprExtra);
if (!extra.isEffect) reason = mergeSources(reason, getReasonForExpr(extra));
}
return reason;
}
function isTemplateShipped(fnRoots, exprExtras) {
for (const fnRoot of fnRoots) if (isRegisteredFnExtra(fnRoot)) return true;
for (const exprExtra of exprExtras) if (getCanonicalExtra(exprExtra).isEffect) return true;
return false;
}
function reserveExportRegisterId(fnExtra, fn, markoRoot) {
if (!isStatic(markoRoot)) return;
const exportNames = getExportNames(fn, markoRoot);
const exportName = exportNames?.find((name) => _marko_compiler.types.isValidIdentifier(name));
if (!exportName) return;
const { markoOpts, opts: { filename } } = (0, _marko_compiler_babel_utils.getFile)();
const programExtra = (0, _marko_compiler_babel_utils.getProgram)().node.extra;
const registerId = (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, filename, `${fnExtra.section.id}/export/${exportName}`);
const registered = {
registerId,
exportName,
filename
};
fnExtra.exportRegisterId = registerId;
programExtra[kRegisteredExports] ??= /* @__PURE__ */ new Map();
for (const name of exportNames) programExtra[kRegisteredExports].set(name, registered);
}
function getExportNames(fn, markoRoot) {
const localName = getExportableName(fn);
if (localName === void 0) return;
const exportNames = markoRoot.isExportNamedDeclaration() && !markoRoot.node.source ? [localName] : [];
const binding = fn.scope.getBinding(localName);
if (binding) for (const ref of binding.referencePaths) {
const specifier = ref.parent;
if (specifier?.type === "ExportSpecifier" && (specifier.exportKind || "value") === "value" && !ref.parentPath.parent.source) {
const exportName = getLiteralName(specifier.exported);
if (exportName !== "default") exportNames.push(exportName);
}
}
return exportNames.length ? exportNames : void 0;
}
function getExportableName(fn) {
const { node, parent } = fn;
if (node.type === "FunctionDeclaration") return node.id?.name;
if (_marko_compiler.types.isVariableDeclarator(parent) && parent.init === node && _marko_compiler.types.isIdentifier(parent.id) && _marko_compiler.types.isVariableDeclaration(fn.parentPath.parent, { kind: "const" })) return parent.id.name;
}
function getStaticDeclRefs(path$11, refs = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set(), fnRoots) {
const decl = getDeclarationRoot(path$11);
if (decl && !seen.has(decl.node)) {
seen.add(decl.node);
const ids = decl.getOuterBindingIdentifiers();
if (ids) for (const name in ids) {
const binding = decl.scope.getBinding(name);
if (binding) addBindingRefs(binding, refs, seen, fnRoots);
}
}
return refs;
}
function addBindingRefs(binding, refs, seen, fnRoots) {
for (const ref of binding.referencePaths) {
if (isInvokedFunction(ref) || ref.parentPath.type === "Program") continue;
const exprRoot = getExprRoot(ref);
const markoRoot = getMarkoRoot(exprRoot);
if (!markoRoot || canIgnoreRegister(markoRoot, exprRoot)) continue;
if (fnRoots) {
const fnRoot = getFnRoot(ref);
if (fnRoot) fnRoots.add(fnRoot.node.extra ??= {});
}
if (isStatic(markoRoot)) getStaticDeclRefs(ref, refs, seen, fnRoots);
else refs.add(exprRoot.node.extra ??= {});
}
}
function registerFunction(fnExtra) {
const { markoOpts, opts: { filename } } = (0, _marko_compiler_babel_utils.getFile)();
fnExtra.name = generateUid(fnExtra.name);
fnExtra.registerId = fnExtra.exportRegisterId ?? (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, filename, `${fnExtra.section.id}/${fnExtra.name.slice(1)}`);
}
function addExportRegistrations(node, seen, statements) {
const { declaration } = node;
if (!declaration) return;
const add = (local, registerId) => {
if (seen.has(registerId)) return;
seen.add(registerId);
statements.push(buildRegistration(local, registerId));
};
if (declaration.type === "FunctionDeclaration") {
if (isRegisteredFnExtra(declaration.extra)) add(declaration.id.name, declaration.extra.registerId);
return;
}
if (isOutputHTML() || declaration.type !== "VariableDeclaration") return;
for (const declarator of declaration.declarations) {
const extra = declarator.init?.extra;
if (isRegisteredFnExtra(extra) && _marko_compiler.types.isIdentifier(declarator.id)) add(declarator.id.name, extra.registerId);
}
}
function buildRegistration(local, registerId) {
return _marko_compiler.types.expressionStatement(isOutputHTML() ? callRuntime("_resume", _marko_compiler.types.identifier(local), _marko_compiler.types.stringLiteral(registerId)) : registerRuntimeValue(registerId, _marko_compiler.types.identifier(local)));
}
function resolveRegisterModule(file, { filename, exportName, registerId }) {
const importer = file.opts.filename;
return getMarkoOpts().resolveVirtualDependency(importer, {
virtualPath: `${relativePath(importer, filename)}.register-${exportName}.js`,
code: `import { ${exportName} as value } from "./${path.default.basename(filename)}";\nimport { _resumed } from "${getRuntimePath("dom")}";\n_resumed${isValidPropertyIdentifier(registerId) ? `.${registerId}` : `[${JSON.stringify(registerId)}]`} = value;\n`
});
}
function relativePath(from, to) {
const relative = path.default.relative(path.default.dirname(from), to).split(path.default.sep).join("/");
return relative.startsWith(".") ? relative : `./${relative}`;
}
//#endregion
//#region src/translator/util/solve-reasons.ts
function solveReasons(intersectionsBySection) {
let reasonsVersion;
do {
reasonsVersion = getReasonsVersion();
resetReaders();
forEachSection((section) => addIntersectionReasons(section, intersectionsBySection.get(section)));
forEachSection(addClosureReasons);
addRegisteredFnReasons(getFunctionReadsByExpression());
forEachSectionReverse(solveSectionReasons);
} while (reasonsVersion !== getReasonsVersion());
}
function solveSectionReasons(section) {
addKnownTagReasons(section);
mergeSlotReasons(section);
ensureSectionReasonGroups(section);
}
function addIntersectionReasons(section, intersections) {
if (intersections) for (const intersection of intersections) for (let i = 0; i < intersection.length - 1; i++) for (let j = i + 1; j < intersection.length; j++) {
addIntersectionMemberReason(section, intersection[i], intersection[j]);
addIntersectionMemberReason(section, intersection[j], intersection[i]);
}
}
function addIntersectionMemberReason(section, member, partner) {
if (!findSlot(member)?.reason?.always && (!isSupersetSources(member, partner) || hasReadIntermediate(member, partner, /* @__PURE__ */ new Set()))) {
if (member.section !== section) addOwnerReason(section, member.section, mergeSources(member.sources, partner.sources));
addReason(ensureSlot(member), partner.sources);
}
}
function hasReadIntermediate(member, partner, seen) {
return some(getBindingsDerivedFrom(member), (from) => {
if (seen.has(from) || !sharesSources(from, partner)) return false;
seen.add(from);
if (bindingUtil.has(partner.sources.state, from) || bindingUtil.has(partner.sources.param, from)) return false;
return !!findSlot(from)?.reason || hasReadIntermediate(from, partner, seen);
});
}
function withoutOwnSources(closure, sources) {
const own = closure.sources;
if (!sources || !own || hasReadIntermediate(closure, closure, /* @__PURE__ */ new Set())) return sources;
return withSources(sources, bindingUtil.difference(sources.state, own.state), bindingUtil.filter(sources.param, (binding) => !someUpToAliasRoot(binding, isInParams, own.param)));
}
function getBranchExprReason(section) {
const { derives, branchExpr } = section;
if (derives) {
let reason = mergeSources(getRendererReason(section) || void 0, getSourcesForDerived(derives));
forEach(section.callSections, (callSection) => {
reason = mergeSources(reason, getBranchExprReasonUntil(callSection, isSameOrAncestorSection(section, callSection) ? section : section.parent));
});
return reason;
}
return branchExpr ? getSourcesForExpr(branchExpr) : ALWAYS;
}
function getBranchExprReasonUntil(section, ancestor) {
let reason;
for (let cur = section; cur !== ancestor; cur = cur.parent) reason = mergeSources(reason, getBranchExprReason(cur));
return reason;
}
function addClosureReasons(section) {
forEach(section.referencedClosures, (closure) => {
const sourceSection = closure.section;
const branchesReason = getBranchExprReasonUntil(section, sourceSection);
addReason(ensureSlot(closure), branchesReason?.always ? branchesReason : withoutOwnSources(closure, branchesReason));
if (isDynamicClosure(section, closure)) {
addOwnerReason(section, sourceSection, branchesReason);
if (closure.sources && closure.type !== 5) {
addReason(ensureSlot(closure, 2), closure.sources);
if (getDynamicClosureIndex(closure, section)) addReason(ensureSlot(closure, 3, section), closure.sources);
}
}
});
}
function addRegisteredFnReasons(fnReadsByExpression) {
addFunctionReasons();
for (const exprFnReads of fnReadsByExpression.values()) for (const fn of exprFnReads.keys()) {
const reason = fn.reason;
if (reason) {
const addReadReason = (binding) => {
addReason(ensureSlot(binding), reason);
if (binding.section !== fn.section) addOwnerReason(fn.section, binding.section, reason);
};
forEach(getReferencedBindingsInFunction(fn), addReadReason);
forEach(getConstantBindingsInFunction(fn), addReadReason);
}
}
}
const UNREAD = {
reason: void 0,
reads: void 0
};
const ALWAYS_READ = {
reason: ALWAYS,
reads: void 0
};
let extraReaders;
let bindingReaders;
resetReaders();
function resetReaders() {
extraReaders = createCyclicMemo(computeExtraReaders, UNREAD);
bindingReaders = createCyclicPathMemo(computeBindingReaders, UNREAD);
}
function getReasonForBinding(binding, properties) {
return bindingReaders(binding, properties).reason;
}
function getReasonForExpr(extra) {
return extra.isEffect ? ALWAYS : extraReaders(extra).reason;
}
function landsRetained(extra) {
if (extra.retained) return true;
if (!extra.isEffect) {
const { reads } = extraReaders(extra);
if (reads) {
for (const read of reads) if (read.retained) return true;
}
}
return false;
}
function computeExtraReaders(extra) {
return readersOfDerives(extra, void 0);
}
function readersOfDerives(extra, part, properties) {
if (extra === (0, _marko_compiler_babel_utils.getProgram)().node.extra?.section.returnValueExpr) return ALWAYS_READ;
let readers = UNREAD;
forEach(extra.derives, (binding) => {
if (!isPartOf(binding, part)) readers = mergeReaders(readers, readersOfDerived(extra, binding, part, properties));
});
return readers;
}
function readersOfDerived(extra, binding, part, properties) {
const linked = bindingReaders(binding, getDerivedPath(extra, binding, part, properties));
const exprs = extra.callSiteExprs;
return linked.reason && exprs ? {
reason: mapParamReason(binding.section.program, linked.reason, exprs, true),
reads: linked.reads
} : linked;
}
function getDerivedPath(extra, binding, part, properties) {
if (properties === void 0 || properties === true || !part) return true;
if (isReferenceTo(extra, part) || bindingUtil.has(extra.spreadFrom, part)) return properties;
const iterates = binding.iterates;
if (iterates && isReferenceTo(iterates.expr, part)) {
if (iterates.type === "in") return concat("1", rest(properties));
return concat("0", isIndexProperty(first(properties)) ? rest(properties) : properties);
}
return true;
}
function isReferenceTo(extra, binding) {
const { read } = extra;
return !!read && read.props === void 0 && getCanonicalBinding(read.binding) === getCanonicalBinding(binding);
}
function isPartOf(binding, value) {
return !!value && binding.aliasOf === value && !isDirectAlias(binding);
}
function computeBindingReaders(binding, properties) {
const head = properties === true || properties === void 0 ? void 0 : first(properties);
const reason = findSlot(binding)?.reason;
let readers = reason ? {
reason,
reads: void 0
} : UNREAD;
const aliased = binding.aliasOf;
if (properties !== true && aliased) readers = mergeReaders(readers, bindingReaders(aliased, properties === void 0 ? binding.property : concat(binding.property, properties)));
for (const expr of binding.reads.keys()) {
if (expr.isEffect) {
if (!(head === "content" && expr.rendersContent && bindingUtil.has(expr.spreadFrom, binding))) readers = mergeReaders(readers, ALWAYS_READ);
continue;
}
readers = mergeReaders(withLandingRead(readers, expr), readersOfDerives(expr, binding, properties));
}
for (const alias of binding.aliases) readers = mergeReaders(readers, bindingReaders(alias, properties));
if (properties === void 0) return readers;
if (properties === true) {
for (const propBinding of binding.propertyAliases.values()) readers = mergeReaders(readers, bindingReaders(propBinding, true));
return readers;
}
const property = first(properties);
if (propsUtil.has(binding.excludeProperties, property)) return UNREAD;
readers = mergePropertyReaders(readers, binding, property, properties);
for (const alias of binding.aliases) readers = mergePropertyReaders(readers, alias, property, properties);
return readers;
}
function mergePropertyReaders(readers, owner, property, properties) {
const propBinding = owner.propertyAliases.get(property);
return propBinding ? mergeReaders(readers, bindingReaders(propBinding, rest(properties))) : readers;
}
function mergeReaders(a, b) {
if (a === UNREAD) return b;
if (b === UNREAD) return a;
const reason = mergeSources(a.reason, b.reason);
const reads = unionReads(a.reads, b.reads);
if (reason === a.reason && reads === a.reads) return a;
if (reason === b.reason && reads === b.reads) return b;
return {
reason,
reads
};
}
function withLandingRead(readers, read) {
return readers.reads?.has(read) ? readers : {
reason: readers.reason,
reads: new Set(readers.reads).add(read)
};
}
function unionReads(a, b) {
if (!a || !b || a === b) return a || b;
let result;
for (const read of b) if (!a.has(read)) (result ??= new Set(a)).add(read);
return result || a;
}
//#endregion
//#region src/translator/util/sections.ts
const sectionUtil = new Sorted(function compareSections(a, b) {
return a.id - b.id;
});
function ensureBodySection(path) {
const extra = path.node.extra ??= {};
let section = extra.section;
if (!section && (path.type === "Program" || path.get("body").length)) {
const parentTag = path.parentPath?.isMarkoTag() ? path.parentPath : void 0;
const parentSection = path.parentPath ? ensureSection(path.parentPath) : void 0;
const sectionName = parentTag ? generateUid((isCoreTagName(parentTag, "define") && _marko_compiler.types.isIdentifier(parentTag.node.var) ? parentTag.node.var.name : parentTag.get("name").toString()) + "_content") : "";
const programExtra = (0, _marko_compiler_babel_utils.getProgram)().node.extra ??= {};
const sections = programExtra.sections ??= [];
section = extra.section = {
id: sections.length,
name: sectionName,
loc: parentTag?.node.name.loc || void 0,
depth: parentSection ? parentSection.depth + 1 : 0,
parent: parentSection,
children: [],
program: void 0,
params: void 0,
localClosures: void 0,
referencedClosures: void 0,
bindings: void 0,
hoisted: void 0,
selector: void 0,
intersections: void 0,
isHoistThrough: void 0,
slots: void 0,
reason: void 0,
paramReasonGroups: void 0,
returnValueExpr: void 0,
content: getContentInfo(path),
branchExpr: void 0,
callSections: void 0,
derives: void 0,
dropped: !!extra.dropped,
hasAbortSignal: false,
abortSignalExprs: 0,
readsOwner: false,
hasSetupWork: false,
branch: void 0,
structure: parentSection && !parentSection.structure ? null : []
};
if (parentSection) {
section.program = parentSection.program;
parentSection.children.push(section);
} else section.program = section;
sections.push(section);
}
return section;
}
function ensureSection(path) {
let cur = path;
while (true) {
if (cur.type === "Program" || cur.type === "MarkoTagBody" && !cur.node.attributeTags && !getTagFacts(cur.parentPath).inlineBody) return ensureBodySection(cur);
cur = cur.parentPath;
}
}
function getSectionForBody(body) {
return body.node.extra?.section;
}
function removeDroppedContent(tag) {
if (tag.node.body.extra?.dropped) tag.node.body.body = [];
}
function getSection(path) {
let section;
let currentPath = path;
while ((section = currentPath.node.extra?.section) === void 0) currentPath = currentPath.parentPath;
return section;
}
const [getScopeIdIdentifier] = createSectionState("scopeIdIdentifier", (section) => generateUidIdentifier(`scope${section.id}_id`));
const [getBranchRendererArgs, setBranchRendererArgs] = createSectionState("rendererExpression");
function forEachSection(fn) {
const { sections } = (0, _marko_compiler_babel_utils.getProgram)().node.extra;
sections?.forEach(fn);
}
function getDynamicTagContentClosures(section) {
if (section.branchExpr?.tagNameType === 2) return getClosuresFromAbove(section, section);
}
function getClosuresFromAbove(section, top) {
let closures = bindingUtil.leadingRun(section.referencedClosures, bindingToSection, sectionUtil.compare, top);
for (const child of section.children) closures = bindingUtil.union(closures, getClosuresFromAbove(child, top));
return closures;
}
function forEachAncestorSection(from, to, fn, arg) {
for (let cur = from; cur !== to && cur.parent; cur = cur.parent) fn(cur, arg);
}
function forEachSectionReverse(fn) {
const { sections } = (0, _marko_compiler_babel_utils.getProgram)().node.extra;
for (let i = sections.length; i--;) fn(sections[i]);
}
function getContentInfo(path) {
const body = path.get("body");
for (let endIndex = body.length; endIndex--;) {
const end = body[endIndex];
const endType = getNodeContentType(end, "endType");
if (endType !== null) {
for (let startIndex = 0; startIndex < endIndex; startIndex++) {
const startType = getNodeContentType(body[startIndex], "startType");
if (startType !== null) return {
startType,
endType,
singleChild: false
};
}
const inlined = end.type === "MarkoTag" && getInlinedSection(end);
return inlined ? inlined.content : {
startType: endType,
endType,
singleChild: endType !== 1
};
}
}
return null;
}
function getNodeContentType(path, edge) {
switch (path.type) {
case "MarkoText": return 4;
case "MarkoPlaceholder": return 2;
case "MarkoScriptlet":
case "MarkoComment":
case "ImportDeclaration":
case "ExportAllDeclaration":
case "ExportNamedDeclaration":
case "ExportDefaultDeclaration": return null;
case "MarkoTag": {
const tag = path;
const tagSection = getInlinedSection(tag);
if (!tagSection) return getTagContentType(tag);
return tagSection.content ? tagSection.content[edge] : null;
}
}
return 1;
}
function getInlinedSection(tag) {
return tag.node.extra?.defineBodySection || !isCoreTag(tag) && analyzeTagNameType(tag) === 1 && !tag.node.extra.tagNameLoad && (0, _marko_compiler_babel_utils.loadFileForTag)(tag).ast.program.extra.section;
}
function getRendererReason(section) {
if (isOptionalBranch(section)) return false;
if (section.branchExpr?.tagNameType === 0) return false;
const { derives } = section;
if (derives) return reduce(derives.binding, (reasons, binding) => {
const reason = getReasonForBinding(binding, derives.properties);
return mergeSources(reasons, reason && (derives.exprs ? mapParamReason(binding.section.program, reason, derives.exprs, true) : mapParamReason(section.program, reason, void 0, false)));
}) || false;
return ALWAYS;
}
function isOptionalBranch(section) {
return !!section.branch?.optional;
}
function isInParentSection(binding, section) {
return section.parent?.id === binding.section.id;
}
function isDirectClosure(section, closure) {
return !!isOptionalBranch(section) && isInParentSection(closure, section);
}
function isDynamicClosure(section, closure) {
return !isDirectClosure(section, closure);
}
function getDynamicClosureIndex(closure, closureSection) {
let index = 0;
find(closure.closureSections, (section) => {
if (section === closureSection) return true;
if (isDynamicClosure(section, closure)) index++;
return false;
});
return index;
}
function getDirectClosures(section) {
if (isOptionalBranch(section)) return bindingUtil.range(section.referencedClosures, bindingToSection, sectionUtil.compare, section.parent);
}
function isSameOrAncestorSection(section, other) {
do
if (other === section) return true;
while (other = other.parent);
return false;
}
function getCommonSection(section, other) {
let a = section;
let b = other;
while (a !== b) if (a.id > b.id) a = a.parent;
else b = b.parent;
return a;
}
function ensureSectionReasonGroups(section) {
ensureReasonGroups(section.reason);
forEach(section.slots, ensureSlotReasonGroups);
}
function ensureSlotReasonGroups(slot) {
ensureReasonGroups(slot.reason);
}
function ensureReasonGroups(reason) {
if (isConditionalReason(reason)) forEachParamGroup(reason.param, ensureParamReasonGroup);
}
function ensureParamReasonGroup(section, group) {
const { paramReasonGroups } = section;
const groups = paramReasonGroups ? addSorted(compareReferences, paramReasonGroups, group) : [group];
if (groups !== paramReasonGroups) setParamReasonGroups(section, groups);
}
function getParamReasonGroupIndex(section, group) {
const index = section.paramReasonGroups && findIndexSorted(compareReferences, section.paramReasonGroups, group);
if (index === void 0 || index === -1) throw new Error("Invalid compiler state, cannot ask for a param reason group that was not analyzed.");
return index;
}
function forEachParamGroup(params, fn) {
bindingUtil.forEachRun(params, bindingToSection, sectionUtil.compare, fn);
}
function reduceParamGroups(params, fn, initial) {
return bindingUtil.reduceRuns(params, bindingToSection, sectionUtil.compare, fn, initial);
}
function bindingToSection(binding) {
return binding.section;
}
function setReadsOwner(from, to) {
forEachAncestorSection(from, to, markReadsOwner, void 0);
}
function markReadsOwner(section) {
section.readsOwner = true;
}
//#endregion
//#region src/translator/util/reasons.ts
function addReason(slot, reason) {
if (reason) {
const curReason = slot.reason;
const newReason = mergeSources(curReason, reason);
if (curReason !== newReason) setSlotReason(slot, newReason);
}
}
function addAlwaysReason(binding) {
addReason(ensureSlot(binding), ALWAYS);
}
function addReasonExprs(slot, expr) {
slot.reasonExprs = concat(slot.reasonExprs, expr);
}
function addOwnerReason(from, to, reason) {
if (reason) forEachAncestorSection(from, to, addOwnerSlotReason, reason);
}
function addOwnerSlotReason(section, reason) {
addReason(ensureSectionSlot(section, 7), reason);
}
function isConditionalReason(reason) {
return !!reason && !reason.always && !reason.state;
}
function isUnconditionalReason(reason) {
return !!reason && !isConditionalReason(reason);
}
function isStateReason(reason) {
return !!reason && !reason.always && !!reason.state;
}
function getSourcesForExpr(expr) {
const root = getCanonicalExtra(expr);
return isReferencedExtra(root) ? getSourcesForRef(getReferencedBindings(root)) : void 0;
}
function getSourcesForExprs(exprs) {
if (exprs) {
if (exprs === true) return ALWAYS;
return reduce(exprs, mergeExprSources);
}
}
function getSourcesForRef(ref) {
return reduce(ref, mergeBindingSources);
}
function getSourcesForDerived({ binding, exprs, properties }) {
if (exprs) return reduce(binding, (sources, binding) => mergeSources(sources, getSourcesForExprs(mapParamBindingToExpr(exprs, getDeepestPropertyAlias(binding, properties)))));
}
function mergeExprSources(sources, expr) {
return mergeSources(sources, getSourcesForExpr(expr));
}
function mergeBindingSources(sources, binding) {
return mergeSources(sources, binding.sources);
}
function mapParamReason(program, reason, exprs, ownParams) {
let mapped;
const params = bindingUtil.filter(reason.param, (param) => {
if (param.section.program === program !== ownParams) return true;
mapped = exprs ? mergeSources(mapped, getSourcesForExprs(mapParamBindingToExpr(exprs, param))) : ALWAYS;
return false;
});
const state = bindingUtil.filter(reason.state, isOwnBinding);
const foreignState = state !== reason.state;
if (params === reason.param && !foreignState) return reason;
return mergeSources(mergeSources(mapped, withSources(reason, state, params)), foreignState ? ALWAYS : void 0);
}
function mapParamReasonToExpr(exprs, reason) {
if (reason) {
if (reason === true) return true;
const result = /* @__PURE__ */ new Set();
forEach(reason, (prop) => {
forEach(mapParamBindingToExpr(exprs, prop), (expr) => {
result.add(expr);
});
});
return fromIter(result);
}
}
function mapParamBindingToExpr(exprs, binding) {
const isWholeAlias = binding.property === void 0 && binding.aliasOf !== void 0;
const curExpr = getKnownExprsAt(exprs, isWholeAlias ? binding.aliasOf : binding);
if (isWholeAlias) {
let result = curExpr.value;
if (curExpr.known) {
for (const key in curExpr.known) if (!propsUtil.has(binding.excludeProperties, key)) result = concat(result, curExpr.known[key].value);
}
return result;
}
return curExpr.value;
}
function getKnownExprsAt(exprs, binding) {
const aliased = binding.aliasOf;
if (!aliased) return exprs;
const known = getKnownExprsAt(exprs, aliased);
return binding.property === void 0 || !known.known ? known : known.known[binding.property] ?? { value: known.value };
}
function applyReasonExprs(section) {
forEach(section.slots, applySlotExprs);
}
function applySlotExprs(slot) {
addReason(slot, getSourcesForExprs(slot.reasonExprs));
}
function mergeSlotReasons(section) {
section.reason = reduce(section.slots, mergeSlotReason, section.reason);
}
function mergeSlotReason(sectionReason, slot) {
return mergeSources(sectionReason, slot.reason);
}
function getNodeReasons(section) {
return reduce(section.slots, addNodeReason, void 0);
}
function addNodeReason(reasons, slot) {
return slot.reason && slot.kind === 0 && slot.owner.type === 0 ? sourcesUtil.add(reasons, slot.reason) : reasons;
}
let reasonsVersion = 0;
function getReasonsVersion() {
return reasonsVersion;
}
function setSlotReason(slot, reason) {
if (!isSameSources(slot.reason, reason)) reasonsVersion++;
slot.reason = reason;
}
function setParamReasonGroups(section, groups) {
reasonsVersion++;
section.paramReasonGroups = groups;
}
function isSameSources(a, b) {
return !!a && compareSources(a, b) === 0;
}
//#endregion
//#region src/translator/util/references.ts
const kReferencedBindings = Symbol("referenced bindings");
const kLazyBindings = Symbol("lazy bindings");
const kReferencedBindingsInFunction = Symbol("referenced bindings in function");
const kConstantBindingsInFunction = Symbol("constant bindings in function");
function ensureLocalClosure(local, section) {
while (section.parent !== local.section) section = section.parent;
let closure = local.localClosures?.get(section);
if (!closure) {
closure = createBinding(local.name, 2, section, void 0, void 0, void 0, local.loc);
closure.localOf = local;
(local.localClosures ??= /* @__PURE__ */ new Map()).set(section, closure);
}
return closure;
}
function isTagVarUsed(tag) {
for (const name in _marko_compiler.types.getBindingIdentifiers(tag.node.var)) {
const binding = tag.scope.getBinding(name);
if (binding?.referencePaths.length || binding?.constantViolations.length) return true;
}
return false;
}
function trackDomVarReferences(tag, binding) {
const tagVar = tag.node.var;
if (!tagVar) return;
const babelBinding = tag.scope.getBinding(tagVar.name);
const section = ensureSection(tag);
binding.originalName = tagVar.name;
if (babelBinding.constantViolations.length) for (const ref of babelBinding.constantViolations) throw ref.type === "MarkoTag" ? ref.get("var").buildCodeFrameError(`Duplicate declaration of \`${binding.originalName}\`.`) : ref.buildCodeFrameError(`\`${binding.originalName}\` is a [tag variable](https://markojs.com/docs/reference/language#tag-variables) on a native element (an element reference) and cannot be assigned to.`);
for (const ref of babelBinding.referencePaths) {
assertReferencedInRender(ref, tagVar.name);
const refSection = ensureSection(ref);
const invoked = isInvokedFunction(ref);
const hoisted = isReferenceHoisted(babelBinding.path, ref) ? getCommonSection(refSection, binding.section) : false;
const getter = !invoked || hoisted && hoisted !== binding.section ? {
hoisted,
invoked
} : void 0;
setReferencesScope(ref);
addReadToExpression(ref, binding, getter);
if (!getter?.hoisted && refSection !== section) {
setReadsOwner(refSection, section);
addOwnerReason(refSection, section, ALWAYS);
}
}
return binding;
}
function trackVarReferences(tag, type, aliased) {
const tagVar = tag.node.var;
if (tagVar) {
const section = ensureSection(tag);
let target = aliased && getCanonicalBinding(aliased);
if (target) {
const { excludeProperties, restOffset } = target;
if (isRest(target)) target = target.aliasOf;
createBindingsAndTrackReferences(tagVar, target.type, tag.scope, section, target, void 0, excludeProperties, restOffset, false);
return target;
}
createBindingsAndTrackReferences(tagVar, type, tag.scope, section, void 0, void 0, void 0);
return tagVar.extra?.binding;
}
}
function trackParamsReferences(body, type) {
const params = body.node.params;
if (body.node.body.length && params.length) {
const section = ensureSection(body);
const paramsBinding = (body.node.extra ??= {}).binding = createBinding(generateUid("params"), type, section, void 0, void 0, void 0, params[0].loc);
paramsBinding.nullable = false;
const bodySection = getSectionForBody(body);
if (bodySection) bodySection.params = paramsBinding;
for (let i = 0; i < params.length; i++) {
const param = params[i];
if (param.type === "RestElement") assertRestNotAssigned(body.scope, param.argument);
if (i === 0 && param.type === "RestElement" && param.argument.type === "Identifier") {
const { argument } = param;
paramsBinding.name = argument.name;
paramsBinding.declared = true;
(argument.extra ??= {}).binding = paramsBinding;
trackReferencesForBinding(body.scope.getBinding(argument.name), paramsBinding);
} else if (param.type === "RestElement") createBindingsAndTrackReferences(param.argument, type, body.scope, section, paramsBinding, void 0, i > 0 ? addNumericPropertiesUntil(void 0, i) : void 0, i);
else if (_marko_compiler.types.isLVal(param)) createBindingsAndTrackReferences(param, type, body.scope, section, paramsBinding, i + "", void 0);
}
return paramsBinding;
}
}
function getMarkoRootAsTag(path) {
const tag = path.isMarkoTag() ? path : getMarkoRoot(path)?.parentPath;
if (tag?.isMarkoTag()) return tag;
}
function isReferenceInOwnBody(bindingPath, reference) {
const tag = getMarkoRootAsTag(bindingPath);
if (!tag) return false;
const body = tag.get("body");
let cur = reference;
while (cur) {
if (cur === body) return true;
cur = cur.parentPath;
}
return false;
}
function isReferenceHoisted(bindingPath, reference) {
const tag = getMarkoRootAsTag(bindingPath);
if (!tag) return false;
const body = tag.parentPath;
let cur = reference;
while (cur) {
if (cur.parentPath === body) return +tag.key > +cur.key;
cur = cur.parentPath;
}
return true;
}
function trackReferencesForBinding(babelBinding, binding) {
const { referencePaths, constantViolations } = babelBinding;
for (const ref of referencePaths) {
const markoRoot = getMarkoRoot(ref);
assertReferencedInRender(ref, ref.node.name, markoRoot);
const refSection = ensureSection(ref);
if (!binding.declared && !isRest(binding)) {
const root = getNearestDeclared(binding);
binding.declared = !!root && ref.scope.getBinding(root.name) !== babelBinding.scope.getBinding(root.name);
}
if (markoRoot?.type === "MarkoAttribute" && markoRoot.parentPath === babelBinding.path && !getFnRoot(ref)) throw ref.buildCodeFrameError(`\`${ref.node.name}\` is the [tag variable](https://markojs.com/docs/reference/language#tag-variables) this tag declares, so its own attributes cannot read it.`);
else if (isReferenceHoisted(babelBinding.path, ref)) {
const invoked = isInvokedFunction(ref);
if (invoked) setReferencesScope(ref);
addReadToExpression(ref, binding, {
hoisted: getCommonSection(refSection, binding.section),
invoked
});
} else if (binding.type !== 3 || refSection !== binding.section) trackReference(ref, binding);
else {
const fnRoot = getFnRoot(ref);
if (fnRoot) {
const fnExtra = fnRoot.node.extra ??= {};
fnExtra.referencedLocalBindingsInFunction = bindingUtil.add(fnExtra.referencedLocalBindingsInFunction, binding);
const refExtra = ref.node.extra ??= {};
refExtra.section = refSection;
refExtra.read = createResolvedRead(binding, void 0);
refExtra.read.localFn = fnExtra;
}
}
}
for (const ref of constantViolations) {
if (ref.type === "MarkoTag") throw ref.get("var").buildCodeFrameError(`Duplicate declaration of \`${binding.name}\`.`);
assertReferencedInRender(ref, binding.name);
if (isReferenceHoisted(babelBinding.path, ref)) throw ref.buildCodeFrameError(`\`${binding.name}\` is declared by a tag below this assignment; a [tag variable](https://markojs.com/docs/reference/language#tag-variables) can only be assigned below its declaration. Move the declaring tag above this code.`);
if (ref.isUpdateExpression()) trackAssignment(ref.get("argument"), binding);
else if (ref.isAssignmentExpression()) {
trackAssignment(ref.get("left"), binding);
if (ref.node.operator !== "=") {
const left = ref.get("left");
if (left.isIdentifier()) trackReference(left, binding);
}
} else if (ref.isForXStatement()) throw ref.get("left").buildCodeFrameError(`\`${binding.name}\` is a [tag variable](https://markojs.com/docs/reference/language#tag-variables), so a \`for...${ref.isForOfStatement() ? "of" : "in"}\` cannot assign to it. Loop into a local variable and assign \`${binding.name}\` from it instead.`);
}
}
function trackAssignment(assignment, binding) {
const fnParent = getFnParent(assignment);
if (!fnParent) throw assignment.buildCodeFrameError(`\`${binding.name}\` is a tag ${binding.type === 2 ? "parameter" : "variable"} and can only be assigned within a script or function.`);
if (binding.type === 3) throw assignment.buildCodeFrameError(`\`${binding.name}\` is a tag parameter and cannot be assigned to.`);
const assigned = getCanonicalBinding(binding);
const fnRoot = getFnRoot(fnParent);
const fnExtra = fnRoot && (fnRoot.node.extra ??= {});
const section = ensureSection(assignment);
setReferencesScope(assignment);
forEachIdentifierPath(assignment, (id) => {
if (id.node.name === binding.name) {
const idExtra = id.node.extra ??= {};
idExtra.assignment = assigned;
idExtra.section = section;
idExtra.exprRoot = getExprRoot(fnRoot || assignment).node.extra ??= {};
idExtra.fnRoot = fnExtra;
getAssignments().push(idExtra);
if (fnExtra) {
fnExtra.section = section;
fnExtra.exprRoot = idExtra.exprRoot;
}
if (assigned.aliasOf && assigned.property !== void 0) {
if (assigned.aliasOf === assigned.section.params) throw assignment.buildCodeFrameError(`\`${binding.name}\` is a tag parameter and cannot be assigned to.`);
const changePropName = assigned.property + "Change";
const changeBinding = assigned.aliasOf.propertyAliases.get(changePropName) || createBinding(generateUid(changePropName), assigned.type, assigned.section, assigned.aliasOf, changePropName, void 0, id.node.loc, assigned.declared);
idExtra.assignmentTo = changeBinding;
addReadToExpression(id, changeBinding, void 0);
}
}
});
}
function assertReferencedInRender(ref, name, markoRoot = getMarkoRoot(ref)) {
if (markoRoot && isStatic(markoRoot)) throw ref.buildCodeFrameError(`\`${name}\` exists only while the template renders, so module level code ([\`static\`, \`server\` and \`client\`](https://markojs.com/docs/reference/language#static) and [\`export\`](https://markojs.com/docs/reference/language#export) statements), which runs once as the template loads, cannot reference it. Reference it in the template instead, passing it to module level functions as an argument.`);
}
function setReferencesScope(path) {
const fnRoot = getFnRoot(path);
if (fnRoot) (fnRoot.node.extra ??= {}).referencesScope = true;
}
const [getGlobalBinding] = createProgramState(() => createBinding("$global", 6, ensureSection((0, _marko_compiler_babel_utils.getProgram)())));
function trackGlobalReference(path) {
trackReference(path, getGlobalBinding());
}
function createBindingsAndTrackReferences(lVal, type, scope, section, aliased, property, excludeProperties, restOffset, declared = true) {
switch (lVal.type) {
case "AssignmentPattern":
createBindingsAndTrackReferences(lVal.left, type, scope, section, aliased, property, excludeProperties, restOffset, declared);
break;
case "Identifier": {
const binding = (lVal.extra ??= {}).binding = createBinding(lVal.name, type, section, aliased, property, excludeProperties, lVal.loc, declared, restOffset);
trackReferencesForBinding(scope.getBinding(lVal.name), binding);
break;
}
case "ObjectPattern": {
const patternBinding = ensurePatternBinding(lVal, type, section, aliased, property, excludeProperties);
const hasRest = lVal.properties.at(-1)?.type === "RestElement";
const declaresPattern = declared || hasRest;
for (const prop of lVal.properties) if (prop.type === "RestElement") {
assertRestNotAssigned(scope, prop.argument);
createBindingsAndTrackReferences(prop.argument, type, scope, section, patternBinding, void 0, excludeProperties, void 0, declaresPattern);
} else {
let key;
if (!prop.computed && prop.key.type === "Identifier") key = prop.key.name;
else if (prop.key.type === "StringLiteral") key = prop.key.value;
else throw scope.path.hub.buildError(prop.key, "Only identifier and string literal keys are supported when destructuring.");
if (hasRest) excludeProperties = propsUtil.add(excludeProperties, key);
if (_marko_compiler.types.isLVal(prop.value)) createBindingsAndTrackReferences(prop.value, type, scope, section, patternBinding, key, void 0, void 0, declaresPattern);
}
break;
}
case "ArrayPattern": {
const patternBinding = ensurePatternBinding(lVal, type, section, aliased, property, excludeProperties);
const declaresPattern = declared || lVal.elements.at(-1)?.type === "RestElement";
let index = (restOffset || 0) - 1;
for (const element of lVal.elements) {
index++;
if (element) {
if (element.type === "RestElement") {
assertRestNotAssigned(scope, element.argument);
excludeProperties = index > 0 ? addNumericPropertiesUntil(excludeProperties, index) : void 0;
createBindingsAndTrackReferences(element.argument, type, scope, section, patternBinding, void 0, excludeProperties, index, declaresPattern);
} else if (_marko_compiler.types.isLVal(element)) {
if (element.type === "Identifier") {
const assignment = getAssignment(scope, element.name);
if (assignment) throw assignment.buildCodeFrameError(`\`${element.name}\` comes from array destructuring, which has no [change handler](https://markojs.com/docs/reference/language#shorthand-change-handlers-two-way-binding), so it cannot be assigned to. Destructure it from an object instead, where assigning it calls the object's \`${element.name}Change\`.`);
}
createBindingsAndTrackReferences(element, type, scope, section, patternBinding, `${index}`, void 0, void 0, declaresPattern);
}
}
}
break;
}
}
}
function ensurePatternBinding(lVal, type, section, aliased, property, excludeProperties) {
const patternBinding = (property ? aliased.propertyAliases.get(property) : aliased) || ((lVal.extra ??= {}).binding = createBinding(generateUid(property || "pattern"), type, section, aliased, property, excludeProperties, lVal.loc));
if (patternBinding.section === section) patternBinding.nullable = false;
return patternBinding;
}
function isAssignment(ref) {
return ref.type !== "MarkoTag";
}
function getAssignment(scope, name) {
return scope.getBinding(name).constantViolations.find(isAssignment);
}
function assertRestNotAssigned(scope, rest) {
if (rest.type === "Identifier") {
const assignment = getAssignment(scope, rest.name);
if (assignment) throw assignment.buildCodeFrameError(`\`${rest.name}\` is a rest element, which has no [change handler](https://markojs.com/docs/reference/language#shorthand-change-handlers-two-way-binding) to receive a new value, so it cannot be assigned to. Assign the properties of the value it is destructured from instead.`);
}
}
function trackReference(referencePath, binding) {
let root = referencePath;
let reference = binding;
while (true) {
const { parent } = root;
if (!_marko_compiler.types.isMemberExpression(parent) && !_marko_compiler.types.isOptionalMemberExpression(parent)) break;
let prop = getMemberExpressionPropString(parent);
if (isAssignedMember(root.parentPath)) {
const object = getCanonicalBinding(reference);
if (isRest(object)) throw root.parentPath.buildCodeFrameError(`\`${referencePath.node.name}\` is a rest element, a copy rebuilt from the value it is destructured from whenever that changes, so assigning its members would be lost. Assign the property on that value instead, or keep your own copy in a \`<let>\`.`);
addAssignedProperty(object, prop);
break;
}
if (prop === void 0) break;
if (reference.aliasOf && isRest(reference)) {
if (reference.restOffset !== void 0) {
if (isIndexProperty(prop)) {
prop = `${+prop + reference.restOffset}`;
reference = reference.aliasOf;
}
} else if (!propsUtil.has(reference.excludeProperties, prop)) reference = reference.aliasOf;
}
if (isInvokedFunction(root.parentPath) && !isEventOrChangeHandler(prop)) break;
root = root.parentPath;
reference = ensurePropertyAlias(reference, prop);
}
if (reference.type === 3) reference = ensureLocalClosure(reference, ensureSection(root));
(referencePath.node.extra ??= {}).binding = binding;
addReadToExpression(root, reference, void 0);
}
function isAssignedMember(member) {
const { node, parent } = member;
switch (parent.type) {
case "AssignmentExpression":
case "AssignmentPattern":
case "ForInStatement":
case "ForOfStatement": return parent.left === node;
case "UnaryExpression": return parent.operator === "delete";
case "UpdateExpression":
case "ArrayPattern":
case "RestElement": return true;
case "ObjectProperty": return parent.value === node && _marko_compiler.types.isObjectPattern(member.parentPath.parent);
default: return false;
}
}
function mergeReferences(section, target, nodes) {
return mergeInto(section, target.extra ??= {}, nodes);
}
function mergeTagReferences(section, tag) {
return mergeReferences(section, tag, getAllTagReferenceNodes(tag));
}
function mergeReferenceGroup(section, nodes) {
return mergeInto(section, {}, nodes);
}
function mergeInto(section, extra, nodes) {
const targetExtra = extra;
const readsByExpression = getReadsByExpression();
const fnReadsByExpression = getFunctionReadsByExpression();
let reads = readsByExpression.get(targetExtra);
let exprFnReads = fnReadsByExpression.get(targetExtra);
let { isEffect, retained } = targetExtra;
for (const node of nodes) {
if (!node) continue;
const extra = node.extra ??= {};
extra.merged = targetExtra;
retained ||= extra.retained;
if (isReferencedExtra(extra)) {
const additionalReads = readsByExpression.get(extra);
const additionalExprFnReads = fnReadsByExpression.get(extra);
isEffect ||= extra.isEffect;
if (additionalReads) {
forEach(additionalReads, (read) => {
const bindingReads = read.binding.reads;
bindingReads.delete(extra);
bindingReads.set(targetExtra, push(bindingReads.get(targetExtra), read));
});
reads = concat(reads, additionalReads);
readsByExpression.delete(extra);
}
if (additionalExprFnReads) {
if (exprFnReads) for (const [key, value] of additionalExprFnReads) exprFnReads.set(key, value);
else fnReadsByExpression.set(targetExtra, exprFnReads = new Map(additionalExprFnReads));
}
} else if (extra?.dropped)
/* v8 ignore next -- a dropped reference is never merged into another */
throw new Error("Cannot merged a dropped reference.");
}
readsByExpression.set(targetExtra, reads);
targetExtra.isEffect = isEffect;
targetExtra.retained = retained;
targetExtra.spreadFrom = getSpreadOnlyBindings(reads);
targetExtra.section = section;
return targetExtra;
}
function getSpreadOnlyBindings(reads) {
if (!some(reads, isSpreadRead)) return;
let spread;
let other;
forEach(reads, (read) => {
if (isSpreadRead(read)) spread = bindingUtil.add(spread, read.binding);
else other = bindingUtil.add(other, read.binding);
});
return bindingUtil.difference(spread, other);
}
function isSpreadRead(read) {
return read.extra.spreadFrom === read.binding;
}
function setDerivedFrom(binding, expr, exprs) {
if (isOwnBinding(binding)) {
const prev = binding.derivedFrom;
binding.derivedFrom = expr === true ? void 0 : prev ? expr ? concat(prev, expr) : prev : expr || false;
}
if (expr && expr !== true) forEach(expr, (expr) => {
expr.derives = push(expr.derives, binding);
if (exprs) expr.callSiteExprs = exprs;
});
}
const [getAssignments] = createProgramState(() => []);
const [getReadsByExpression] = createProgramState(() => /* @__PURE__ */ new Map());
const [getFunctionReadsByExpression] = createProgramState(() => /* @__PURE__ */ new Map());
const [getReferenceFinalizers] = createProgramState(() => []);
function onFinalizeReferences(finalize) {
getReferenceFinalizers().push(finalize);
}
function addRead(exprExtra, extra, binding, section, getter) {
const readsByExpression = getReadsByExpression();
const read = {
binding,
extra,
getter,
inOwnBody: false,
comparedTo: void 0,
deferred: false,
fnRoot: void 0
};
if (section.dropped) return read;
binding.reads.set(exprExtra, push(binding.reads.get(exprExtra), read));
exprExtra.section = section;
readsByExpression.set(exprExtra, push(readsByExpression.get(exprExtra), read));
return read;
}
function dropNodes(node) {
forEachNodeExtra(node, dropExtra);
}
function untrackNodes(node) {
forEachNodeExtra(node, untrackExtra);
}
function forEachNodeExtra(node, fn) {
if (Array.isArray(node)) for (const item of node) fn(item.extra ??= {});
else fn(node.extra ??= {});
}
function dropExtra(exprExtra) {
exprExtra.dropped = true;
untrackExtra(exprExtra);
}
function untrackExtra(exprExtra) {
/* v8 ignore next 3 -- a merged reference is never dropped */
if (exprExtra.merged) throw new Error("Cannot drop a merged reference");
const readsByExpr = getReadsByExpression();
const reads = readsByExpr.get(exprExtra);
if (reads) {
readsByExpr.delete(exprExtra);
getFunctionReadsByExpression().delete(exprExtra);
forEach(reads, (read) => {
for (let cur = read.binding; cur; cur = cur.aliasOf) cur.reads.delete(exprExtra);
});
}
}
function dropContent(body) {
const bodyExtra = body.extra ??= {};
bodyExtra.dropped = true;
if (bodyExtra.section) bodyExtra.section.dropped = true;
untrackNodes(body.params);
dropChildren(body.body);
}
function dropChildren(children) {
for (const child of children) switch (child.type) {
case "MarkoTag":
untrackNodes(child.name);
if (child.arguments) untrackNodes(child.arguments);
if (child.var) untrackNodes(child.var);
for (const attr of child.attributes) untrackNodes(attr.value);
dropChildren(child.attributeTags);
dropContent(child.body);
break;
case "MarkoPlaceholder":
untrackNodes(child.value);
break;
case "MarkoScriptlet": untrackNodes(child.body);
}
}
function addReadToExpression(root, binding, getter) {
const { node } = root;
const fnRoot = getFnRoot(root);
const exprRoot = getExprRoot(fnRoot || root);
const section = ensureSection(exprRoot);
const rootExtra = exprRoot.node.extra ??= { section };
const exprExtra = getCanonicalExtra(rootExtra);
if (exprExtra.dropped) return;
const extra = node.extra ??= {};
extra.exprRoot = rootExtra;
const read = addRead(exprExtra, extra, binding, section, getter);
const { parent } = root;
if (parent.type === "BinaryExpression" && (parent.operator === "===" || parent.operator === "!==")) read.comparedTo = parent.left === node ? parent.right : parent.left;
if (!getter && binding.type === 4) {
const babelBinding = root.scope.getBinding(binding.name);
read.inOwnBody = !!babelBinding && babelBinding.kind !== "param" && isReferenceInOwnBody(babelBinding.path, root);
}
if (!getter && root.parent.type === "MarkoSpreadAttribute") extra.spreadFrom = binding;
if (fnRoot) {
read.deferred = fnRoot.node.type !== "ObjectMethod" || fnRoot.node.kind === "method";
const fnReadsByExpr = getFunctionReadsByExpression();
let exprFnReads = fnReadsByExpr.get(exprExtra);
if (!exprFnReads) fnReadsByExpr.set(exprExtra, exprFnReads = /* @__PURE__ */ new Map());
const fnExtra = fnRoot.node.extra ??= {};
fnExtra.section = section;
fnExtra.exprRoot = rootExtra;
read.fnRoot = fnExtra;
exprFnReads.set(fnExtra, push(exprFnReads.get(fnExtra), read));
}
}
function getAllTagReferenceNodes(tag, referenceNodes = [], collectAttrTag) {
if (tag.arguments) for (const arg of tag.arguments) referenceNodes.push(arg);
for (const attr of tag.attributes) referenceNodes.push(attr.value);
for (const child of tag.body.attributeTags ? tag.body.body : tag.attributeTags) switch (child.type) {
case "MarkoTag":
if (collectAttrTag && _marko_compiler.types.isStringLiteral(child.name) && child.name.value[0] === "@") collectAttrTag(child);
else getAllTagReferenceNodes(child, referenceNodes, collectAttrTag);
break;
case "MarkoScriptlet": for (const statement of child.body) referenceNodes.push(statement);
}
return referenceNodes;
}
function createResolvedRead(binding, props, inOwnBody = false) {
return {
binding,
props,
inOwnBody,
getter: void 0
};
}
function createResolvedGetterRead(binding, props, getter) {
return {
binding,
props,
inOwnBody: false,
getter
};
}
function isReferencedExtra(extra) {
return !!(extra && !extra.dropped && extra.section);
}
function hasResumableAssignment(binding) {
return some(binding.assignments, isResumableAssignment);
}
function isResumableAssignment({ exprRoot, fnRoot }) {
return !!getCanonicalExtra(exprRoot).isEffect || isRegisteredFnExtra(fnRoot);
}
function isAssignedBindingExtra(extra) {
return isReferencedExtra(extra) && extra.assignment !== void 0;
}
function isRegisteredFnExtra(extra) {
return isReferencedExtra(extra) && extra.registerId !== void 0;
}
function getReferencedBindings(extra) {
return extra && getCanonicalExtra(extra)[kReferencedBindings];
}
function getBindingsDerivedFrom(binding) {
if (binding.aliasOf) return binding.aliasOf;
if (binding.derivedFrom) return getValueReferences(binding.derivedFrom);
}
function getValueReferences(exprs) {
return reduce(exprs, addValueReferences);
}
function addValueReferences(refs, expr) {
return isReferencedExtra(getCanonicalExtra(expr)) && !expr.initialValue ? bindingUtil.union(refs, getReferencedBindings(expr)) : refs;
}
function getReferencedBindingsInFunction(extra) {
return extra[kReferencedBindingsInFunction];
}
function getConstantBindingsInFunction(extra) {
return extra[kConstantBindingsInFunction];
}
function setResolvedFunctionReads(extra, referencedBindings, constantBindings) {
extra[kReferencedBindingsInFunction] = referencedBindings;
extra[kConstantBindingsInFunction] = constantBindings;
}
function setResolvedReads(extra, referencedBindings, lazyBindings) {
extra[kReferencedBindings] = referencedBindings;
extra[kLazyBindings] = lazyBindings;
}
function getCanonicalExtra(extra) {
while (extra.merged) extra = extra.merged;
return extra;
}
function addNumericPropertiesUntil(props, len) {
let result = props;
for (let i = len; i--;) result = propsUtil.add(result, i + "");
return result;
}
//#endregion
//#region src/translator/util/bindings.ts
const [getBindings] = createProgramState(() => /* @__PURE__ */ new Set());
const [getNextBindingId, setNextBindingId] = createProgramState(() => 0);
function createBinding(name, type, refSection, aliased, property, excludeProperties, loc = null, refDeclared = false, restOffset) {
const id = getNextBindingId();
const section = aliased ? aliased.section : refSection;
const sameSection = refSection === section;
const declared = sameSection && refDeclared;
const binding = {
id,
uid: id,
name,
originalName: void 0,
type,
loc,
section,
property,
declared,
closureSections: void 0,
closureId: void 0,
assignments: void 0,
excludeProperties,
assignedProperties: void 0,
sources: void 0,
intersection: void 0,
derivedFrom: void 0,
reads: /* @__PURE__ */ new Map(),
aliases: /* @__PURE__ */ new Set(),
hoists: void 0,
getters: /* @__PURE__ */ new Map(),
propertyAliases: /* @__PURE__ */ new Map(),
aliasOf: aliased,
iterates: void 0,
declaredAlias: void 0,
localOf: void 0,
localClosures: void 0,
restOffset,
returnedBy: void 0,
reserveSize: 0,
scopeAccessor: void 0,
nullable: !sameSection || excludeProperties === void 0 && restOffset === void 0,
pruned: void 0,
exposed: false,
hasLazyReads: false
};
if (property) {
const propBinding = aliased.propertyAliases.get(property);
if (propBinding) {
binding.property = void 0;
binding.aliasOf = propBinding;
propBinding.aliases.add(binding);
} else aliased.propertyAliases.set(property, binding);
} else if (aliased) {
aliased.aliases.add(binding);
if (declared) aliased.declaredAlias ??= binding;
}
setNextBindingId(id + 1);
getBindings().add(binding);
return binding;
}
function reserveId(binding, offset) {
binding.reserveSize = Math.max(binding.reserveSize, offset);
}
function ensurePropertyAlias(binding, property) {
const canonical = getCanonicalBinding(binding);
return canonical.propertyAliases.get(property) || createBinding(canonical.name + toIdentifierAccess(property), canonical.type, canonical.section, canonical, property);
}
function addAssignedProperty(binding, property) {
if (binding.assignedProperties !== true) binding.assignedProperties = property === void 0 || propsUtil.add(binding.assignedProperties, property);
}
function getAssignedObject(binding) {
let object;
for (let alias = binding; alias.aliasOf && !isRest(alias); alias = alias.aliasOf) if (alias.property !== void 0) {
const parent = getCanonicalBinding(alias.aliasOf);
if (parent.assignedProperties === true || propsUtil.has(parent.assignedProperties, alias.property)) object = alias.aliasOf;
}
return object;
}
function getPropertyAlias(binding, properties) {
return reduceWhile(properties, getExistingPropertyAlias, binding);
}
function getExistingPropertyAlias(binding, property) {
return getCanonicalBinding(binding).propertyAliases.get(property);
}
function getDeepestPropertyAlias(binding, properties) {
let alias = binding;
if (Array.isArray(properties)) for (const property of properties) {
const next = alias.propertyAliases.get(property);
if (!next) break;
alias = next;
}
else if (properties !== void 0) alias = alias.propertyAliases.get(properties) ?? alias;
return alias;
}
function compareReferences(a, b) {
return a === b ? 0 : a ? b ? Array.isArray(a) ? Array.isArray(b) ? compareIntersections(a, b) : -1 : Array.isArray(b) ? 1 : bindingUtil.compare(a, b) : 1 : b ? -1 : 0;
}
/**
* reference group priority is sorted by number of references,
* then if needed by reference order.
*/
function compareIntersections(a, b) {
const len = a.length;
const lenDelta = len - b.length;
if (lenDelta !== 0) return lenDelta;
for (let i = 0; i < len; i++) {
const compareResult = bindingUtil.compare(a[i], b[i]);
if (compareResult !== 0) return compareResult;
}
return 0;
}
function getAliasRoot(binding) {
let root = binding;
while (root.aliasOf) root = root.aliasOf;
return root;
}
const bindingUtil = new Sorted(function compareBindings(a, b) {
return a === b ? 0 : a.section.id - b.section.id || +(b.type === 0) - +(a.type === 0) || a.uid - b.uid;
});
const propsUtil = new Sorted(function compareProps(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
});
function getCanonicalBinding(binding) {
const alias = binding.aliasOf;
if (alias && isDirectAlias(binding)) return alias;
return binding;
}
function someAlias(binding, test, arg, directOnly) {
if (test(binding, arg)) return true;
for (const alias of binding.aliases) if ((!directOnly || isDirectAlias(alias)) && someAlias(alias, test, arg, directOnly)) return true;
return false;
}
function someUpToAliasRoot(binding, test, arg) {
for (let cur = binding; cur; cur = cur.aliasOf) if (test(cur, arg)) return true;
return false;
}
function getNearestDeclared(binding) {
for (let cur = binding; cur; cur = cur.aliasOf) if (cur.declared) return cur;
}
function getDeclaredAlias(binding) {
return !getNearestDeclared(binding) && binding.declaredAlias;
}
function isDirectAlias(binding) {
return binding.aliasOf !== void 0 && binding.property === void 0 && !isRest(binding);
}
function isRest(binding) {
return binding.excludeProperties !== void 0 || binding.restOffset !== void 0;
}
function getDebugAccess(binding, toParam, formatProperty) {
let root = binding;
let access = "";
while (root.aliasOf && (toParam ? root.aliasOf !== root.section.params : !(root.loc || root.declared)) && !isRest(root)) {
if (root.property !== void 0) access = formatProperty(root.property) + access;
root = root.aliasOf;
}
return {
root,
access
};
}
function isTemplateParam(binding) {
return binding.type === 2 && !binding.section.parent;
}
function getDebugName(binding) {
const { root, access } = getDebugAccess(binding, isTemplateParam(binding), toAccess);
return root.name + access;
}
function getDebugNames(refs) {
return mapToString(refs, ", ", getDebugName);
}
function getDebugNamesAsIdentifier(refs) {
return mapToString(refs, "__OR__", getDebugNameAsIdentifier);
}
function getDebugNameAsIdentifier(binding) {
const { root, access } = getDebugAccess(binding, isTemplateParam(binding), toIdentifierAccess);
return root.name + access;
}
function toIdentifierAccess(property) {
return `_${property.replace(/[^a-z0-9_$]/gi, "_")}`;
}
function isInvokeOnlyBinding(binding) {
return !someAlias(binding, isReadBeyondInvoking, void 0);
}
function isReadBeyondInvoking(binding) {
if (binding.assignments || binding.hoists || binding.getters.size || binding.propertyAliases.size || isRest(binding)) return true;
for (const expr of binding.reads.keys()) if (!expr.invokeOnly) return true;
return false;
}
function isOwnBinding(binding) {
return binding.section.program === (0, _marko_compiler_babel_utils.getProgram)().node.extra.section;
}
function hasNonConstantPropertyAlias(ref) {
for (const alias of ref.propertyAliases.values()) if (alias.type !== 5) return true;
return false;
}
function getPropertyPath(binding, ancestor) {
if (binding === ancestor) return;
const path = getPropertyPath(binding.aliasOf, ancestor);
return binding.property === void 0 ? path : push(path, binding.property);
}
function isIndexProperty(property) {
return /^\d+$/.test(property);
}
//#endregion
//#region src/translator/util/module-read.ts
const styleImportReg = /\.(?:css(?:\.[cm]?[jt]s)?|less|s[ac]ss|styl(?:us)?|pcss|postcss)(?:\?|$)/i;
const kModuleRead = Symbol("module read");
/** The module read an expression is, resolved on first use: translate replaces
* a `<style/name>` tag. */
function getModuleRead(path, expr) {
return ((expr.extra ??= {})[kModuleRead] ??= resolveModuleRead(path, expr)) || void 0;
}
/** A module read of a stylesheet module, whose reads are class name strings. */
function getStyleImportRead(path, expr) {
const moduleRead = getModuleRead(path, expr);
if (moduleRead && (moduleRead.request === void 0 || styleImportReg.test(moduleRead.request))) return moduleRead.read;
}
function toModuleReadExpression([name, ...members]) {
let expr = _marko_compiler.types.identifier(name);
for (const member of members) expr = _marko_compiler.types.memberExpression(expr, _marko_compiler.types.identifier(member));
return expr;
}
function resolveModuleRead(path, expr) {
switch (expr.type) {
case "Identifier": {
const decl = path.scope.getBinding(expr.name)?.path;
const importDecl = decl?.parentPath;
if (importDecl?.isImportDeclaration()) {
const scriptlet = importDecl.parentPath;
return scriptlet.isMarkoScriptlet() && scriptlet.node.target ? null : {
read: [expr.name],
request: importDecl.node.source.value
};
}
return decl && isCoreTagName(decl, "style") && decl.node.var.type === "Identifier" ? {
read: [expr.name],
request: void 0
} : null;
}
case "MemberExpression": {
const object = !expr.computed && getModuleRead(path, expr.object);
return object ? {
read: [...object.read, expr.property.name],
request: object.request
} : null;
}
}
return null;
}
//#endregion
//#region src/translator/util/structure.ts
const walkCodeToName = {
[32]: "get",
[37]: "replace",
[38]: "endChild",
[47]: "beginChild",
[48]: "beginChildWithVar",
[49]: "dynamicTagWithVar",
[67]: "next",
[97]: "over",
[107]: "out",
[117]: "multiplier",
[91]: "nextEnd",
[106]: "overEnd",
[116]: "outEnd",
[126]: "multiplierEnd"
};
function enter(path) {
getSection(path).structure?.push(0);
}
function exit(path) {
getSection(path).structure?.push(1);
}
function enterShallow(path) {
getSection(path).structure?.push(0, 1);
}
function child(tag, name, renderer) {
getSection(tag).structure?.push({
kind: Child,
name,
binding: tag.node.extra.childScopeBinding,
renderer
});
}
function writeTo(path) {
const { structure } = getSection(path);
return (strs, ...exprs) => {
if (!structure) return;
const exprsLen = exprs.length;
pushMarkup(structure, strs[0]);
for (let i = 0; i < exprsLen; i++) {
pushMarkup(structure, exprs[i]);
pushMarkup(structure, strs[i + 1]);
}
};
}
function writeModuleReadTo(path, read) {
getSection(path).structure?.push({
kind: ModuleRead,
read
});
}
function writeTextTo(path, value) {
if (value) getSection(path).structure?.push({
kind: Text,
value
});
}
function pushMarkup(structure, str) {
if (!str) return;
const last = structure.length - 1;
if (typeof structure[last] === "string") structure[last] += str;
else structure.push(str);
}
function node(path, binding) {
return addNode(path, binding, false);
}
function marker(path, binding) {
addNode(path, binding, true);
}
function controlFlowNode(tag, section) {
const extra = tag.node.extra ??= {};
if (getOnlyChildParentTagName(tag)) {
const parentTag = getParentTag(tag).node;
const parentTagName = parentTag.name.value;
return extra.nodeBinding = (parentTag.extra ??= {}).nodeBinding ??= createBinding("#" + parentTagName.toLowerCase(), 0, section);
}
const binding = extra.nodeBinding = createBinding("#text", 0, section);
marker(tag, binding);
enterShallow(tag);
return binding;
}
function addNode(path, binding, marker) {
const { structure } = getSection(path);
if (!structure) return;
const op = {
kind: Node,
binding,
marker
};
structure.push(op);
return op;
}
function resolveStructure(section) {
const resolved = {
writes: [""],
walks: [""],
walkComment: [],
steps: []
};
if (section.content?.startType === 1) separate(resolved);
let textEdge;
for (const op of section.structure) if (typeof op === "string") {
appendLiteral(resolved.writes, op);
textEdge = void 0;
} else if (typeof op === "number") resolved.steps.push(op);
else switch (op.kind) {
case Text:
if (textEdge === "child") separate(resolved);
appendLiteral(resolved.writes, op.value);
textEdge = "own";
break;
case ModuleRead:
resolved.writes.push(toModuleReadExpression(op.read), "");
textEdge = void 0;
break;
case Node: {
if (!op.binding) continue;
const withVar = hasScopeOffset(op.binding);
const code = op.marker ? withVar ? 49 : 37 : 32;
flushSteps(resolved);
resolved.walkComment.push(walkCodeToName[code]);
appendLiteral(resolved.walks, String.fromCharCode(code));
if (op.marker) {
appendLiteral(resolved.writes, "<!>");
textEdge = void 0;
}
break;
}
case Child: {
const withVar = hasScopeOffset(op.binding);
const content = refContent(op.renderer);
if (content) {
if (textEdge && content.startType === 4) separate(resolved);
textEdge = content.endType === 4 ? "child" : void 0;
flushSteps(resolved);
}
const template = op.renderer && resolveRef(op.renderer, "template");
if (template) resolved.writes.push(template, "");
resolved.walkComment.push(`<${op.name}${withVar ? "/var" : ""}>`);
appendLiteral(resolved.walks, String.fromCharCode(withVar ? 48 : 47));
const walks = op.renderer && resolveRef(op.renderer, "walks");
if (walks) resolved.walks.push(walks, "");
appendLiteral(resolved.walks, String.fromCharCode(38));
break;
}
}
if (section.content?.endType === 1) separate(resolved);
flushSteps(resolved);
return resolved;
}
function hasScopeOffset(nodeBinding) {
return nodeBinding.reserveSize >= 1;
}
function separate(resolved) {
appendLiteral(resolved.writes, "<!>");
resolved.steps.push(0, 1);
}
function refContent(ref) {
return (ref && (ref.kind === "sectionRef" ? ref.section : ref.program.section))?.content;
}
function resolveRef(ref, part) {
if (ref.kind === "sectionRef") return declareSectionMeta(ref.section)[part === "template" ? "writes" : "walks"];
const name = ref.program.exportNames[part];
if (ref.program.section === (0, _marko_compiler_babel_utils.getProgram)().node.extra.section) {
declareOwnExports();
return _marko_compiler.types.identifier(name);
}
return importOrSelfReferenceName((0, _marko_compiler_babel_utils.getFile)(), ref.path, name, `${ref.hint}_${part}`);
}
const [getSectionMeta] = createSectionState("SectionMeta", (section) => {
if (!section.structure || section.dropped) return {
walks: void 0,
writes: void 0
};
const { writes, walks, walkComment } = resolveStructure(section);
const walkLiteral = buildStringExpression(walks, true);
if (walkLiteral && walkLiteral.value !== "") withLeadingComment(walkLiteral, walkComment.join(", "));
return {
walks: walkLiteral,
writes: buildStringExpression(writes, true)
};
});
function writeStructureExports(program) {
const { walks, writes } = getSectionMeta(getSectionForBody(program));
const exportNames = program.node.extra.exportNames;
const { decls, exportsAt = decls.length } = getMetaDecls();
if (exportsAt < decls.length) program.node.body.unshift(_marko_compiler.types.variableDeclaration("const", decls.slice(exportsAt)));
program.node.body.unshift(_marko_compiler.types.exportNamedDeclaration(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(exportNames.template), writes || _marko_compiler.types.stringLiteral(""))])), _marko_compiler.types.exportNamedDeclaration(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(exportNames.walks), walks || _marko_compiler.types.stringLiteral(""))])));
if (exportsAt) program.node.body.unshift(_marko_compiler.types.variableDeclaration("const", decls.slice(0, exportsAt)));
}
const [getMetaDecls] = createProgramState(() => ({ decls: [] }));
const declaredSectionMetas = /* @__PURE__ */ new WeakSet();
function declareSectionMeta(section) {
const meta = getSectionMeta(section);
if (!declaredSectionMetas.has(meta)) {
declaredSectionMetas.add(meta);
const { walks, writes } = meta;
const { decls } = getMetaDecls();
if (walks) {
meta.walks = generateUidIdentifier(`${section.name}__walks`);
decls.push(_marko_compiler.types.variableDeclarator(meta.walks, walks));
}
if (writes) {
meta.writes = generateUidIdentifier(`${section.name}__template`);
decls.push(_marko_compiler.types.variableDeclarator(meta.writes, writes));
}
}
return meta;
}
function declareOwnExports() {
const state = getMetaDecls();
if (state.exportsAt === void 0) {
getSectionMeta((0, _marko_compiler_babel_utils.getProgram)().node.extra.section);
state.exportsAt = state.decls.length;
}
}
function flushSteps({ walks, walkComment, steps }) {
if (!steps.length) return;
const walkCodes = [];
let walkString = "";
let depth = 0;
for (const step of steps) if (step === 0) {
depth++;
walkCodes.push(67);
} else {
depth--;
if (depth >= 0) {
walkCodes.length = walkCodes.lastIndexOf(67);
walkCodes.push(97);
} else {
walkCodes.length = walkCodes.lastIndexOf(107) + 1;
walkCodes.push(107);
depth = 0;
}
}
let current = walkCodes[0];
let count = 0;
for (const walk of walkCodes) if (walk !== current) {
walkComment.push(`${walkCodeToName[current]}(${count})`);
walkString += nCodeString(current, count);
current = walk;
count = 1;
} else count++;
walkComment.push(`${walkCodeToName[current]}(${count})`);
walkString += nCodeString(current, count);
steps.length = 0;
appendLiteral(walks, walkString);
}
function nCodeString(code, number) {
switch (code) {
case 67: return toCharString(number, code, 25);
case 97: return toCharString(number, code, 10);
case 107: return toCharString(number, code, 10);
default: throw new Error(`Unexpected walk code: ${code}`);
}
}
function toCharString(number, startCode, rangeSize) {
let result = "";
if (number >= rangeSize) {
const multiplier = Math.floor(number / rangeSize);
result += toCharString(multiplier, 117, 10);
number -= multiplier * rangeSize;
}
result += String.fromCharCode(startCode + number);
return result;
}
/** `_content` strips trailing exit codes before it walks, so a renderer that
* reaches the runtime through it never needs them on the wire. */
function trimTrailingExits(walks) {
if (!_marko_compiler.types.isStringLiteral(walks)) return walks;
const value = walks.value.replace(/[^\0-1]+$/, "");
return value === walks.value ? walks : value ? withLeadingComment(_marko_compiler.types.stringLiteral(value), getComment(walks)) : void 0;
}
function getComment(node) {
return node.leadingComments?.[0]?.value.trim() || "";
}
//#endregion
//#region src/translator/util/visitors.ts
function extractVisitors(visitors) {
const result = {
migrate: {},
transform: {},
analyze: {},
translate: {}
};
for (const _name in visitors) {
const name = _name;
const value = visitors[name];
if (value.migrate) result.migrate[name] = value.migrate;
if (value.transform) result.transform[name] = value.transform;
if (value.analyze) result.analyze[name] = value.analyze;
if (value.translate) result.translate[name] = value.translate;
}
return result;
}
function translateByTarget({ html, dom }) {
return {
enter(path) {
enterHook(isOutputHTML() ? html : dom, path);
},
exit(path) {
exitHook(isOutputHTML() ? html : dom, path);
}
};
}
function enterHook(modulePlugin, path) {
if (modulePlugin) {
const plugin = getPlugin(modulePlugin);
if (isFunctionPlugin(plugin)) plugin(path, _marko_compiler.types);
else if (plugin.enter) plugin.enter(path, _marko_compiler.types);
}
}
function exitHook(modulePlugin, path) {
if (modulePlugin) {
const plugin = getPlugin(modulePlugin);
if (!isFunctionPlugin(plugin) && plugin.exit) plugin.exit(path, _marko_compiler.types);
}
}
function getPlugin(modulePlugin) {
return isModulePlugin(modulePlugin) ? modulePlugin.default : modulePlugin;
}
function isModulePlugin(plugin) {
return Boolean(plugin.default);
}
function isFunctionPlugin(plugin) {
return typeof plugin === "function";
}
//#endregion
//#region src/translator/core/await.ts
var await_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag, "Write the promise as a value attribute and receive the result as a tag parameter instead: `<await|result|=promise>`.");
assertNoSpreadAttrs(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag, "For pending and error UI, wrap the `<await>` in a [`<try>` tag](https://markojs.com/docs/reference/core-tag#try) with `<@placeholder>` and `<@catch|err|>` attribute tags.");
const { node } = tag;
const tagBody = tag.get("body");
const section = ensureSection(tag);
const valueAttr = assertOnlyValueAttr(tag, true);
assertHasBody(tag);
const tagExtra = tag.node.extra ??= {};
const nodeBinding = tagExtra.nodeBinding = createBinding("#text", 0, section);
if (node.body.params.length && (node.body.params.length > 1 || node.body.params[0].type === "RestElement")) throw tag.get("name").buildCodeFrameError("The [`<await>` tag](https://markojs.com/docs/reference/core-tag#await) only supports a single parameter.");
const bodySection = ensureBodySection(tagBody);
const valueExtra = valueAttr.value.extra ??= {};
const paramsBinding = trackParamsReferences(tagBody, 4);
if (paramsBinding) {
valueExtra.pure = false;
setDerivedFrom(paramsBinding, valueExtra);
}
initBranchSection(bodySection, valueExtra, {
nodeBinding,
optional: false
});
addSetupWork(section);
marker(tag, nodeBinding);
enterShallow(tag);
},
translate: translateByTarget({
html: {
enter(tag) {
flushBefore(tag);
},
exit(tag) {
const { node } = tag;
const [valueAttr] = node.attributes;
const nodeBinding = node.extra.nodeBinding;
const tagBody = tag.get("body");
const section = getSection(tag);
const bodySection = getSectionForBody(tagBody);
writeHTMLResumeStatements(tag);
tag.replaceWith(_marko_compiler.types.expressionStatement(callRuntime("_await", getScopeIdIdentifier(section), getScopeAccessorLiteral(nodeBinding), valueAttr.value, _marko_compiler.types.arrowFunctionExpression(node.body.params, toOnlyExpressionOrBlock(node.body.body)), getWriteGuard(section, bodySection?.reason, true))))[0].skip();
}
},
dom: { exit(tag) {
const { node } = tag;
const nodeBinding = node.extra.nodeBinding;
const section = getSection(tag);
const bodySection = getSectionForBody(tag.get("body"));
const signal = getSignal(section, nodeBinding, "await_promise");
const valueExpr = node.attributes[0].value;
signal.build = () => {
const branchRenderArgs = getBranchRendererArgs(bodySection);
const branchParams = branchRenderArgs.pop();
(signal.prependStatements ||= []).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(bodySection.name), callRuntime("_await_content", getScopeAccessorLiteral(nodeBinding, true), ...trimEmptyArgs(branchRenderArgs)))]));
importRuntimeFeature("catch");
return callRuntime("_await_promise", getScopeAccessorLiteral(nodeBinding, true), branchParams);
};
addStatement("render", section, void 0, _marko_compiler.types.callExpression(_marko_compiler.types.identifier(bodySection.name), [scopeIdentifier]));
addValue(section, getReferencedBindings(valueExpr.extra), signal, valueExpr);
tag.remove();
} }
}),
attributes: {},
autocomplete: [{
description: "Use to consume asynchronous data.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#await"
}],
types: runtime_info_default.name + "/tags/await.d.marko"
};
//#endregion
//#region src/translator/core/class.ts
var class_default = {
parse(tag) {
throw tag.hub.buildError(tag.node.name, "class {} component blocks are no longer supported. Use <let> and <const> tags for state.");
},
parseOptions: {
statement: true,
rawOpenTag: true
}
};
//#endregion
//#region src/translator/util/statement-tag.ts
function parseSingleStatement(tag, msg) {
const { node } = tag;
const statements = (0, _marko_compiler_babel_utils.parseStatements)((0, _marko_compiler_babel_utils.getFile)(), node.rawValue, node.start, node.end);
if (statements.length > 1) throw tag.hub.buildError(statements[1], msg);
return statements[0];
}
function createStatementTag(keyword) {
const target = keyword === "static" ? void 0 : keyword;
const keywordReg = new RegExp(`^${keyword}\\s*`);
return {
parse(tag) {
const { node } = tag;
const file = (0, _marko_compiler_babel_utils.getFile)();
const rawValue = node.rawValue;
const code = rawValue.replace(keywordReg, "");
const start = node.start + (rawValue.length - code.length);
let block = (0, _marko_compiler_babel_utils.parseBlock)(file, code, start, start + code.length);
if (block.body.length === 1 && _marko_compiler.types.isBlockStatement(block.body[0])) block = block.body[0];
const scriptlet = _marko_compiler.types.markoScriptlet(block.body, true, target);
scriptlet.innerComments = block.innerComments;
tag.replaceWith(scriptlet);
},
parseOptions: {
statement: true,
rawOpenTag: true
},
autocomplete: [{
displayText: `${keyword} <statement>`,
description: `A JavaScript statement which is only evaluated once your template is loaded${target ? ` on the ${target}` : ""}.`,
descriptionMoreURL: `https://markojs.com/docs/reference/language#${keyword === "static" ? "static" : "server-and-client"}`
}]
};
}
//#endregion
//#region src/translator/core/client.ts
var client_default = createStatementTag("client");
//#endregion
//#region src/translator/util/evaluate.ts
const kEvaluated = Symbol("evaluated");
function evaluate(value) {
return (value.extra ??= {})[kEvaluated] ??= computeEvaluated(value);
}
function computeEvaluated(value) {
const computed = (0, _marko_compiler_babel_utils.computeNode)(value);
return computed ? {
confident: true,
computed: computed.value,
nullable: computed.value == null,
pure: true
} : {
confident: false,
computed: void 0,
nullable: isNullableExpr(value),
pure: !traverseContains(value, isImpure)
};
}
function isImpure(node) {
switch (node.type) {
case "ArrowFunctionExpression":
case "ClassPrivateMethod":
case "ClassPrivateProperty":
case "FunctionExpression": return skip;
case "ClassMethod":
case "ObjectMethod": return node.computed && traverseContains(node.key, isImpure) || skip;
case "ClassAccessorProperty":
case "ClassProperty": return node.static ? void 0 : node.computed && traverseContains(node.key, isImpure) || skip;
case "CallExpression": return node.callee.type === "ArrowFunctionExpression" || node.callee.type === "FunctionExpression" ? traverseContains(node.arguments, isImpure) || traverseContains(node.callee.params, isImpure) || traverseContains(node.callee.body, isImpure) || skip : true;
case "AssignmentExpression":
case "NewExpression":
case "OptionalCallExpression":
case "TaggedTemplateExpression":
case "ThrowStatement":
case "UpdateExpression": return true;
case "UnaryExpression": return node.operator === "delete";
}
}
function isNullableExpr(expr) {
switch (expr.type) {
case "ArrayExpression":
case "ArrowFunctionExpression":
case "BigIntLiteral":
case "BinaryExpression":
case "BooleanLiteral":
case "ClassExpression":
case "FunctionExpression":
case "NewExpression":
case "NumericLiteral":
case "ObjectExpression":
case "RegExpLiteral":
case "StringLiteral":
case "TemplateLiteral":
case "UpdateExpression": return false;
case "AssignmentExpression": switch (expr.operator) {
case "=": return isNullableExpr(expr.right);
case "*=":
case "/=":
case "%=":
case "+=":
case "-=":
case "<<=":
case ">>=":
case ">>>=":
case "&=":
case "^=":
case "|=":
case "**=": return false;
case "||=":
case "??=": return isNullableExpr(expr.right);
case "&&=": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
default: return true;
}
case "AwaitExpression": return isNullableExpr(expr.argument);
case "ConditionalExpression": return isNullableExpr(expr.consequent) || isNullableExpr(expr.alternate);
case "LogicalExpression": switch (expr.operator) {
case "||":
case "??": return isNullableExpr(expr.right);
case "&&": return isNullableExpr(expr.left) || isNullableExpr(expr.right);
default: return true;
}
case "ParenthesizedExpression": return isNullableExpr(expr.expression);
case "SequenceExpression": return isNullableExpr(expr.expressions[expr.expressions.length - 1]);
case "UnaryExpression": return expr.operator === "void";
default: return true;
}
}
//#endregion
//#region src/translator/core/const.ts
var const_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
assertHasVar(tag, getVarHint);
const valueAttr = assertOnlyValueAttr(tag, true);
const valueExtra = valueAttr.value.extra ??= {};
valueExtra.pure = evaluate(valueAttr.value).pure;
const valueBinding = _marko_compiler.types.isIdentifier(valueAttr.value) ? tag.scope.getBinding(valueAttr.value.name) : void 0;
const aliased = valueBinding?.identifier.extra?.binding && !isReferenceHoisted(valueBinding.path, tag.get("attributes")[0].get("value")) ? valueBinding.identifier.extra.binding : void 0;
const binding = trackVarReferences(tag, 4, aliased);
if (binding) {
assertNoTagVarMutation(tag);
if (!evaluate(valueAttr.value).nullable) binding.nullable = false;
if (aliased) {
dropNodes(valueAttr.value);
valueExtra.binding = aliased;
} else {
setDerivedFrom(binding, valueExtra);
addSetupExpr(ensureSection(tag), valueAttr.value);
}
}
},
translate: { exit(tag) {
const { node } = tag;
const [valueAttr] = node.attributes;
const { value } = valueAttr;
const varBinding = node.var.extra?.binding;
if (isOutputDOM()) {
const section = getSection(tag);
if (varBinding && !varBinding.aliasOf && !value.extra?.dropped) {
const signal = initValue(varBinding);
addValue(section, getReferencedBindings(value.extra), signal, value);
}
} else if (!varBinding?.pruned || !value.extra?.dropped) translateVar(tag, value);
tag.remove();
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
description: "Use to create a constant binding.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#const"
}],
types: runtime_info_default.name + "/tags/const.d.marko"
};
function getVarHint(tag) {
const { attributes } = tag.node;
const [attr] = attributes;
return attributes.length === 1 && attr.type === "MarkoAttribute" && attr.name !== "value" && /^[A-Za-z_$][\w$]*$/.test(attr.name) ? `The variable goes after a slash: \`<const/${attr.name}=...>\`. For a one time module level value, prefix a plain JavaScript statement with \`static\`.` : "For example: `<const/doubled=count * 2>`.";
}
//#endregion
//#region src/translator/core/debug.ts
var debug_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
const valueAttr = assertOnlyValueAttr(tag);
const section = ensureSection(tag);
if (valueAttr) addSetupExpr(section, valueAttr.value);
else addSetupWork(section);
},
translate: { exit(tag) {
addTagStatement(tag, withPreviousLocation(_marko_compiler.types.debuggerStatement(), tag.node));
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
description: "Debug on value change.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#debug"
}],
types: runtime_info_default.name + "/tags/debug.d.marko"
};
//#endregion
//#region src/translator/core/define.ts
var define_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
assertHasVar(tag);
const tagBody = tag.get("body");
const bodySection = ensureBodySection(tagBody);
const varBinding = trackVarReferences(tag, 4);
if (!varBinding) {
dropNodes(getAllTagReferenceNodes(tag.node));
return;
}
assertNoTagVarMutation(tag);
const paramsBinding = trackParamsReferences(tagBody, 2);
setTagContentDerives(tag, varBinding);
if (bodySection) {
if (_marko_compiler.types.isIdentifier(tag.node.var)) {
const babelBinding = tag.scope.getBinding(tag.node.var.name);
let allDirectReferences = true;
let allHaveInput = true;
for (const ref of babelBinding.referencePaths) {
if (isReferenceHoisted(babelBinding.path, ref)) throw ref.buildCodeFrameError("Hoisted values must be functions. The `<define>` tag variable may not be hoisted. Please move the `<define>` tag prior to any references or extract to a separate `.marko` file.");
if (ref.parent.type === "MarkoTag" && ref.parent.name === ref.node) {
(ref.parent.extra ??= {}).defineBodySection = bodySection;
allHaveInput &&= !ref.parent.arguments?.length;
dropNodes(ref.parent.name);
} else {
allHaveInput = false;
allDirectReferences = false;
}
}
if (allDirectReferences) {
const inputAlias = allHaveInput && paramsBinding?.propertyAliases.get("0");
if (inputAlias) inputAlias.nullable = false;
dropNodes(getAllTagReferenceNodes(tag.node));
return;
}
}
}
analyzeAttributeTags(tag);
setDerivedFrom(varBinding, mergeTagReferences(ensureSection(tag), tag.node));
},
translate: {
enter(tag) {
if (!tag.node.var) {
tag.remove();
return;
}
if (isOutputHTML()) flushBefore(tag);
},
exit(tag) {
const { node } = tag;
const translatedAttrs = translateAttrs(tag);
if (isOutputHTML()) {
writeHTMLResumeStatements(tag);
translateVar(tag, propsToExpression(translatedAttrs.properties), "const", translatedAttrs.statements);
tag.insertBefore(translatedAttrs.statements);
} else {
if (_marko_compiler.types.isIdentifier(node.var)) {
const babelBinding = tag.scope.getBinding(node.var.name);
let hasDirectReferences = false;
let allDirectReferences = true;
for (const ref of babelBinding.referencePaths) if (ref.parent.type === "MarkoTag" && ref.parent.name === ref.node) hasDirectReferences = true;
else allDirectReferences = false;
const bodySection = getSectionForBody(tag.get("body"));
if (bodySection && hasDirectReferences) {
const signal = getSignal(bodySection, void 0);
signal.build = () => {
const hasWork = signalHasWork(signal);
if (hasWork && !bodySection.hasSetupWork) throw new Error("Marko internal error: analysis marked a `<define>` body's setup as empty but translation produced statements for it. Please open an issue with a reproduction.");
if (bodySection.hasSetupWork) return callRuntime("_child_setup", hasWork ? buildSignalFn(signal) : _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.numericLiteral(0)));
};
}
if (bodySection && allDirectReferences) {
tag.remove();
return;
}
}
const section = getSection(tag);
const referencedBindings = getReferencedBindings(node.extra);
if (translatedAttrs.statements.length) addStatement("render", section, referencedBindings, translatedAttrs.statements);
addValue(section, referencedBindings, initValue(tag.get("var").node.extra.binding), propsToExpression(translatedAttrs.properties));
}
tag.remove();
}
},
attributes: {},
autocomplete: [{
description: "Use to create a constant object binding that can be rendered.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#define"
}],
types: runtime_info_default.name + "/tags/define.d.marko"
};
//#endregion
//#region src/translator/core/effect.ts
var effect_default = {
migrate: (tag) => {
if (tag.node.body.body.length) throw tag.get("name").buildCodeFrameError("The `<effect>` tag has been replaced by [`<script>`](https://markojs.com/docs/reference/core-tag#script), which runs its body as code. Rename it to `<script>`.");
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
assertNoSpreadAttrs(tag);
(0, _marko_compiler_babel_utils.assertAllowedAttributes)(tag, ["value"]);
(0, _marko_compiler_babel_utils.diagnosticDeprecate)(tag, {
label: "The 'effect' tag has been replaced by the 'script' tag.",
fix() {
const { node } = tag;
tag.replaceWith(_marko_compiler.types.markoTag(withPreviousLocation(_marko_compiler.types.stringLiteral("script"), node.name), node.attributes, node.body, node.arguments, node.var, node.attributeTags));
}
});
},
attributes: {},
types: runtime_info_default.name + "/tags/effect.d.marko"
};
//#endregion
//#region src/translator/core/export.ts
var export_default = {
parse(tag) {
const statement = parseSingleStatement(tag, "The `<export>` tag takes a single export statement.");
const defaultExport = getDefaultExport(statement);
if (defaultExport) throw tag.hub.buildError(defaultExport, "A template is already its own default export. Use a named export instead.");
tag.replaceWith(statement);
},
parseOptions: {
statement: true,
rawOpenTag: true
},
autocomplete: [{ displayText: "export <value>" }]
};
function getDefaultExport(statement) {
if (statement.type === "ExportDefaultDeclaration") return statement;
if (statement.type !== "ExportNamedDeclaration") return;
for (const specifier of statement.specifiers) {
const { exported } = specifier;
if (exported && getLiteralName(exported) === "default") return specifier;
}
}
//#endregion
//#region src/translator/core/for.ts
var for_default = {
analyze(tag) {
const tagSection = ensureSection(tag);
const isAttrTag = tag.node.body.attributeTags;
const tagBody = tag.get("body");
const paramsBinding = trackParamsReferences(tagBody, isAttrTag ? 3 : 4);
let allowAttrs;
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
assertNoSpreadAttrs(tag);
const forType = getForType(tag.node);
switch (forType) {
case "of":
allowAttrs = ["of"];
break;
case "in":
allowAttrs = ["in"];
break;
case "to":
allowAttrs = [
"to",
"from",
"step"
];
break;
case "until":
allowAttrs = [
"until",
"from",
"step"
];
break;
default: throw tag.buildCodeFrameError("The [`<for>` tag](https://markojs.com/docs/reference/core-tag#for) requires an `of=`, `in=`, `to=`, or `until=` attribute.");
}
if (!isAttrTag) allowAttrs.push("by");
const keyAttr = tag.node.attributes.find((attr) => attr.type === "MarkoAttribute" && attr.name === "key");
if (keyAttr) throw tag.hub.buildError(keyAttr, `The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) keys items with the \`by=\` attribute, not \`key=\`. ${forType === "of" ? "Use `by=\"propName\"` or `by=(item, index) => key`" : forType === "in" ? "Use `by=(key, value) => key`" : "Use `by=(num) => key`"}.`);
(0, _marko_compiler_babel_utils.assertAllowedAttributes)(tag, allowAttrs);
const extraParam = tag.node.body.params[forType === "of" || forType === "in" ? 2 : 1];
if (extraParam && extraParam.type !== "RestElement") throw tag.hub.buildError(extraParam, `The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) only provides \`|${forType === "of" ? "item, index" : forType === "in" ? "key, value" : "num"}|\` with \`${forType}=\`, so this parameter is never supplied.`);
if (isAttrTag) {
if (paramsBinding) setDerivedFrom(paramsBinding, fromIter(tag.node.attributes.map((attr) => attr.value.extra ??= {})));
return;
}
const byAttr = getKnownAttrValues(tag.node).by;
if (byAttr) (byAttr.extra ??= {}).consumed = true;
if (forType !== "of" && byAttr?.type === "StringLiteral") throw tag.hub.buildError(byAttr, `The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) only supports a string \`by\` key with \`of\`; use a \`by=(${forType === "in" ? "key, value" : "index"}) => ...\` function for \`<for ${forType}>\`.`);
const bodySection = ensureBodySection(tagBody);
if (!bodySection) {
dropNodes(getAllTagReferenceNodes(tag.node));
return;
}
const nodeBinding = controlFlowNode(tag, tagSection);
const tagExtra = mergeTagReferences(tagSection, tag.node);
addReasonExprs(ensureSlot(nodeBinding, 4), tagExtra);
if (paramsBinding) {
setDerivedFrom(paramsBinding, tagExtra);
if (forType === "of" || forType === "in") paramsBinding.iterates = {
expr: getKnownAttrValues(tag.node)[forType].extra ??= {},
type: forType
};
const keyBinding = getLoopKeyBinding(byAttr, paramsBinding, forType);
if (keyBinding) {
keyBinding.type = 5;
keyBinding.scopeAccessor = getAccessorProp().LoopKey;
onFinalizeReferences(() => detectForSelector(bodySection, keyBinding));
}
}
initBranchSection(bodySection, tagExtra, {
nodeBinding,
optional: true
});
},
translate: translateByTarget({
html: {
enter(tag) {
if (tag.node.body.attributeTags) return;
if (!getSectionForBody(tag.get("body"))) {
tag.remove();
return;
}
flushBefore(tag);
},
exit(tag) {
if (tag.node.body.attributeTags) return;
const bodySection = getSectionForBody(tag.get("body"));
const { node } = tag;
const nodeBinding = node.extra.nodeBinding;
const forAttrs = getKnownAttrValues(node);
const forType = getForType(node);
const params = node.body.params;
const statements = [];
const bodyStatements = node.body.body;
const branchReason = getBranchWriteReason(bodySection);
resumeOwnerByMarkerWhenUnconditional(bodySection, nodeBinding);
writeHTMLResumeStatements(tag);
const forTagArgs = getBaseArgsInForTag(forType, forAttrs);
const forTagHTMLRuntime = branchReason ? forTypeToBranchRuntime(forType) : forTypeToRuntime(forType);
forTagArgs.push(_marko_compiler.types.arrowFunctionExpression(params, _marko_compiler.types.blockStatement(bodyStatements)));
if (branchReason) forTagArgs.push(forAttrs.by || _marko_compiler.types.numericLiteral(0), ...getBranchResumeArgs(tag, branchReason, isSingleNodeBranch(bodySection)));
statements.push(_marko_compiler.types.expressionStatement(callRuntime(forTagHTMLRuntime, ...forTagArgs)));
for (const replacement of tag.replaceWithMultiple(statements)) replacement.skip();
}
},
dom: {
enter(tag) {
if (tag.node.body.attributeTags) return;
if (!getSectionForBody(tag.get("body"))) tag.remove();
},
exit(tag) {
if (tag.node.body.attributeTags) return;
const tagBody = tag.get("body");
const tagSection = getSection(tag);
const bodySection = getSectionForBody(tagBody);
const { node } = tag;
const tagExtra = node.extra;
const referencedBindings = getReferencedBindings(tagExtra);
const nodeBinding = tagExtra.nodeBinding;
const hop = {
kind: "for",
nodeBinding
};
setClosureSignalBuilder(tag, hop, (closure, render) => {
const selectorKeyBinding = getForSelectorKey(bodySection, closure);
if (!selectorKeyBinding) return buildClosureHop(hop, render);
return callRuntime("_for_selector", getScopeAccessorLiteral(nodeBinding, true), getScopeAccessorLiteral(closure, true), getScopeAccessorLiteral(selectorKeyBinding, true), render);
});
const forType = getForType(node);
const forAttrs = getKnownAttrValues(node);
const signal = getSignal(tagSection, nodeBinding, "for");
signal.build = () => {
return callRuntime(isKeyedByIndex(forType, forAttrs) ? forTypeToUnkeyedBranchRuntime(forType) : forTypeToBranchRuntime(forType), getScopeAccessorLiteral(nodeBinding, true), ...trimEmptyArgs(getBranchRendererArgs(bodySection)));
};
const loopArgs = getBaseArgsInForTag(forType, forAttrs);
if (forAttrs.by) loopArgs.push(forAttrs.by);
addValue(tagSection, referencedBindings, signal, _marko_compiler.types.arrayExpression(loopArgs));
tag.remove();
}
}
}),
parseOptions: { controlFlow: true },
attributes: {
of: {
type: "expression",
autocomplete: [{ description: "Iterates over a list of items." }]
},
in: {
type: "expression",
autocomplete: [{ description: "Iterates over the keys and values of an object." }]
},
to: {
type: "number",
autocomplete: [{ description: "Iterates up to the provided number (inclusive)" }]
},
until: {
type: "number",
autocomplete: [{ description: "Iterates up to the provided number (exclusive)" }]
},
from: {
type: "number",
autocomplete: [{ description: "Iterates starting from the provided number (inclusive)" }]
},
step: {
type: "number",
autocomplete: [{ description: "The amount to increment during each iteration (with from/to/until)" }]
}
},
autocomplete: [
{
snippet: "for|${1:value, index}| of=${3:array}",
description: "Use to iterate over lists, object properties, or between ranges.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#for"
},
{
snippet: "for|${1:name, value}| in=${3:object}",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#for"
},
{
snippet: "for|${1:index}| to=${2:number}",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#for"
},
{
snippet: "for|${1:index}| until=${2:number}",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#for"
}
]
};
function getLoopKeyBinding(byAttr, paramsBinding, forType) {
if (!paramsBinding) return;
if (byAttr) {
const item = paramsBinding.propertyAliases.get("0");
return item && getKeyAlias(byAttr, item);
}
return paramsBinding.propertyAliases.get(forType === "of" ? "1" : "0");
}
function getKeyAlias(byAttr, item) {
if (byAttr.type === "StringLiteral") return getPropertyAlias(item, byAttr.value);
if (byAttr.type === "ArrowFunctionExpression" || byAttr.type === "FunctionExpression") {
const itemParam = byAttr.params[0];
let body = byAttr.body;
if (body.type === "BlockStatement") {
const [statement] = body.body;
body = body.body.length === 1 && statement.type === "ReturnStatement" ? statement.argument : void 0;
}
if (itemParam?.type === "Identifier" && body) return getMemberChainAlias(body, itemParam.name, item);
}
}
function getMemberChainAlias(node, rootName, item) {
if (node.type === "Identifier") return node.name === rootName ? item : void 0;
if (node.type === "MemberExpression" || node.type === "OptionalMemberExpression") {
const property = getMemberExpressionPropString(node);
if (property !== void 0) {
const object = getMemberChainAlias(node.object, rootName, item);
return object && getPropertyAlias(object, property);
}
}
}
function isKeyedByIndex(type, attrs) {
if (attrs.by) return false;
switch (type) {
case "of": return true;
case "to":
case "until": return isNumberOrOmitted(attrs.from, 0) && isNumberOrOmitted(attrs.step, 1);
default: return false;
}
}
function isNumberOrOmitted(node, value) {
return !node || node.type === "NumericLiteral" && node.value === value;
}
//#endregion
//#region src/translator/util/body-to-text.ts
function bodyToText(body, decodeEntities = false) {
return buildText(body, toText, decodeEntities);
}
function bodyToUncoercedText(body) {
return buildText(body, identity);
}
function injectTextCoercion(expr) {
switch (expr.type) {
case "ConditionalExpression":
injectTextCoercion(expr.consequent);
injectTextCoercion(expr.alternate);
break;
case "TemplateLiteral": expr.expressions = expr.expressions.map((child) => toText(child));
}
}
function toText(value) {
return callRuntime("_to_text", value);
}
function identity(value) {
return value;
}
function buildText(body, coerce, decodeEntities = false) {
const templateQuasis = [];
const templateExpressions = [];
let currentQuasi = "";
let placeholderExtra;
let singleValue;
for (const child of body.body) if (_marko_compiler.types.isMarkoText(child)) currentQuasi += decodeEntities ? (0, _marko_compiler_babel_utils.decodeHTML)(child.value) : child.value;
else if (_marko_compiler.types.isMarkoPlaceholder(child)) {
placeholderExtra ||= child.value.extra;
templateQuasis.push(toTemplateElement(currentQuasi));
templateExpressions.push(coerce(child.value));
singleValue = child.value;
currentQuasi = "";
}
if (templateExpressions.length) {
if (templateExpressions.length === 1 && !currentQuasi && !templateQuasis[0].value.cooked && !_marko_compiler.types.isStringLiteral(singleValue)) return singleValue;
templateQuasis.push(toTemplateElement(currentQuasi, true));
const literal = _marko_compiler.types.templateLiteral(templateQuasis, templateExpressions);
literal.extra = placeholderExtra && getCanonicalExtra(placeholderExtra);
return literal;
}
return _marko_compiler.types.stringLiteral(currentQuasi);
}
//#endregion
//#region src/translator/core/html-comment.ts
const escapeCommentText = (text) => text.replace(/>/g, ">");
var html_comment_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributes)(tag);
assertIdentifierVar(tag);
const tagVar = tag.node.var;
let needsBinding = !!tagVar && isTagVarUsed(tag);
let nodeBinding;
const referenceNodes = [];
for (const child of tag.get("body").get("body")) if (child.isMarkoPlaceholder()) {
referenceNodes.push(child.node.value);
needsBinding = true;
} else if (!child.isMarkoText()) throw child.buildCodeFrameError("Invalid child. Only text is allowed inside an html comment.");
if (needsBinding) {
const tagSection = ensureSection(tag);
const tagExtra = mergeReferences(tagSection, tag.node, referenceNodes);
nodeBinding = tagExtra.nodeBinding = createBinding("#comment", 0, tagSection, void 0, void 0, void 0, void 0, !!tagVar);
trackDomVarReferences(tag, nodeBinding);
if (isTagVarUsed(tag)) addAlwaysReason(nodeBinding);
addReasonExprs(ensureSlot(nodeBinding), tagExtra);
}
const write = writeTo(tag);
if (nodeBinding) node(tag, nodeBinding);
enter(tag);
write`<!--`;
const textLiteral = bodyToUncoercedText(tag.node.body);
if (_marko_compiler.types.isStringLiteral(textLiteral)) write`${escapeCommentText(textLiteral.value)}`;
exit(tag);
write`-->`;
},
translate: { exit(tag) {
const tagSection = getSection(tag);
const tagExtra = tag.node.extra;
const nodeBinding = tagExtra.nodeBinding;
const write = writeTo$1(tag);
if (isOutputHTML()) {
const { body } = tag.node.body;
write`<!--`;
if (nodeBinding && isEmptiableCommentBody(body)) {
if (body.length) write`${_marko_compiler.types.logicalExpression("||", buildCommentValue(body), _marko_compiler.types.stringLiteral(" "))}`;
else write` `;
} else for (const child of body) if (_marko_compiler.types.isMarkoText(child)) write`${escapeCommentText(child.value)}`;
else if (_marko_compiler.types.isMarkoPlaceholder(child)) write`${callRuntime(child.escape ? "_escape_comment" : "_unescaped", child.value)}`;
write`-->`;
} else {
const textLiteral = bodyToText(tag.node.body);
if (!_marko_compiler.types.isStringLiteral(textLiteral)) addStatement("render", tagSection, getReferencedBindings(tagExtra), callRuntime("_text", createScopeReadExpression(nodeBinding), textLiteral));
}
if (nodeBinding) markNode(tag, nodeBinding, getWriteReason(nodeBinding));
tag.remove();
} },
parseOptions: { text: true },
types: runtime_info_default.name + "/tags/html-comment.d.marko",
autocomplete: [{
description: "Use to create an html comment that is not stripped from the output.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#html-comment"
}]
};
function isEmptiableCommentBody(body) {
for (const child of body) if (!_marko_compiler.types.isMarkoPlaceholder(child) || isNonEmptyLiteral(child.value)) return false;
return true;
}
function isNonEmptyLiteral(value) {
return _marko_compiler.types.isStringLiteral(value) ? !!value.value : _marko_compiler.types.isNumericLiteral(value);
}
function buildCommentValue(body) {
let value;
for (const child of body) {
const part = callRuntime(child.escape ? "_escape_comment" : "_unescaped", child.value);
value = value ? _marko_compiler.types.binaryExpression("+", value, part) : part;
}
return value;
}
//#endregion
//#region src/translator/core/html-script.ts
var html_script_default = {
types: runtime_info_default.name + "/tags/html-script.d.marko",
html: true,
parseOptions: {
text: true,
preserveWhitespace: true
},
autocomplete: [{
description: "Use instead of `<script>` to render a native tag directly, without processing by Marko.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#html-script--html-style"
}]
};
//#endregion
//#region src/translator/core/html-style.ts
var html_style_default = {
types: runtime_info_default.name + "/tags/html-style.d.marko",
html: true,
parseOptions: {
text: true,
preserveWhitespace: true
},
autocomplete: [{
description: "Use instead of `<style>` to render a native tag directly, without processing by Marko.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#html-script--html-style"
}]
};
//#endregion
//#region src/translator/core/id.ts
var id_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
assertHasVar(tag);
assertIdentifierVar(tag);
const valueAttr = assertOnlyValueAttr(tag);
const valueNode = valueAttr ? valueAttr.value : tag.node;
const valueExtra = valueAttr ? valueAttr.value.extra ??= {} : tag.node.extra ??= {};
valueExtra.pure = !valueAttr || evaluate(valueAttr.value).pure;
const binding = trackVarReferences(tag, 4);
if (binding) {
assertNoTagVarMutation(tag);
setDerivedFrom(binding, valueExtra);
}
addSetupExpr(ensureSection(tag), valueNode);
},
translate: { exit(tag) {
const { node } = tag;
const [valueAttr] = node.attributes;
if ((valueAttr ? valueAttr.value : node).extra?.dropped) {
tag.remove();
return;
}
const id = isOutputHTML() ? callRuntime("_id") : callRuntime("_id", scopeIdentifier);
if (isOutputHTML()) tag.replaceWith(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(node.var, valueAttr ? _marko_compiler.types.logicalExpression("||", valueAttr.value, id) : id)]));
else {
const section = getSection(tag);
const signal = initValue(node.var.extra.binding);
if (valueAttr) {
const { value } = valueAttr;
addValue(section, getReferencedBindings(value.extra), signal, _marko_compiler.types.logicalExpression("||", value, evaluate(value).confident ? id : callRuntime("_id", scopeIdentifier, _marko_compiler.types.stringLiteral(getPrefixedScopeAccessor(node.var.extra.binding, getAccessorPrefix().IdFallback)))));
} else addValue(section, void 0, signal, id);
tag.remove();
}
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
displayText: "id/<name>",
description: "Use to create a unique identifier.",
snippet: "id/${1:name}",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#id"
}],
types: runtime_info_default.name + "/tags/id.d.marko"
};
//#endregion
//#region src/common/errors.ts
const lowercaseOnAttrReg = /^on[a-z]/;
function assertExclusiveAttrs(attrs, onError = throwErr, isSet = isTruthy) {
if (attrs) {
let exclusiveAttrs;
if (isSet(attrs.checkedChange)) (exclusiveAttrs ||= []).push("checkedChange");
if ("checkedValue" in attrs) {
(exclusiveAttrs ||= []).push("checkedValue");
if ("checked" in attrs) exclusiveAttrs.push("checked");
} else if (isSet(attrs.checkedValueChange)) {
(exclusiveAttrs ||= []).push("checkedValueChange");
if ("checked" in attrs) exclusiveAttrs.push("checked");
}
if (isSet(attrs.valueChange)) {
(exclusiveAttrs ||= []).push("valueChange");
if ("checked" in attrs && !exclusiveAttrs.includes("checked")) exclusiveAttrs.push("checked");
}
if (exclusiveAttrs && exclusiveAttrs.length > 1) onError(`The attributes ${joinWithAnd(exclusiveAttrs)} are mutually exclusive.`);
}
}
function isTruthy(value) {
return value;
}
function throwErr(msg) {
throw new Error(msg);
}
function joinWithAnd(a) {
switch (a.length) {
case 0: return "";
case 1: return a[0];
case 2: return `${a[0]} and ${a[1]}`;
default: return `${a.slice(0, -1).join(", ")}, and ${a[a.length - 1]}`;
}
}
//#endregion
//#region src/html/attrs.ts
function _attr_class(value) {
return stringAttr("class", toDelimitedString(value, " ", stringifyClassEntry));
}
function _attr_style(value) {
return stringAttr("style", toDelimitedString(value, ";", stringifyStyleEntry));
}
function _attr(name, value) {
return isNullishOrFalse(value) ? "" : stringifyAttr(name, value);
}
function stringAttr(name, value) {
return value && " " + name + attrAssignment(value);
}
function stringifyAttr(name, value) {
switch (typeof value) {
case "string": return " " + name + attrAssignment(value);
case "boolean": return " " + name;
case "number": return " " + name + "=" + value;
}
return " " + name + attrAssignment(value + "");
}
const singleQuoteAttrReplacements = /['\r]|&(?=[#a-zA-Z])/g;
const doubleQuoteAttrReplacements = /["\r]|&(?=[#a-zA-Z])/g;
const needsQuotedAttr = /["'>\s]|&[#a-zA-Z]|\/$/g;
function attrAssignment(value) {
return value ? needsQuotedAttr.test(value) ? value[needsQuotedAttr.lastIndex - 1] === (needsQuotedAttr.lastIndex = 0, "\"") ? "='" + escapeSingleQuotedAttrValue(value) + "'" : "=\"" + escapeDoubleQuotedAttrValue(value) + "\"" : "=" + value : "";
}
function escapeSingleQuotedAttrValue(value) {
return singleQuoteAttrReplacements.test(value) ? value.replace(singleQuoteAttrReplacements, replaceUnsafeSingleQuoteAttrChar) : value;
}
function replaceUnsafeSingleQuoteAttrChar(match) {
return match === "'" ? "'" : match === "\r" ? " " : "&";
}
function escapeDoubleQuotedAttrValue(value) {
return doubleQuoteAttrReplacements.test(value) ? value.replace(doubleQuoteAttrReplacements, replaceUnsafeDoubleQuoteAttrChar) : value;
}
function replaceUnsafeDoubleQuoteAttrChar(match) {
return match === "\"" ? """ : match === "\r" ? " " : "&";
}
//#endregion
//#region src/html/writer.ts
let $chunk;
function getState() {
return $chunk.boundary.state;
}
globalThis.setImmediate || globalThis.setTimeout || globalThis.queueMicrotask;
//#endregion
//#region src/html/content.ts
var content_exports = /* @__PURE__ */ __exportAll({
_escape: () => _escape,
_escape_comment: () => _escape_comment,
_escape_script: () => _escape_script,
_escape_style: () => _escape_style,
_escape_style_value: () => _escape_style_value,
_to_text: () => _to_text,
_unescaped: () => _unescaped,
quoteScriptTemplateLiteral: () => quoteScriptTemplateLiteral
});
function _to_text(val) {
return val || val === 0 ? val + "" : "";
}
function _unescaped(val) {
return val ? val + "" : val === 0 ? "0" : "";
}
const unsafeXMLReg = /[<&\r]/g;
const replaceUnsafeXML = (c) => c === "&" ? "&" : c === "<" ? "<" : " ";
const escapeXMLStr = (str) => unsafeXMLReg.test(str) ? str.replace(unsafeXMLReg, replaceUnsafeXML) : str;
function _escape(val) {
return val ? escapeXMLStr(val + "") : val === 0 ? "0" : "";
}
const unsafeScriptReg = /<(\/?script|!--)/gi;
const escapeScriptStr = (str) => unsafeScriptReg.test(str) ? str.replace(unsafeScriptReg, "\\u003C$1") : str;
function _escape_script(val) {
return val ? escapeScriptStr(val + "") : val === 0 ? "0" : "";
}
const unsafeScriptTemplateLiteralReg = /[`\\\r]|\$\{|<(?=\/?script|!--)/gi;
const replaceUnsafeScriptTemplateLiteral = (c) => c === "<" ? "\\x3C" : c === "\r" ? "\\r" : "\\" + c;
const quoteScriptTemplateLiteral = (str) => "`" + (unsafeScriptTemplateLiteralReg.test(str) ? str.replace(unsafeScriptTemplateLiteralReg, replaceUnsafeScriptTemplateLiteral) : str) + "`";
const unsafeStyleReg = /<(\/style)/gi;
const escapeStyleStr = (str) => unsafeStyleReg.test(str) ? str.replace(unsafeStyleReg, "\\3C$1") : str;
function _escape_style(val) {
return val ? escapeStyleStr(val + "") : val === 0 ? "0" : "";
}
function _escape_style_value(val) {
return val || val === 0 ? escapeStyleValue(val + "") : "";
}
const unsafeCommentReg = />/g;
function escapeCommentStr(str) {
if (unsafeCommentReg.test(str)) str = str.replace(unsafeCommentReg, ">");
return str.startsWith(getState().commentPrefix) ? "&#" + str.charCodeAt(0) + ";" + str.slice(1) : str;
}
function _escape_comment(val) {
return val ? escapeCommentStr(val + "") : val === 0 ? "0" : "";
}
//#endregion
//#region src/translator/core/if.ts
const BRANCHES_LOOKUP = /* @__PURE__ */ new WeakMap();
const IfTag = {
analyze(tag) {
assertValidCondition(tag);
if (tag.node.body.attributeTags) return;
if (isCoreTagName(tag, "if")) {
let branchTag = tag;
do
ensureBodySection(branchTag.get("body"));
while (branchTag = getNextBranchTag(branchTag));
}
if (isLastBranch(tag)) {
const branches = getBranches(tag);
const [ifTag] = branches[0];
const ifTagSection = ensureSection(ifTag);
const ifTagExtra = ifTag.node.extra ??= {};
const mergeReferenceNodes = [];
const nodeBinding = controlFlowNode(ifTag, ifTagSection);
for (let index = 0; index < branches.length; index++) {
const [branchTag, branchBodySection] = branches[index];
if (branchBodySection) initBranchSection(branchBodySection, ifTagExtra, {
nodeBinding,
optional: true,
index
});
if (branchTag.node.attributes.length) mergeReferenceNodes.push(branchTag.node.attributes[0].value);
}
mergeReferences(ifTagSection, ifTag.node, mergeReferenceNodes);
addReasonExprs(ensureSlot(nodeBinding, 4), ifTagExtra);
}
},
translate: translateByTarget({
html: {
enter(tag) {
if (tag.node.body.attributeTags) return;
flushBefore(tag);
},
exit(tag) {
if (tag.node.body.attributeTags) return;
const bodySection = getSectionForBody(tag.get("body"));
if (bodySection) {
const [ifTag] = getBranches(tag)[0];
resumeOwnerByMarkerWhenUnconditional(bodySection, ifTag.node.extra.nodeBinding);
writeHTMLResumeStatements(tag);
}
if (isLastBranch(tag)) {
const branches = getBranches(tag);
const [ifTag] = branches[0];
const nextTag = tag.getNextSibling();
let branchReasons;
let statement;
for (let i = branches.length; i--;) {
const [branchTag, branchBodySection] = branches[i];
const bodyStatements = branchTag.node.body.body;
if (branchBodySection) {
const branchReason = getBranchWriteReason(branchBodySection);
if (branchReason) {
branchReasons = sourcesUtil.add(branchReasons, branchReason);
bodyStatements.push(_marko_compiler.types.returnStatement(_marko_compiler.types.numericLiteral(i)));
}
}
const [testAttr] = branchTag.node.attributes;
const curStatement = toOnlyStatementOrBlock(bodyStatements);
if (testAttr) statement = _marko_compiler.types.ifStatement(testAttr.value, curStatement, statement);
else statement = curStatement;
}
if (branchReasons) {
const cbNode = _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([statement]));
statement = _marko_compiler.types.expressionStatement(callRuntime("_if", cbNode, ...getBranchResumeArgs(ifTag, branchReasons, branches.every(([, branchBody]) => isSingleNodeBranch(branchBody)))));
}
for (const [branchTag] of branches) branchTag.remove();
nextTag.insertBefore(statement);
}
}
},
dom: { exit(tag) {
if (tag.node.body.attributeTags) return;
if (isLastBranch(tag)) {
const branches = getBranches(tag);
const [ifTag] = branches[0];
const ifTagSection = getSection(ifTag);
const ifTagExtra = branches[0][0].node.extra;
const nodeBinding = ifTagExtra.nodeBinding;
let expr = _marko_compiler.types.numericLiteral(branches.length);
for (let i = branches.length; i--;) {
const [branchTag, branchBodySection] = branches[i];
const [testAttr] = branchTag.node.attributes;
const consequent = _marko_compiler.types.numericLiteral(branchBodySection ? i : -1);
if (branchBodySection) setClosureSignalBuilder(branchTag, {
kind: "if",
nodeBinding,
index: i
});
branchTag.remove();
expr = testAttr ? _marko_compiler.types.conditionalExpression(testAttr.value, consequent, expr) : consequent;
}
const signal = getSignal(ifTagSection, nodeBinding, "if");
signal.build = () => {
const rendererArgs = [];
for (const [_, branchBodySection] of branches) if (branchBodySection) rendererArgs.push(...getBranchRendererArgs(branchBodySection).slice(0, 3));
else rendererArgs.push(void 0, void 0, void 0);
return callRuntime("_if", getScopeAccessorLiteral(nodeBinding, true), ...trimEmptyArgs(rendererArgs));
};
addValue(ifTagSection, getReferencedBindings(ifTagExtra), signal, expr);
}
} }
}),
parseOptions: { controlFlow: true },
autocomplete: [{
snippet: "if=${1:condition}",
description: "Use to display content only if the condition is met.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#if--else"
}]
};
const ElseIfTag = {
...IfTag,
autocomplete: [{
snippet: "else-if=${1:condition}",
description: "Use after an <if> or <else-if> tag to display content if those conditions do not match and this one does.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#if--else"
}]
};
const ElseTag = {
...IfTag,
autocomplete: [{
description: "Use after an <if> or <else-if> tag to display content if those conditions do not match.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#if--else"
}]
};
function flattenTextOnlyConditional(rootTag) {
if (!isCoreTagName(rootTag, "if")) return;
const tagBody = rootTag.parentPath;
if (!tagBody.isMarkoTagBody()) return;
const parentTag = tagBody.parentPath;
if (!parentTag.isMarkoTag() || analyzeTagNameType(parentTag) !== 0) return;
const branches = [];
let tag = rootTag;
do {
const { node } = tag;
if (node.body.attributeTags) return;
for (const child of node.body.body) if (_marko_compiler.types.isMarkoText(child)) {
if (_escape(child.value) !== child.value) return;
} else if (!_marko_compiler.types.isMarkoPlaceholder(child) || !child.escape) return;
branches.push(tag);
} while (tag = getNextBranchTag(tag));
for (const branchTag of branches) assertValidCondition(branchTag);
let expr = _marko_compiler.types.stringLiteral("");
let needsTextCoercion = false;
for (let i = branches.length; i--;) {
const branchTag = branches[i];
const text = bodyToUncoercedText(branchTag.node.body);
needsTextCoercion ||= _marko_compiler.types.isTemplateLiteral(text);
const [conditionAttr] = branchTag.node.attributes;
expr = conditionAttr ? _marko_compiler.types.conditionalExpression(conditionAttr.value, text, expr) : text;
}
for (let i = branches.length; i-- > 1;) branches[i].remove();
const placeholder = _marko_compiler.types.markoPlaceholder(expr, true);
if (needsTextCoercion) (placeholder.extra ??= {}).needsTextCoercion = true;
rootTag.replaceWith(placeholder);
}
function assertValidCondition(tag) {
const conditionTagName = getTagName(tag);
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag, conditionTagName === "else" ? "Write the condition as an attribute instead: `<else if=condition>`." : `Write the condition as a value attribute instead: \`<${conditionTagName}=condition>\`.`);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertHasBody(tag);
assertNoSpreadAttrs(tag);
switch (getTagName(tag)) {
case "if":
assertOnlyValueAttr(tag, true);
break;
case "else-if":
assertOnlyValueAttr(tag, true);
assertHasPrecedingCondition(tag);
break;
case "else":
assertOptionalIfAttribute(tag);
assertHasPrecedingCondition(tag);
}
}
function assertHasPrecedingCondition(tag) {
let prev = tag.getPrevSibling();
while (prev.node && prev.isMarkoComment()) prev = prev.getPrevSibling();
if (!isConditionTag(prev) || getTagName(prev) === "else" && !prev.node.attributes.length) throw tag.buildCodeFrameError(`The [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#if--else) must have a preceding \`<if=cond>\` or \`<else if=cond>\`.`);
}
function assertOptionalIfAttribute(tag) {
const { attributes } = tag.node;
if (attributes.length > 1 || attributes.length === 1 && !isIfAttr(attributes[0])) {
const ifAttr = attributes.find(isIfAttr);
throw buildAttrsError(tag, attributes.filter((attr) => attr !== ifAttr), "The [`<else>` tag](https://markojs.com/docs/reference/core-tag#if--else) only supports the `if=` attribute.");
}
}
function getBranches(tag) {
let branches = BRANCHES_LOOKUP.get(tag);
if (!branches) {
let curTag = tag;
branches = [];
do {
BRANCHES_LOOKUP.set(curTag, branches);
branches.push([curTag, getSectionForBody(curTag.get("body"))]);
} while (curTag = getNextBranchTag(curTag));
}
return branches;
}
function getNextBranchTag(tag) {
let next = tag.getNextSibling();
while (next.isMarkoComment()) next = next.getNextSibling();
if (isCoreTagName(next, "else-if") || isCoreTagName(next, "else")) return next;
}
function isLastBranch(tag) {
const branches = getBranches(tag);
return branches[branches.length - 1][0] === tag;
}
function isIfAttr(attr) {
return attr.type === "MarkoAttribute" && attr.name === "if";
}
//#endregion
//#region src/translator/core/import.ts
var import_default = {
parse(tag) {
tag.replaceWith(parseSingleStatement(tag, "The [`<import>` tag](https://markojs.com/docs/reference/language#import) takes a single import statement."));
},
parseOptions: {
statement: true,
rawOpenTag: true
},
autocomplete: [{
displayText: "import <scope> from \"<path>\"",
description: "Use to import external modules, follows the same syntax as JavaScript imports.",
snippet: "import ${2} from \"${1:path}\"",
descriptionMoreURL: "https://markojs.com/docs/reference/language#import"
}]
};
//#endregion
//#region src/translator/util/finalize-references.ts
function finalizeReferences() {
const intersectionsBySection = /* @__PURE__ */ new Map();
settleAssignments();
pruneBindings();
removeDroppedAssignments();
excludeAssignedChangeHandlers();
resolveReads(intersectionsBySection);
forEachSection(finalizeContentDerives);
resolveBindings();
forEachSection(addSectionReasons);
for (const finalize of getReferenceFinalizers()) finalize();
forEachSection(applyReasonExprs);
solveReasons(intersectionsBySection);
finalizeRegistrations();
allocateIds(intersectionsBySection);
getReadsByExpression().clear();
getFunctionReadsByExpression().clear();
}
function settleAssignments() {
for (const idExtra of getAssignments()) if (inEmittedExpr(idExtra)) {
const binding = idExtra.assignment;
binding.assignments = push(binding.assignments, idExtra);
}
}
function pruneBindings() {
const bindings = getBindings();
for (const binding of bindings) if (binding.type !== 0) {
if (pruneBinding(binding)) bindings.delete(binding);
}
}
function removeDroppedAssignments() {
for (const idExtra of getAssignments()) if (!inEmittedExpr(idExtra)) {
const binding = idExtra.assignment;
binding.assignments = filter(binding.assignments, inEmittedExpr);
}
}
function excludeAssignedChangeHandlers() {
const excluded = /* @__PURE__ */ new Set();
for (const { assignment: binding } of getAssignments()) if (binding.assignments && binding.aliasOf && binding.property !== void 0 && !excluded.has(binding)) {
excluded.add(binding);
for (const alias of binding.aliasOf.aliases) if (propsUtil.has(alias.excludeProperties, binding.property)) alias.excludeProperties = propsUtil.add(alias.excludeProperties, binding.property + "Change");
}
}
function resolveReads(intersectionsBySection) {
const fnReadsByExpression = getFunctionReadsByExpression();
for (const [expr, reads] of getReadsByExpression()) if (isReferencedExtra(expr)) {
const exprBindings = resolveReferencedBindings(expr, reads, intersectionsBySection);
setResolvedReads(expr, exprBindings.referencedBindings, exprBindings.lazyBindings);
if (exprBindings.globalBindings) (0, _marko_compiler_babel_utils.getProgram)().node.extra.hasGlobalRead = true;
if (!exprBindings.referencedBindings) addSetupWork(expr.section);
forEach(exprBindings.lazyBindings, markLazyRead);
if (exprBindings.closureBindings) expr.section.referencedClosures = bindingUtil.union(expr.section.referencedClosures, exprBindings.closureBindings);
if (exprBindings.closureSection) {
setReadsOwner(expr.section, exprBindings.closureSection);
if (readsValuesOnResume(expr)) addOwnerReason(expr.section, exprBindings.closureSection, ALWAYS);
}
if (exprBindings.hoistedSection) {
setReadsOwner(expr.section, exprBindings.hoistedSection);
addOwnerReason(expr.section, exprBindings.hoistedSection, ALWAYS);
}
if (expr.isEffect) {
if (readsValuesOnResume(expr)) {
forEach(exprBindings.referencedBindings, addAlwaysReason);
forEach(exprBindings.constantBindings, addAlwaysReason);
}
forEach(exprBindings.lazyBindings, addAlwaysReason);
} else forEach(reads, (read) => {
if (!read.fnRoot && read.extra.exprRoot?.retained) addReasonExprs(ensureSlot(read.binding), expr);
});
if (exprBindings.allBindings) {
const exprFnReads = fnReadsByExpression.get(expr);
if (exprFnReads) for (const [fn, fnReads] of exprFnReads) {
const fnBindings = fn === expr ? exprBindings : resolveReferencedBindingsInFunction(expr, exprBindings.allBindings, fnReads);
setResolvedFunctionReads(fn, fn === expr ? bindingUtil.union(fnBindings.referencedBindings, exprBindings.lazyBindings) : fnBindings.referencedBindings, fnBindings.constantBindings);
}
}
}
}
function resolveBindings() {
const bindingNamesBySection = /* @__PURE__ */ new Map();
for (const binding of getBindings()) {
const { name, section } = binding;
if (binding.type === 6) {
resolveBindingSources(binding);
continue;
}
if (binding.type !== 0) {
resolveBindingSources(binding);
forEach(binding.assignments, ({ section: assignedSection }) => {
setReadsOwner(assignedSection, section);
addOwnerReason(assignedSection, section, ALWAYS);
});
let bindingNames = bindingNamesBySection.get(section);
if (!bindingNames) {
bindingNamesBySection.set(section, bindingNames = /* @__PURE__ */ new Set());
forEach(section.bindings, ({ name }) => bindingNames.add(name));
}
if (bindingNames.has(binding.name)) binding.name = generateUid(name);
}
if (binding.hoists) {
const highestHoistSection = first(binding.hoists);
addAlwaysReason(binding);
binding.section.hoisted = bindingUtil.add(binding.section.hoisted, binding);
for (let section = binding.section; section !== highestHoistSection; section = section.parent) {
if (!isOptionalBranch(section)) addReason(ensureSectionSlot(section, 10, section.parent), ALWAYS);
if (section.parent !== highestHoistSection) section.parent.isHoistThrough = true;
}
}
const canonicalBinding = getCanonicalBinding(binding);
section.bindings = bindingUtil.add(section.bindings, canonicalBinding);
bindingNamesBySection.get(section)?.add(canonicalBinding.name);
if (binding.localOf) section.localClosures = bindingUtil.add(section.localClosures, binding);
}
}
function addSectionReasons(section) {
if (section.isHoistThrough) addReason(ensureSectionSlot(section, 6), ALWAYS);
forEach(section.referencedClosures, (closure) => {
closure.closureSections = sectionUtil.add(closure.closureSections, section);
addOwnerReason(section, closure.section, closure.sources);
});
if (isOptionalBranch(section)) {
const closureSources = getSourcesForRef(getDirectClosures(section));
const branchSlot = ensureSectionSlot(section, 9);
addReason(branchSlot, section.isHoistThrough || section.hoisted ? mergeSources(ALWAYS, closureSources) : closureSources);
addReasonExprs(branchSlot, section.branchExpr);
addReasonExprs(ensureSlot(section.branch.nodeBinding), section.branchExpr);
}
}
function allocateIds(intersectionsBySection) {
const closureIdEnds = /* @__PURE__ */ new Map();
forEachSection((section) => {
const { bindings } = section;
const intersectionSources = /* @__PURE__ */ new Map();
const intersectionMeta = section.intersections = /* @__PURE__ */ new Map();
const intersections = (intersectionsBySection.get(section) || []).filter((intersection) => {
const source = getIntersectionSource(intersection, section, intersectionSources);
if (source) intersectionMeta.set(intersection, { source });
return !source;
});
let anchors;
if (intersections.length) {
const sectionAnchors = anchors = /* @__PURE__ */ new Map();
for (const intersection of intersections) {
const anchor = last(intersection);
if (anchor.section === section) sectionAnchors.set(intersection, anchor);
}
intersections.sort((a, b) => {
const aAnchor = sectionAnchors.get(a);
const bAnchor = sectionAnchors.get(b);
return aAnchor ? bAnchor ? bindingUtil.compare(aAnchor, bAnchor) : 1 : bAnchor ? -1 : 0;
});
}
let intersectionIndex = 0;
let nextId = 0;
const walked = /* @__PURE__ */ new Set();
for (const op of section.structure || []) {
const binding = getWalkedBinding(op);
if (binding) {
walked.add(binding);
binding.id = nextId++;
nextId += binding.reserveSize;
}
}
let intersection;
const assignIntersectionId = (intersection) => {
intersectionMeta.set(intersection, {
source: void 0,
id: nextId++,
returnedBy: getLastOwnSourceReturn(intersection, section)
});
};
forEach(bindings, (binding) => {
if (walked.has(binding)) return;
if (binding.type !== 0) while (intersectionIndex < intersections.length && !anchors.get(intersection = intersections[intersectionIndex])) {
intersectionIndex++;
assignIntersectionId(intersection);
}
binding.id = nextId++;
nextId += binding.reserveSize;
while (intersectionIndex < intersections.length && anchors.get(intersection = intersections[intersectionIndex]) === binding) {
intersectionIndex++;
assignIntersectionId(intersection);
}
});
while (intersectionIndex < intersections.length) {
intersection = intersections[intersectionIndex];
intersectionIndex++;
assignIntersectionId(intersection);
}
let closureId = section.parent ? closureIdEnds.get(section.parent) : 0;
forEach(bindings, (binding) => {
if (binding.closureSections) {
closureId = Math.max(closureId, nextId);
binding.closureId = closureId++;
}
});
closureIdEnds.set(section, closureId);
});
}
function getWalkedBinding(op) {
return typeof op === "object" && (op.kind === "node" || op.kind === "child") ? op.binding : void 0;
}
function getLastOwnSourceReturn(intersection, section) {
let last;
const seen = /* @__PURE__ */ new Set();
const track = (binding) => {
if (binding.section === section && !seen.has(binding)) {
seen.add(binding);
const { returnedBy } = getAliasRoot(binding);
if (returnedBy && (!last || last.id < returnedBy.id)) last = returnedBy;
if (binding.derivedFrom) forEach(getValueReferences(binding.derivedFrom), track);
forEach(binding.sources?.state, track);
forEach(binding.sources?.param, track);
}
};
forEach(intersection, track);
return last;
}
function getIntersectionSource(intersection, section, resolved) {
if (!resolved.has(intersection)) {
resolved.set(intersection, void 0);
resolved.set(intersection, resolveIntersectionSource(intersection, section, resolved));
}
return resolved.get(intersection);
}
function resolveIntersectionSource(intersection, section, resolved) {
let sources;
for (const member of intersection) {
if (!member.sources) return void 0;
if (member.section !== section || isDirectAlias(member)) return void 0;
const rootIntersection = getRootIntersection(member);
if (rootIntersection && rootIntersection !== intersection && !getIntersectionSource(rootIntersection, section, resolved)) return;
sources = mergeSources(sources, member.sources);
}
if (!sources || sources.state && sources.param) return;
const source = sources.state || sources.param;
return source && !Array.isArray(source) && source.section === section && !source.returnedBy ? source : void 0;
}
const [getResolvedSources] = createProgramState(() => /* @__PURE__ */ new Set());
function resolveBindingSources(binding) {
const resolvedSources = getResolvedSources();
if (resolvedSources.has(binding)) return;
resolvedSources.add(binding);
switch (binding.type) {
case 1: {
const aliasRoot = getAliasRoot(binding);
if (aliasRoot !== binding) {
resolveBindingSources(aliasRoot);
binding.sources = aliasRoot.sources;
} else if (binding.assignments) binding.sources = createSources(binding, void 0);
else resolveDerivedSources(binding);
return;
}
case 2:
binding.sources = createSources(void 0, getCanonicalBinding(binding));
return;
case 6:
binding.sources = globalSources;
return;
}
const aliasRoot = getAliasRoot(binding);
if (aliasRoot !== binding) {
if (!resolvedSources.has(aliasRoot)) {
resolvedSources.add(aliasRoot);
resolveDerivedSources(aliasRoot);
}
binding.sources = aliasRoot.sources;
} else resolveDerivedSources(binding);
}
function resolveDerivedSources(binding) {
const exprs = binding.derivedFrom;
if (exprs === void 0) binding.sources = createSources(binding, void 0);
else if (exprs) {
const refs = getValueReferences(exprs);
binding.sources = reduce(refs, mergeResolvedSources, binding.sources);
binding.intersection = Array.isArray(refs) ? refs : refs && getRootIntersection(refs);
}
}
function mergeResolvedSources(sources, ref) {
resolveBindingSources(ref);
return mergeSources(sources, ref.sources);
}
function getRootIntersection(binding) {
return getAliasRoot(binding).intersection;
}
function readsValuesOnResume(expr) {
return !!expr.isEffect && !expr.retained;
}
function isEmitted(exprExtra) {
return !getCanonicalExtra(exprExtra).dropped;
}
function inEmittedExpr({ exprRoot, section }) {
return !section.dropped && isEmitted(exprRoot);
}
function isDroppableValue(expr) {
return (!!expr.pure || !!expr.callSiteExprs) && !expr.merged && !expr.dropped;
}
function dropUnreadValue(expr) {
if (isDroppableValue(expr) && every(expr.derives, isPrunedBinding)) dropExtra(expr);
}
function isPrunedBinding(binding) {
return !!binding.pruned;
}
function pruneBinding(binding) {
if (binding.pruned !== void 0) return binding.pruned;
binding.pruned = false;
for (const read of binding.reads.keys()) pruneDerived(read);
forEach(binding.assignments, pruneAssignmentDerived);
const assignedObject = getAssignedObject(binding);
for (const [expr, reads] of binding.reads) {
const ancestor = assignedObject ? getNearestReadBy(assignedObject, expr) || assignedObject : getNearestReadBy(binding.aliasOf, expr);
if (ancestor) {
ancestor.reads.set(expr, concat(ancestor.reads.get(expr), reads));
binding.reads.delete(expr);
}
}
let shouldPrune = true;
for (const alias of binding.aliases) if (pruneBinding(alias)) binding.aliases.delete(alias);
else if (alias.type !== 5) shouldPrune = false;
for (const [key, alias] of binding.propertyAliases) if (pruneBinding(alias)) binding.propertyAliases.delete(key);
else if (alias.type !== 5) shouldPrune = false;
shouldPrune &&= !binding.reads.size && !(binding.reserveSize && hasEmittedAssignment(binding));
binding.pruned = shouldPrune;
if (shouldPrune && !hasEmittedAssignment(binding)) {
if (binding.derivedFrom) forEach(binding.derivedFrom, dropUnreadValue);
}
return shouldPrune;
}
function hasEmittedAssignment(binding) {
return some(binding.assignments, inEmittedExpr);
}
function pruneAssignmentDerived({ exprRoot }) {
pruneDerived(exprRoot);
}
function pruneDerived(expr) {
if (isDroppableValue(expr)) forEach(expr.derives, pruneBinding);
}
function resolveReferencedBindingsInFunction(expr, refs, reads) {
let referencedBindings;
let constantBindings;
const closest = /* @__PURE__ */ new Set();
forEach(reads, ({ getter, binding }) => {
if (getter) {} else if (binding.type === 5) {
if (bindingUtil.has(refs, binding)) constantBindings = bindingUtil.add(constantBindings, binding);
} else if (binding.type !== 0 && binding.type !== 6) closest.add(getNearestReadBy(binding, expr));
});
if (closest.size) referencedBindings = bindingUtil.filter(refs, (ref) => closest.has(ref));
return {
referencedBindings,
constantBindings
};
}
function getNearestReadBy(binding, expr) {
for (let cur = binding; cur; cur = cur.aliasOf) if (cur.reads.has(expr)) return cur;
}
function markLazyRead(binding) {
binding.hasLazyReads = true;
}
function addBindingGetter(binding, { invoked, hoisted }) {
if (!invoked || !binding.getters.has(hoisted)) {
if (hoisted === binding.section) binding.getters.delete(false);
if (hoisted || !binding.getters.has(binding.section)) binding.getters.set(hoisted, !invoked);
}
}
function isLazyRead(expr, read, binding, isChangeHandlerRead) {
return !!(expr.invokeOnly && read.deferred && !isChangeHandlerRead && (!binding.aliasOf || isParamBinding(binding)) && binding.type !== 5);
}
function isParamBinding(binding) {
const root = getAliasRoot(binding);
return root === root.section.params;
}
function resolveReferencedBindings(expr, reads, intersectionsBySection) {
let referencedBindings;
let constantBindings;
let allBindings;
let lazyBindings;
let globalBindings;
let closureBindings;
let closureSection;
let hoistedSection;
forEach(reads, (read) => {
let { binding } = read;
const { extra, getter } = read;
if (getter) {
extra.section = expr.section;
extra.read = createResolvedGetterRead(binding, void 0, getter);
addBindingGetter(binding, getter);
if (getter.hoisted) {
binding.hoists = sectionUtil.add(binding.hoists, getter.hoisted);
if (!hoistedSection || getter.hoisted.depth < hoistedSection.depth) hoistedSection = getter.hoisted;
}
} else {
const isChangeHandlerRead = extra.assignmentTo === binding;
if (isChangeHandlerRead) {
const ancestor = getNearestReadBy(binding.aliasOf, expr);
if (ancestor) binding = ancestor;
} else if (binding.type !== 6) {
extra.section = expr.section;
({binding} = extra.read = resolveConstantReference(binding) ?? resolveExpressionReference(expr, read));
}
if (binding.type === 6) globalBindings = bindingUtil.add(globalBindings, binding);
else if (binding.type !== 0) {
const isLazy = isLazyRead(expr, read, binding, isChangeHandlerRead);
if (isLazy) lazyBindings = bindingUtil.add(lazyBindings, binding);
else if (binding.type === 5) constantBindings = bindingUtil.add(constantBindings, binding);
else referencedBindings = bindingUtil.add(referencedBindings, binding);
if (binding.section !== expr.section) {
const closure = getConstantRoot(binding) ?? getCanonicalBinding(binding);
if (!isLazy) closureBindings = bindingUtil.add(closureBindings, closure);
if (!closureSection || closure.section.depth < closureSection.depth) closureSection = closure.section;
}
}
}
allBindings = bindingUtil.add(allBindings, binding);
});
lazyBindings = bindingUtil.difference(lazyBindings, referencedBindings);
if (Array.isArray(referencedBindings)) referencedBindings = getCanonicalIntersection(intersectionsBySection, expr.section, referencedBindings);
if (referencedBindings && constantBindings) getCanonicalIntersection(intersectionsBySection, expr.section, bindingUtil.union(referencedBindings, constantBindings));
return {
referencedBindings,
constantBindings,
allBindings,
lazyBindings,
globalBindings,
closureBindings,
closureSection,
hoistedSection
};
}
function getCanonicalIntersection(intersectionsBySection, section, intersection) {
const intersections = intersectionsBySection.get(section) || [];
const canonical = findSorted(compareIntersections, intersections, intersection);
if (canonical) return canonical;
intersectionsBySection.set(section, addSorted(compareIntersections, intersections, intersection));
return intersection;
}
function resolveConstantReference(binding) {
const root = getConstantRoot(binding);
return root && createResolvedRead(root, getPropertyPath(binding, root));
}
function getConstantRoot(binding) {
let root;
for (let cur = binding; cur.aliasOf; cur = cur.aliasOf) {
if (cur.property === void 0 && !isDirectAlias(cur)) break;
if (cur.aliasOf.type === 5) root = cur.aliasOf;
}
return root;
}
function resolveExpressionReference(expr, { binding, inOwnBody }) {
const ancestor = getNearestReadBy(binding.aliasOf, expr);
return ancestor ? createResolvedRead(ancestor, getPropertyPath(binding, ancestor)) : createResolvedRead(binding, void 0, inOwnBody);
}
//#endregion
//#region src/translator/core/let.ts
var let_default = {
analyze(tag) {
const { node } = tag;
const tagVar = node.var;
let valueAttr;
let valueChangeAttr;
for (const attr of node.attributes) if (_marko_compiler.types.isMarkoAttribute(attr)) {
if (attr.name === "value") {
if (valueAttr) throw tag.hub.buildError(attr, "Invalid duplicate value attribute.");
valueAttr = attr;
} else if (attr.name === "valueChange") {
if (valueChangeAttr) throw tag.hub.buildError(attr, "Invalid duplicate valueChange attribute.");
valueChangeAttr = attr;
}
}
assertNoSpreadAttrs(tag);
assertOnlyValueAttr(tag, false, true, tagVar ? void 0 : getDeclarationHint);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
assertHasVar(tag, "For example: `<let/count=0>`.");
assertIdentifierVar(tag);
if (valueChangeAttr && (0, _marko_compiler_babel_utils.computeNode)(valueChangeAttr.value)?.value) throw tag.get("attributes").find((attr) => attr.node === valueChangeAttr).get("value").buildCodeFrameError("The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) [`valueChange=` attribute](https://markojs.com/docs/reference/core-tag#controllable-let) must be a function.");
const tagSection = ensureSection(tag);
const binding = trackVarReferences(tag, 1);
const tagExtra = mergeReferences(tagSection, tag.node, [valueAttr?.value, valueChangeAttr?.value]);
setDerivedFrom(binding, tagExtra);
if (valueChangeAttr) {
const changeSlot = ensureSlot(binding, 1);
reserveId(binding, 1);
tagExtra.retained = true;
tagExtra.pure = (!valueAttr || evaluate(valueAttr.value).pure) && evaluate(valueChangeAttr.value).pure;
onFinalizeReferences(() => {
if (binding.assignments) addReason(changeSlot, ALWAYS);
});
} else {
tagExtra.initialValue = true;
tagExtra.pure = !valueAttr || evaluate(valueAttr.value).pure;
}
},
translate: { exit(tag) {
const { node } = tag;
if (node.extra?.dropped) {
tag.remove();
return;
}
const tagVar = node.var;
const valueAttr = node.attributes.find((attr) => _marko_compiler.types.isMarkoAttribute(attr) && (attr.default || attr.name === "value")) ?? _marko_compiler.types.markoAttribute("value", _marko_compiler.types.identifier("undefined"));
const valueChangeAttr = node.attributes.find((attr) => _marko_compiler.types.isMarkoAttribute(attr) && attr.name === "valueChange");
const section = getSection(tag);
const binding = tagVar.extra.binding;
const unused = binding.pruned && !hasEmittedAssignment(binding);
if (isOutputDOM()) {
const referencedBindings = getReferencedBindings(tag.node.extra);
if (unused) {
for (const attr of [valueAttr, valueChangeAttr]) if (attr && !evaluate(attr.value).pure) addValue(section, referencedBindings, initValue(binding), attr.value);
tag.remove();
return;
}
const signal = initValue(binding, true);
addValue(section, referencedBindings, signal, valueAttr.value);
if (valueChangeAttr) signal.extraArgs = [valueChangeAttr.value];
signal.buildAssignment = (valueSection, value) => {
if (valueChangeAttr || signalHasWork(signal)) return _marko_compiler.types.callExpression(signal.identifier, [getScopeExpression(valueSection, signal.section), value]);
};
} else {
translateVar(tag, valueAttr.value, "let");
if (unused) {
if (valueChangeAttr && !evaluate(valueChangeAttr.value).pure) tag.insertBefore(_marko_compiler.types.expressionStatement(valueChangeAttr.value));
} else if (valueChangeAttr) {
const accessor = writeSlot(findSlot(binding, 1), _marko_compiler.types.logicalExpression("||", valueChangeAttr.value, _marko_compiler.types.buildUndefinedNode()));
if (accessor && !isOptimize()) {
const { root, access } = getDebugAccess(binding, false, toAccess);
setSectionDebugVar(section, accessor, `${root.name + access}Change`, root.loc);
}
}
}
tag.remove();
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
description: "Use to create a mutable binding.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#let"
}],
types: runtime_info_default.name + "/tags/let.d.marko"
};
function getDeclarationHint(attr) {
if (/^[A-Za-z_$][\w$]*$/.test(attr.name)) return `To declare reactive state, the variable goes after a slash: \`<let/${attr.name}=...>\`. For a one time module level value, prefix a plain JavaScript statement with \`static\`.`;
}
//#endregion
//#region src/translator/core/lifecycle.ts
const [getIndex, setIndex] = createSectionState("lifecycleIndex", () => 0);
var lifecycle_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
assertNoSpreadAttrs(tag);
const { node } = tag;
const section = ensureSection(tag);
for (const attr of node.attributes) (attr.value.extra ??= {}).consumed = true;
const tagExtra = mergeTagReferences(section, tag.node);
tagExtra.isEffect = true;
section.hasAbortSignal = true;
if (node.attributes.length === 0) throw tag.get("name").buildCodeFrameError("The [`<lifecycle>` tag](https://markojs.com/docs/reference/core-tag#lifecycle) requires at least one attribute.");
(0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
},
translate: { exit(tag) {
const { node } = tag;
const section = getSection(tag);
const tagExtra = node.extra;
const referencedBindings = getReferencedBindings(tagExtra);
if (isOutputDOM()) {
const translatedAttrs = translateAttrs(tag);
const index = getIndex(section);
setIndex(section, index + 1);
translatedAttrs.statements.push(_marko_compiler.types.expressionStatement(callRuntime("_lifecycle", scopeIdentifier, propsToExpression(translatedAttrs.properties), index > 0 ? _marko_compiler.types.numericLiteral(index) : void 0)));
addStatement("effect", section, referencedBindings, translatedAttrs.statements);
} else addHTMLEffectCall(section, referencedBindings);
tag.remove();
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
description: "Use to create side effects.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#lifecycle"
}],
types: runtime_info_default.name + "/tags/lifecycle.d.marko"
};
//#endregion
//#region src/translator/core/log.ts
var log_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
const valueAttr = assertOnlyValueAttr(tag, true);
addSetupExpr(ensureSection(tag), valueAttr.value);
},
translate: { exit(tag) {
addTagStatement(tag, _marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(_marko_compiler.types.memberExpression(_marko_compiler.types.identifier("console"), _marko_compiler.types.identifier("log")), [tag.node.attributes[0].value])));
} },
parseOptions: { openTagOnly: true },
attributes: {},
autocomplete: [{
description: "Use to log a value to the console.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#log"
}],
types: runtime_info_default.name + "/tags/log.d.marko"
};
//#endregion
//#region src/translator/core/return.ts
var return_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
assertNoSpreadAttrs(tag);
let valueAttr;
let valueChangeAttr;
for (const attr of tag.node.attributes) if (_marko_compiler.types.isMarkoAttribute(attr)) {
if (attr.name === "value") {
if (valueAttr) throw tag.hub.buildError(attr, "Invalid duplicate value attribute.");
valueAttr = attr;
} else if (attr.name === "valueChange") {
if (valueChangeAttr) throw tag.hub.buildError(attr, "Invalid duplicate valueChange attribute.");
valueChangeAttr = attr;
}
}
assertOnlyValueAttr(tag, true, true);
const parentTag = getParentTag(tag);
if (parentTag) {
if ((0, _marko_compiler_babel_utils.isNativeTag)(parentTag)) throw tag.get("name").buildCodeFrameError("The [`<return>` tag](https://markojs.com/docs/reference/core-tag#return) can not be used in a [native tag](https://markojs.com/docs/reference/native-tag).");
else if (getTagFacts(parentTag).controlFlow) throw tag.get("name").buildCodeFrameError(`The [\`<return>\` tag](https://markojs.com/docs/reference/core-tag#return) can not be used under the \`<${parentTag.get("name").toString()}>\` tag.`);
}
const section = ensureSection(tag);
if (section.returnValueExpr) throw tag.get("name").buildCodeFrameError(`Cannot have multiple [\`<return>\` tags](https://markojs.com/docs/reference/core-tag#return) ${tag.parent.type === "Program" ? "for the template" : "within a tag's body content"}.`);
const attrs = getKnownAttrValues(tag.node);
if (attrs.valueChange) {
(attrs.valueChange.extra ??= {}).isEffect = true;
addSetupExpr(section, attrs.valueChange);
addReason(ensureSectionSlot(section, 8), ALWAYS);
}
addSetupExpr(section, attrs.value);
section.returnValueExpr = attrs.value.extra ??= {};
},
translate: translateByTarget({
html: { exit(tag) {
const section = getSection(tag);
const attrs = getKnownAttrValues(tag.node);
flushBefore(tag);
if (attrs.valueChange) writeSlot(findSectionSlot(section, 8), _marko_compiler.types.logicalExpression("||", attrs.valueChange, _marko_compiler.types.buildUndefinedNode()));
if (attrs.value) {
const returnId = generateUidIdentifier("return");
setReturnValueIdentifier(section, returnId);
tag.replaceWith(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(returnId, attrs.value)]))[0].skip();
}
} },
dom: { exit(tag) {
const section = getSection(tag);
const attrs = getKnownAttrValues(tag.node);
if (attrs.value) addStatement("render", section, getReferencedBindings(attrs.value.extra), callRuntime("_return", scopeIdentifier, attrs.value));
if (attrs.valueChange) addStatement("render", section, getReferencedBindings(attrs.valueChange.extra), callRuntime("_return_change", scopeIdentifier, attrs.valueChange));
tag.remove();
} }
}),
parseOptions: { openTagOnly: true },
autocomplete: [{
displayText: "return=<value>",
description: "Provides a value for use in a parent template.",
snippet: "return=${1:value}",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#return"
}]
};
//#endregion
//#region src/translator/core/script.ts
const htmlScriptTagAlternateMsg = " For a native html [`<script>` tag](https://markojs.com/docs/reference/core-tag#script) use the `html-script` core tag instead.";
var script_default = {
parse(tag) {
const { node } = tag;
const { body } = node.body;
if (body.length) {
let code = "";
for (const child of body) {
if (child.type !== "MarkoText") throw (0, _marko_compiler_babel_utils.getFile)().hub.buildError(child, "Unexpected content in [`<script>` tag](https://markojs.com/docs/reference/core-tag#script). Only javascript and typescript is supported." + htmlScriptTagAlternateMsg, SyntaxError);
code += child.value;
}
const start = body[0]?.start;
const end = body[body.length - 1]?.end;
const block = (0, _marko_compiler_babel_utils.parseBlock)((0, _marko_compiler_babel_utils.getFile)(), code, start, end);
if (block.body.length || block.innerComments) {
const valueFn = _marko_compiler.types.arrowFunctionExpression([], block, !!traverseFindAwait(block));
node.attributes.push(_marko_compiler.types.markoAttribute("value", valueFn));
}
node.body.body = [];
}
},
analyze(tag) {
const { node } = tag;
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoBodyContent(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
if (node.var) throw tag.hub.buildError(node.var, "The [`<script>` tag](https://markojs.com/docs/reference/core-tag#script) does not support a tag variable reference." + htmlScriptTagAlternateMsg);
let seenValueAttr = false;
for (const attr of node.attributes) if (attr.type === "MarkoAttribute" && attr.name === "value") {
if (seenValueAttr) throw tag.hub.buildError(attr, "Invalid duplicate value attribute.");
seenValueAttr = true;
if (!isEmptyFunction(attr.value)) {
const valueExtra = attr.value.extra ??= {};
valueExtra.isEffect = true;
valueExtra.consumed = true;
addSetupExpr(ensureSection(tag), attr.value);
(0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
}
} else throw tag.hub.buildError(attr, "The [`<script>` tag](https://markojs.com/docs/reference/core-tag#script) does not support html attributes." + htmlScriptTagAlternateMsg);
if (!seenValueAttr) dropNodes(getAllTagReferenceNodes(node));
},
translate: { exit(tag) {
const { node } = tag;
const [valueAttr] = node.attributes;
if (!valueAttr?.value.extra?.isEffect) {
tag.remove();
return;
}
const section = getSection(tag);
const { value } = valueAttr;
const referencedBindings = getReferencedBindings(value.extra);
const isFunction = _marko_compiler.types.isFunctionExpression(value) || _marko_compiler.types.isArrowFunctionExpression(value);
if (isFunction && _marko_compiler.types.isBlockStatement(value.body) && traverseContains(value.body, isReturnedFunction)) (0, _marko_compiler_babel_utils.diagnosticWarn)(tag, { label: "The value returned from a [`<script>`](https://markojs.com/docs/reference/core-tag#script) body is discarded, so this cleanup function will never run. Register it with [`$signal.onabort`](https://markojs.com/docs/reference/language#signal) or use [`<lifecycle onDestroy>`](https://markojs.com/docs/reference/core-tag#lifecycle) instead." });
if (isOutputDOM()) {
let inlineBody = null;
if (isFunction) {
if (value.async || value.generator) {} else if (_marko_compiler.types.isBlockStatement(value.body)) {
if (!traverseContains(value.body, isReturnStatement)) {
let hasDeclaration = false;
for (const child of value.body.body) if (_marko_compiler.types.isDeclaration(child)) {
hasDeclaration = true;
break;
}
inlineBody = hasDeclaration ? value.body : value.body.body;
}
} else inlineBody = _marko_compiler.types.expressionStatement(value.body);
}
addStatement("effect", section, referencedBindings, inlineBody || _marko_compiler.types.callExpression(value, []));
} else addHTMLEffectCall(section, referencedBindings);
tag.remove();
} },
parseOptions: {
text: true,
preserveWhitespace: true
},
autocomplete: [{
description: "Use to create side effects.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#script"
}],
types: runtime_info_default.name + "/tags/script.d.marko"
};
function isEmptyFunction(node) {
return (_marko_compiler.types.isFunctionExpression(node) || _marko_compiler.types.isArrowFunctionExpression(node)) && _marko_compiler.types.isBlockStatement(node.body) && !node.body.body.length;
}
function isReturnedFunction(node) {
switch (node.type) {
case "FunctionDeclaration":
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassMethod":
case "ObjectMethod":
case "ClassPrivateMethod": return skip;
case "ReturnStatement": return _marko_compiler.types.isFunctionExpression(node.argument) || _marko_compiler.types.isArrowFunctionExpression(node.argument);
default: return false;
}
}
function isReturnStatement(node) {
switch (node.type) {
case "FunctionDeclaration":
case "FunctionExpression":
case "ArrowFunctionExpression":
case "ClassMethod":
case "ObjectMethod":
case "ClassPrivateMethod": return skip;
case "ReturnStatement": return true;
default: return false;
}
}
//#endregion
//#region src/translator/core/server.ts
var server_default = createStatementTag("server");
//#endregion
//#region src/translator/core/show.ts
const kStartBinding = Symbol("<show> range start binding");
const kEndBinding = Symbol("<show> range end binding");
const kStaticDisplay = Symbol("<show> static display");
const kSingleNodeBody = Symbol("<show> single node body");
const htmlDisplayRefs = /* @__PURE__ */ new WeakMap();
var show_default = {
analyze: {
enter(tag) {
assertValidShow(tag);
const tagExtra = tag.node.extra ??= {};
const display = tag.node.attributes[0].value;
const displayEval = evaluate(display);
tagExtra[kSingleNodeBody] = isSingleNodeBody(tag);
if (displayEval.confident) tagExtra[kStaticDisplay] = !!displayEval.computed;
if (tagExtra[kStaticDisplay] === true) return;
assertLegalHiddenContext(tag);
const tagSection = ensureSection(tag);
if (getOnlyChildParentTagName(tag)) controlFlowNode(tag, tagSection);
else {
tagExtra[kStartBinding] = createBinding("#text", 0, tagSection);
marker(tag, tagExtra[kStartBinding]);
enterShallow(tag);
}
if (tagExtra[kStaticDisplay] === void 0) mergeReferences(tagSection, tag.node, [display]);
else addSetupWork(tagSection);
},
exit(tag) {
const tagExtra = tag.node.extra;
if (tagExtra[kStaticDisplay] === true) return;
const tagSection = getSection(tag);
if (tagExtra[kStartBinding]) {
if (!tagExtra[kSingleNodeBody]) {
tagExtra[kEndBinding] = createBinding("#text", 0, tagSection);
marker(tag, tagExtra[kEndBinding]);
enterShallow(tag);
}
controlFlowNode(tag, tagSection);
}
const nodeBinding = tagExtra.nodeBinding;
if (tagExtra[kStaticDisplay] === void 0) {
addReasonExprs(ensureSlot(nodeBinding), tagExtra);
addReasonExprs(ensureSlot(nodeBinding, 4), tagExtra);
}
}
},
translate: translateByTarget({
html: {
enter(tag) {
const tagExtra = tag.node.extra;
flushBefore(tag);
const staticDisplay = tagExtra[kStaticDisplay];
if (staticDisplay === true) return;
if (staticDisplay === false) {
writeTo$1(tag)`<t hidden>`;
return;
}
const display = tag.node.attributes[0].value;
if (!_marko_compiler.types.isIdentifier(display)) htmlDisplayRefs.set(tag.node, declareConstBefore(tag, "show", display));
},
exit(tag) {
const tagExtra = tag.node.extra;
const staticDisplay = tagExtra[kStaticDisplay];
if (staticDisplay === false) writeTo$1(tag)`</t>`;
flushInto(tag);
const bodyStatements = tag.node.body.body;
if (staticDisplay !== void 0) {
for (const replacement of tag.replaceWithMultiple(bodyStatements)) replacement.skip();
return;
}
const tagSection = getSection(tag);
const display = htmlDisplayRefs.get(tag.node) || tag.node.attributes[0].value;
const nodeBinding = tagExtra.nodeBinding;
const onlyChildParentTagName = getOnlyChildParentTagName(tag);
const singleNode = tagExtra[kSingleNodeBody];
const endArgs = buildBranchEndArgs(tagSection, nodeBinding, onlyChildParentTagName, singleNode);
const showStart = singleNode ? callRuntime("_show_start", _marko_compiler.types.cloneNode(display, true), _marko_compiler.types.numericLiteral(0)) : callRuntime("_show_start", _marko_compiler.types.cloneNode(display, true), ...buildBranchEndArgs(tagSection, nodeBinding, onlyChildParentTagName, singleNode));
const statements = [
_marko_compiler.types.expressionStatement(showStart),
...bodyStatements,
_marko_compiler.types.expressionStatement(callRuntime("_show_end", getScopeIdIdentifier(tagSection), getScopeAccessorLiteral(nodeBinding), display, ...endArgs))
];
for (const replacement of tag.replaceWithMultiple(statements)) replacement.skip();
}
},
dom: { exit(tag) {
const tagExtra = tag.node.extra;
if (tagExtra[kStaticDisplay] === true) {
tag.remove();
return;
}
const tagSection = getSection(tag);
const endBinding = tagExtra[kEndBinding];
const nodeBinding = tagExtra.nodeBinding;
const startBinding = tagExtra[kStartBinding];
const display = tagExtra[kStaticDisplay] === false ? _marko_compiler.types.booleanLiteral(false) : tag.node.attributes[0].value;
const signal = getSignal(tagSection, nodeBinding, "show");
signal.build = () => {
return callRuntime("_show", getScopeAccessorLiteral(nodeBinding, true), startBinding ? getScopeAccessorLiteral(startBinding, true) : void 0, endBinding ? getScopeAccessorLiteral(endBinding, true) : void 0);
};
addValue(tagSection, getReferencedBindings(tagExtra), signal, display);
tag.remove();
} }
}),
parseOptions: { controlFlow: true },
autocomplete: [{
snippet: "show=${1:condition}",
description: "Use to render content that is always mounted but only displayed when the condition is met.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#show"
}],
types: runtime_info_default.name + "/tags/show.d.marko"
};
function isSingleNodeBody(tag) {
let elements = 0;
for (const child of tag.get("body").get("body")) {
if (child.isMarkoComment()) continue;
if (child.isMarkoTag() && analyzeTagNameType(child) === 0 && _marko_compiler.types.isStringLiteral(child.node.name)) elements++;
else return false;
}
return elements === 1;
}
function assertValidShow(tag) {
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag, "Write the condition as a value attribute instead: `<show=condition>`.");
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
assertNoSpreadAttrs(tag);
assertHasBody(tag);
if (tag.node.body.attributeTags) throw tag.get("name").buildCodeFrameError("The [`<show>` tag](https://markojs.com/docs/reference/core-tag#show) does not support [attribute tags](https://markojs.com/docs/reference/language#attribute-tags).");
assertOnlyValueAttr(tag, true, false, getRenameHint);
}
function getRenameHint(attr) {
return `Use \`<show=condition>\` instead of \`<show ${attr.name}=condition>\`.`;
}
function assertLegalHiddenContext(tag) {
const parentTag = getParentTag(tag);
if (parentTag && getTagFacts(parentTag).discardsWrapperChildren) {
const parentName = getTagName(parentTag);
throw tag.get("name").buildCodeFrameError(`A [\`<${getTagName(tag)}>\` tag](https://markojs.com/docs/reference/core-tag#show) cannot be a direct child of \`<${parentName}>\`: hidden content is wrapped in an element that \`<${parentName}>\` discards, which would render the content instead of hiding it. Move the \`<${getTagName(tag)}>\` inside the row or option, or use [\`<if>\`](https://markojs.com/docs/reference/core-tag#if).`);
}
}
//#endregion
//#region src/translator/core/static.ts
var static_default = createStatementTag("static");
//#endregion
//#region src/translator/util/asset-imports.ts
function addAssetImport(request) {
((0, _marko_compiler_babel_utils.getFile)().metadata.marko.assetImports ??= /* @__PURE__ */ new Set()).add(request);
}
function isClientAssetImport(file, request) {
const { hydrateIncludeImports } = file.markoOpts;
return typeof hydrateIncludeImports === "function" ? hydrateIncludeImports(request) : !!hydrateIncludeImports?.test(request);
}
//#endregion
//#region src/translator/util/style-interpolation.ts
const htmlStyleTagAlternateMsg = " For a native html [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) use the `html-style` core tag instead.";
function checkStyleInterpolations(tag) {
const { body } = tag.node.body;
let stringQuote = "";
let inComment = false;
let groupDepth = 0;
let urlDepth = 0;
let blockDepth = 0;
let valueColon = false;
let runPlaceholder;
let runAfterColon = false;
let runDecl = false;
const endRun = (selector) => {
if (runPlaceholder && (selector || !runAfterColon && runDecl)) throw tag.hub.buildError(runPlaceholder, selector ? styleSelectorMsg : stylePropertyMsg);
valueColon = false;
runPlaceholder = void 0;
};
for (let i = 0; i < body.length; i++) {
const child = body[i];
if (_marko_compiler.types.isMarkoPlaceholder(child)) {
if (stringQuote) throw tag.hub.buildError(child, styleStringMsg);
if (urlDepth) throw tag.hub.buildError(child, styleUrlMsg);
if (!runPlaceholder) {
runPlaceholder = child;
runAfterColon = valueColon;
runDecl = blockDepth > 0;
}
const prev = body[i - 1];
if (_marko_compiler.types.isMarkoText(prev) && cssGluedBefore.test(prev.value)) throw tag.hub.buildError(child, styleGluedBeforeMsg);
const next = body[i + 1];
if (_marko_compiler.types.isMarkoText(next) && cssGluedValue.test(next.value)) throw tag.hub.buildError(child, styleGluedMsg);
continue;
}
const text = child.value;
for (let j = 0; j < text.length; j++) {
const c = text[j];
if (inComment) {
if (c === "*" && text[j + 1] === "/") {
inComment = false;
j++;
}
} else if (stringQuote) {
if (c === "\\") j++;
else if (c === stringQuote) stringQuote = "";
} else if (c === "\\") j++;
else if (c === "/" && text[j + 1] === "*") {
inComment = true;
j++;
} else if (c === "\"" || c === "'") stringQuote = c;
else if (c === "(" || c === "[") {
groupDepth++;
if (!urlDepth && cssUrlBefore.test(text.slice(0, j + 1)) && !cssQuotedArg.test(text.slice(j + 1))) urlDepth = groupDepth;
} else if (c === ")" || c === "]") {
if (groupDepth) {
if (urlDepth === groupDepth) urlDepth = 0;
groupDepth--;
}
} else if (!groupDepth) switch (c) {
case ":":
if (blockDepth) valueColon = true;
break;
case "{":
endRun(true);
blockDepth++;
break;
case ";":
endRun(!blockDepth);
break;
case "}":
endRun(false);
if (blockDepth) blockDepth--;
}
}
}
endRun(!blockDepth);
}
const styleInterpolationMsg = "A `${...}` interpolation in a [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) is substituted as a `var(--…)` custom property reference, which";
const styleSelectorMsg = `${styleInterpolationMsg} only resolves in a declaration value, not in a selector or at-rule prelude. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
const stylePropertyMsg = `${styleInterpolationMsg} cannot be used as a property name. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
const styleStringMsg = `${styleInterpolationMsg} is not substituted inside a quoted CSS string — the literal text \`var(--…)\` would be rendered instead of the value. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
const styleUrlMsg = `${styleInterpolationMsg} is not substituted inside an unquoted \`url()\` — the raw url token consumes the \`var(--…)\` text literally, invalidating the declaration. Move the whole \`url(...)\` into the interpolated value. For a native html [\`<style>\` tag](https://markojs.com/docs/reference/core-tag#style) use the \`html-style\` core tag instead.`;
const styleGluedMsg = `${styleInterpolationMsg} CSS does not re-tokenize, so a unit written directly after it (eg \`\${x}px\`) becomes the invalid \`var(--…)px\`. Move the unit into the interpolated value (so it resolves to eg \`"10px"\`) or use \`calc(var(--…) * 1px)\`.`;
const styleGluedBeforeMsg = `${styleInterpolationMsg} CSS does not re-tokenize, so text written directly before it (eg \`10\${x}\`) merges with the \`var(--…)\` into a single invalid token. Add whitespace before the interpolation or move the text into the interpolated value.`;
const cssGluedValue = /^(?:[%.\d]|(?:p[xtc]|in|[cm]m|q|r?em|ex|ch|r?lh|v[whib]|vmin|vmax|fr|deg|g?rad|turn|m?s|k?hz|dp(?:i|cm|px)|cq[whib]|cqmin|cqmax)(?![\w-]))/i;
const cssGluedBefore = /[\w%]$/;
const cssUrlBefore = /(?:^|[^\w-])url\($/i;
const cssQuotedArg = /^\s*["']/;
//#endregion
//#region src/translator/core/style.ts
const kStyleImportPath = Symbol("style import path");
const kCustomPropertyNames = Symbol("custom property names");
const STYLE_EXT_REG = /^style((?:\.[a-zA-Z0-9$_-]+)+)?/;
const [getStyleCounts] = createProgramState(() => ({}));
const [getCustomPropertyCount, setCustomPropertyCount] = createProgramState(() => 0);
var style_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
const { node: node$3 } = tag;
assertNoStyleAttributes(tag);
const names = createCustomPropertyNames(tag);
if (names) {
checkStyleInterpolations(tag);
checkDynamicStylePlacement(tag);
}
const importPath = createStyleDependency((0, _marko_compiler_babel_utils.getFile)(), node$3, names);
(node$3.extra ??= {})[kStyleImportPath] = importPath;
if (importPath) addAssetImport(importPath);
if (names) {
analyzeDynamicStyle(tag, names);
addSetupWork(ensureSection(tag));
node(tag, tag.node.extra.nodeBinding);
enterShallow(tag);
writeTo(tag)`<style></style>`;
}
},
translate: translateByTarget({
html: { exit: translateHTML$1 },
dom: { exit: translateDOM$1 }
}),
parseOptions: {
html: false,
text: true,
rawOpenTag: true,
preserveWhitespace: true
},
attributes: {}
};
function analyzeDynamicStyle(tag, names) {
const { node } = tag;
const section = ensureSection(tag);
const binding = node.extra.nodeBinding = createBinding("#style", 0, section);
node.extra[kCustomPropertyNames] = names;
let exprExtras = mergeReferences(section, node, []);
for (const value of dynamicStyleValues(node)) exprExtras = push(exprExtras, value.extra ??= {});
addReasonExprs(ensureSlot(binding), exprExtras);
}
function createCustomPropertyNames(tag) {
let names;
for (const child of tag.node.body.body) if (_marko_compiler.types.isMarkoPlaceholder(child)) {
const index = getCustomPropertyCount();
setCustomPropertyCount(index + 1);
(names ??= []).push(customPropertyName(index));
} else if (!_marko_compiler.types.isMarkoText(child)) throw tag.hub.buildError(child, "The [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) only supports text and `${...}` interpolations." + htmlStyleTagAlternateMsg);
return names;
}
const styleNameUnsafeReg = /[^a-zA-Z0-9_]/g;
const encodeStyleNameChar = (c) => "-" + c.charCodeAt(0).toString(36);
function customPropertyName(index) {
const file = (0, _marko_compiler_babel_utils.getFile)();
const id = (0, _marko_compiler_babel_utils.getTemplateId)(file.markoOpts, file.opts.filename, index.toString(36));
return "--" + ((file.markoOpts.runtimeId || "M_") + id).replace(styleNameUnsafeReg, encodeStyleNameChar);
}
function checkDynamicStylePlacement(tag) {
for (const sibling of tag.getAllPrevSiblings()) {
if (isCoreTagName(sibling, "style")) continue;
if (sibling.isMarkoText() ? /\S/.test(sibling.node.value) : getNodeContentType(sibling, "startType") !== null) {
(0, _marko_compiler_babel_utils.diagnosticWarn)(tag, { label: "The `${...}` values of a [`<style>` tag](https://markojs.com/docs/reference/core-tag#style) only apply to the subsequent siblings of the `<style>` tag and their descendants, so the content before this tag will not receive them. Move the `<style>` tag above the content it styles." });
return;
}
}
}
function assertNoStyleAttributes(tag) {
const { node } = tag;
const extClass = (STYLE_EXT_REG.exec(node.rawValue || "")?.[1]?.slice(1))?.replace(/\./g, " ");
for (const attr of node.attributes) {
if (attr.start == null && attr.type === "MarkoAttribute" && attr.name === "class" && attr.value.type === "StringLiteral" && attr.value.value === extClass) continue;
throw tag.hub.buildError(attr.value, "The `style` does not support html attributes." + htmlStyleTagAlternateMsg);
}
}
function translateHTML$1(tag) {
const { node } = tag;
const binding = node.extra?.nodeBinding;
if (binding) {
writeTo$1(tag)`${callRuntime("_style_html", buildStyleDecls(node))}`;
markNode(tag, binding, getWriteReason(binding));
}
emitStyleImport(tag);
tag.remove();
}
function translateDOM$1(tag) {
const { node } = tag;
const binding = node.extra?.nodeBinding;
if (binding) {
const names = node.extra[kCustomPropertyNames];
const section = getSection(tag);
const readEl = () => createScopeReadExpression(binding);
addStatement("render", section, void 0, callRuntime("_style_shell", scopeIdentifier, getScopeAccessorLiteral(binding)), true);
dynamicStyleValues(node).forEach((value, i) => {
const valueRef = getReferencedBindings(value.extra);
addStatement("render", section, valueRef, callRuntime("_style_rule_item", readEl(), _marko_compiler.types.stringLiteral(names[i]), value), !valueRef);
});
}
emitStyleImport(tag);
tag.remove();
}
function dynamicStyleValues(node) {
const values = [];
for (const child of node.body.body) if (_marko_compiler.types.isMarkoPlaceholder(child)) values.push(child.value);
return values;
}
function emitStyleImport(tag) {
const { node } = tag;
const importPath = node.extra?.[kStyleImportPath];
if (!importPath) return;
if (!node.var) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(importPath)));
else if (_marko_compiler.types.isIdentifier(node.var)) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.importDeclaration([_marko_compiler.types.importNamespaceSpecifier(node.var)], _marko_compiler.types.stringLiteral(importPath)));
else {
const varDecl = _marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(node.var, (0, _marko_compiler_babel_utils.importStar)((0, _marko_compiler_babel_utils.getFile)(), importPath, "style"))]);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(isOutputDOM() ? varDecl : _marko_compiler.types.markoScriptlet([varDecl], true));
}
}
function buildStyleDecls(node) {
const names = node.extra[kCustomPropertyNames];
const parts = [];
dynamicStyleValues(node).forEach((value, i) => {
parts.push(`${names[i]}:`);
parts.push(callRuntime("_escape_style_value", value));
parts.push(";");
});
return buildStringExpression(parts);
}
/**
* Hands a `<style>` block's css to the configured `resolveVirtualDependency`
* hook as a new virtual dependency, returning its client-side import path.
*/
function createStyleDependency(file, node, names) {
const { resolveVirtualDependency, sourceMaps } = file.markoOpts;
if (!resolveVirtualDependency) return;
const { filename } = file.opts;
let ext = STYLE_EXT_REG.exec(node.rawValue || "")?.[1] || ".css";
if (node.var && !/\.module\./.test(ext)) ext = ".module" + ext;
const counts = getStyleCounts();
const index = counts[ext] || 0;
counts[ext] = index + 1;
const magicString = sourceMaps ? new magic_string.default(file.code, { filename }) : void 0;
let code = "";
let last = 0;
let map;
let nameIndex = 0;
for (const child of node.body.body) {
const placeholder = _marko_compiler.types.isMarkoPlaceholder(child);
const text = placeholder ? `var(${names[nameIndex++]})` : child.value;
if (magicString) {
const start = (0, _marko_compiler_babel_utils.getStart)(file, child);
if (start === null) magicString.appendLeft(last, text);
else {
const end = (0, _marko_compiler_babel_utils.getEnd)(file, child);
if (start > last) magicString.remove(last, start);
if (placeholder) magicString.update(start, end, text);
last = end;
}
} else code += text;
}
if (magicString) {
if (file.code.length > last) magicString.remove(last, file.code.length);
code = magicString.toString();
map = magicString.generateMap({
source: filename,
includeContent: true
});
if (sourceMaps === "inline" || sourceMaps === "both") {
code += `\n/*# sourceMappingURL=${map.toUrl()}*/`;
if (sourceMaps === "inline") map = void 0;
}
}
return resolveVirtualDependency(filename, {
virtualPath: `./${path.default.basename(filename)}${index ? `.${index}` : ""}${ext}`,
code,
map
});
}
//#endregion
//#region src/translator/core/try.ts
var try_default = {
analyze(tag) {
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributes)(tag);
const attrTags = analyzeAttributeTags(tag);
if (attrTags) {
for (const name in attrTags) {
if (name !== "@placeholder" && name !== "@catch") {
const suggestion = name[1] === "p" ? "`<@placeholder>`" : "`<@catch>`";
throw tag.buildCodeFrameError(`The [\`<try>\` tag](https://markojs.com/docs/reference/core-tag#try) only supports the \`<@placeholder>\` and \`<@catch>\` attribute tags, but received \`<${name}>\`. Did you mean ${suggestion}?`);
}
const { dynamic, repeated } = attrTags[name];
if (dynamic || repeated) throw tag.get("name").buildCodeFrameError(dynamic ? `The [\`<try>\` tag](https://markojs.com/docs/reference/core-tag#try) needs its \`<${name}>\` written directly inside it, not within control flow such as \`<if>\` or \`<for>\`.` : `The [\`<try>\` tag](https://markojs.com/docs/reference/core-tag#try) takes a single \`<${name}>\`.`);
}
for (const child of tag.get("attributeTags")) if (child.isMarkoTag() && (child.node.attributes.length || child.node.arguments)) throw child.get("name").buildCodeFrameError(`The [\`<try>\` tag](https://markojs.com/docs/reference/core-tag#try)'s \`<${getTagName(child)}>\` takes no attributes, only content.`);
}
const section = ensureSection(tag);
const tagExtra = mergeTagReferences(section, tag.node);
const nodeBinding = tagExtra.nodeBinding = createBinding("#text", 0, section);
assertHasBody(tag);
if (!attrTags) throw tag.get("name").buildCodeFrameError("The [`<try>` tag](https://markojs.com/docs/reference/core-tag#try) needs a `<@catch>` to handle errors or a `<@placeholder>` to show while its content is pending. Without either it has no effect, so render its content directly.");
initBranchSection(ensureBodySection(tag.get("body")), tagExtra, {
nodeBinding,
optional: false
});
marker(tag, nodeBinding);
enterShallow(tag);
},
translate: translateByTarget({
html: {
enter(tag) {
flushBefore(tag);
},
exit(tag) {
const section = getSection(tag);
const tagBody = tag.get("body");
const nodeBinding = tag.node.extra.nodeBinding;
const { catchTag, catchSection, placeholderTag, placeholderSection } = getTryParts(tag);
writeHTMLResumeStatements(tag);
const tryArgs = [
getScopeIdIdentifier(section),
getScopeAccessorLiteral(nodeBinding),
buildContent(tagBody),
placeholderSection && buildContent(placeholderTag.get("body")),
catchTag && (catchSection ? buildContent(catchTag.get("body")) : _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([]))),
placeholderSection && _marko_compiler.types.stringLiteral(getResumeRegisterId(placeholderSection, "content")),
catchTag && _marko_compiler.types.stringLiteral(catchSection ? getResumeRegisterId(catchSection, "content") : getResumeRegisterId(section, nodeBinding, "catch"))
];
tag.replaceWith(_marko_compiler.types.expressionStatement(callRuntime("_try", ...tryArgs)))[0].skip();
}
},
dom: { exit(tag) {
const nodeBinding = tag.node.extra.nodeBinding;
const section = getSection(tag);
const bodySection = getSectionForBody(tag.get("body"));
const { catchTag, catchSection, placeholderSection } = getTryParts(tag);
const emptyCatchId = catchTag && !catchSection && getResumeRegisterId(section, nodeBinding, "catch");
const signal = getSignal(section, nodeBinding, "try");
signal.build = () => {
importRuntimeFeature("catch");
if (placeholderSection) importRuntimeFeature("placeholder");
let catchContent = catchSection && _marko_compiler.types.identifier(catchSection.name);
if (emptyCatchId) {
catchContent = _marko_compiler.types.identifier(`${signal.identifier.name}__catch`);
(signal.prependStatements ||= []).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(catchContent, callRuntime("_content", _marko_compiler.types.stringLiteral(emptyCatchId)))]));
}
const [template, walks, setup] = getBranchRendererArgs(bodySection);
return callRuntime("_try", getScopeAccessorLiteral(nodeBinding, true), ...trimEmptyArgs([
template,
walks,
setup,
placeholderSection && _marko_compiler.types.identifier(placeholderSection.name),
catchContent
]));
};
addValue(section, void 0, signal);
tag.remove();
} }
}),
attributes: {},
autocomplete: [{
description: "Used to capture errors and display placeholders for nested content.",
descriptionMoreURL: "https://markojs.com/docs/reference/core-tag#try"
}],
types: runtime_info_default.name + "/tags/try.d.marko"
};
function getTryParts(tag) {
const catchTag = getAttrTag(tag, "@catch");
const placeholderTag = getAttrTag(tag, "@placeholder");
return {
catchTag,
catchSection: catchTag && getSectionForBody(catchTag.get("body")),
placeholderTag,
placeholderSection: placeholderTag && getSectionForBody(placeholderTag.get("body"))
};
}
function getAttrTag(tag, name) {
for (const child of tag.get("attributeTags")) if (child.isMarkoTag() && getTagName(child) === name) return child;
}
function buildContent(body) {
return _marko_compiler.types.arrowFunctionExpression(body.node.params, _marko_compiler.types.blockStatement([getScopeReasonStatement(getSectionForBody(body)), ...body.node.body]));
}
//#endregion
//#region src/translator/core/index.ts
var core_default = {
taglibId: runtime_info_default.taglibId,
"<attrs>": attrs_default,
"<await>": await_default,
"<class>": class_default,
"<client>": client_default,
"<const>": const_default,
"<debug>": debug_default,
"<define>": define_default,
"<effect>": effect_default,
"<else-if>": ElseIfTag,
"<else>": ElseTag,
"<export>": export_default,
"<for>": for_default,
"<html-comment>": html_comment_default,
"<html-script>": html_script_default,
"<html-style>": html_style_default,
"<id>": id_default,
"<if>": IfTag,
"<import>": import_default,
"<let>": let_default,
"<lifecycle>": lifecycle_default,
"<log>": log_default,
"<return>": return_default,
"<script>": script_default,
"<server>": server_default,
"<show>": show_default,
"<static>": static_default,
"<style>": style_default,
"<try>": try_default
};
//#endregion
//#region src/translator/visitors/cdata.ts
var cdata_default = { translate: { enter(cdata) {
throw cdata.buildCodeFrameError("CDATA sections are not supported in Marko.");
} } };
//#endregion
//#region src/translator/visitors/comment.ts
var comment_default = { translate: { exit(comment) {
comment.remove();
} } };
//#endregion
//#region src/translator/visitors/declaration.ts
var declaration_default = { translate: { enter(decl) {
throw decl.buildCodeFrameError("XML declarations sections are not supported in Marko.");
} } };
//#endregion
//#region src/translator/visitors/document-type.ts
var document_type_default = { translate: { exit(documentType) {
if (isOutputHTML()) {
writeTo$1(documentType)`<!${documentType.node.value}>`;
if (getMarkoOpts().linkAssets && !isBeforeHtmlOrHead(documentType)) writeTo$1(documentType)`${callRuntime("_flush_head")}`;
}
documentType.remove();
} } };
function isBeforeHtmlOrHead(documentType) {
let next = documentType.getNextSibling();
while (next.node) {
if (next.isMarkoTag()) {
const { name } = next.node;
return name.type === "StringLiteral" && (name.value === "html" || name.value === "head");
}
next = next.getNextSibling();
}
return false;
}
//#endregion
//#region src/translator/visitors/export-declaration.ts
var export_declaration_default = {
analyze(exportDecl) {
const { node } = exportDecl;
const { source } = node;
if (source) {
const tagImport = (0, _marko_compiler_babel_utils.resolveTagImport)(exportDecl, source.value);
if (tagImport) {
(node.extra ??= {}).tagImport = tagImport;
trackTagImport(tagImport);
}
}
},
translate: { exit(exportDecl) {
const { node } = exportDecl;
const tagImport = node.extra?.tagImport;
if (tagImport) node.source.value = tagImport;
} }
};
//#endregion
//#region src/translator/visitors/function.ts
var function_default = { analyze(fn) {
const awaitNode = isMarkoAttribute(fn.parentPath) && _marko_compiler.types.isFunctionExpression(fn.node) && !fn.node.async && traverseFindAwait(fn.node.body);
if (awaitNode) {
const file = (0, _marko_compiler_babel_utils.getFile)();
const start = file.code.indexOf("await", awaitNode.start ?? 0);
const highlight = start >= 0 && (awaitNode.end == null || start < awaitNode.end) ? (0, _marko_compiler_babel_utils.withLoc)(file, _marko_compiler.types.cloneNode(awaitNode), start, start + 5) : awaitNode;
throw fn.hub.buildError(highlight, "Attribute methods containing `await` must be `async`. Add `async` before the method name.");
}
if (fn !== getFnRoot(fn)) return;
const { node } = fn;
if ((_marko_compiler.types.isObjectMethod(node) || _marko_compiler.types.isClassMethod(node)) && (node.kind === "get" || node.kind === "set")) return;
const exprRoot = getExprRoot(fn);
const markoRoot = getMarkoRoot(exprRoot);
if (!markoRoot || canIgnoreRegister(markoRoot, exprRoot)) return;
const section = getSection(fn);
const fnExtra = node.extra ??= {};
fnExtra.section = section;
fnExtra.exprRoot = exprRoot.node.extra ??= {};
fnExtra.name = node.id?.name || (isMarkoAttribute(markoRoot) ? markoRoot.node.default ? _marko_compiler.types.toIdentifier((markoRoot.parentPath.has("var") ? markoRoot.parentPath.get("var") : markoRoot.parentPath.get("name")).toString()) : markoRoot.node.name : _marko_compiler.types.isVariableDeclarator(fn.parent) && _marko_compiler.types.isIdentifier(fn.parent.id) ? fn.parent.id.name : _marko_compiler.types.isObjectMethod(node) && _marko_compiler.types.isIdentifier(node.key) ? node.key.name : "anonymous");
trackFunction(fn, fnExtra, markoRoot);
} };
function isMarkoAttribute(path) {
return path ? path.isMarkoAttribute() : false;
}
//#endregion
//#region src/translator/visitors/import-declaration.ts
const [getHtmlLoadWrapped] = createProgramState(() => /* @__PURE__ */ new Map());
var import_declaration_default = {
analyze(importDecl) {
const { node } = importDecl;
const { source } = node;
const { value } = source;
if (_marko_compiler.types.isProgram(importDecl.parent) && isClientAssetImport((0, _marko_compiler_babel_utils.getFile)(), value)) addAssetImport(value);
const { tagImport } = getImportFacts(importDecl);
if (tagImport) {
trackTagImport(tagImport);
trackRegisteredImports(importDecl);
}
const loadAttrPath = getLoadAttr(importDecl);
if (loadAttrPath) {
if ((node.importKind || "value") !== "value") throw importDecl.buildCodeFrameError("Invalid load import.");
for (const specifier of importDecl.get("specifiers")) if (!_marko_compiler.types.isImportDefaultSpecifier(specifier.node)) throw specifier.buildCodeFrameError("Invalid load import, only a default specifier is allowed.");
if (!node.specifiers.some(_marko_compiler.types.isImportDefaultSpecifier)) throw importDecl.buildCodeFrameError("Invalid load import, a default specifier is required.");
if (!getMarkoOpts().linkAssets) {
loadAttrPath.remove();
return;
}
const { local } = node.specifiers.find(_marko_compiler.types.isImportDefaultSpecifier);
const useAbove = importDecl.scope.getBinding(local.name).referencePaths.find((ref) => ref.find((p) => !!p.parentPath?.isProgram()).key < importDecl.key);
if (useAbove) throw useAbove.buildCodeFrameError(`\`${local.name}\` is used above its \`load\` import. Move the import above its first use.`);
const file = (0, _marko_compiler_babel_utils.getFile)();
const loadFile = tagImport && (0, _marko_compiler_babel_utils.loadFileForImport)(file, value);
if (!loadFile) throw importDecl.buildCodeFrameError("Unable to resolve marko file for load import.");
(file.path.node.extra.loadImports ??= /* @__PURE__ */ new Set()).add(loadFile.opts.filename);
if (loadFile.ast.program.extra?.featureType === "class") throw importDecl.buildCodeFrameError(`The [\`load\` import attribute](https://markojs.com/docs/reference/lazy-loading) is not supported for the Marko 5 (class API) tag \`${value}\`. Import it without \`load\`, or migrate the tag to the tags API.`);
}
},
translate: { exit(importDecl) {
const { node } = importDecl;
const { extra } = node;
const tagImport = extra?.tagImport;
const loadImport = extra?.loadImport;
if (tagImport) {
if (loadImport) {
const { local } = node.specifiers.find(_marko_compiler.types.isImportDefaultSpecifier);
const binding = importDecl.scope.getBinding(local.name);
const file = (0, _marko_compiler_babel_utils.getFile)();
const loadFile = (0, _marko_compiler_babel_utils.loadFileForImport)(file, node.source.value);
if (isOutputHTML()) {
const wrappedName = ensureHtmlLoadWrapped(getReadyId(loadFile), _marko_compiler.types.identifier(local.name), loadFile.opts.filename, loadImport.render ? void 0 : loadImport.triggers);
for (const ref of binding.referencePaths) ref.replaceWith(_marko_compiler.types.identifier(wrappedName));
node.source.value = tagImport;
node.attributes = void 0;
return;
} else if (binding.referencePaths.every((ref) => _marko_compiler.types.isMarkoTag(ref.parent) && ref.parent.extra?.tagNameLoad)) importDecl.remove();
else {
importRuntimeFeature("catch");
const load = _marko_compiler.types.arrowFunctionExpression([], dynamicImport((0, _marko_compiler_babel_utils.resolveRelativePath)(file, loadFile.opts.filename), _marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.identifier("mod")], toMemberExpression(_marko_compiler.types.identifier("mod"), "default"))));
const args = [_marko_compiler.types.stringLiteral(loadFile.metadata.marko.id), load];
importDecl.replaceWith(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(local, extra.registeredImports?.has(local.name) ? _marko_compiler.types.callExpression(importRuntime("_load_template"), args) : callRuntime("_load_template", ...args))]));
}
return;
}
node.source.value = tagImport;
}
} }
};
function ensureHtmlLoadWrapped(readyId, originalIdentifier, filename, triggers) {
const markoOpts = getMarkoOpts();
const loadWrapped = getHtmlLoadWrapped();
const existing = loadWrapped.get(readyId);
if (existing) return existing;
markoOpts.linkAssets?.onAsset("load", filename, readyId);
const wrappedName = generateUid(`${originalIdentifier.name ?? "tag"}_withLoadAssets`);
loadWrapped.set(readyId, wrappedName);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.markoScriptlet([_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(wrappedName), callRuntime("withLoadAssets", originalIdentifier, (0, _marko_compiler_babel_utils.importNamed)((0, _marko_compiler_babel_utils.getFile)(), markoOpts.linkAssets.runtime, "flush"), _marko_compiler.types.stringLiteral(readyId), triggers ? _marko_compiler.types.valueToNode(triggers) : void 0))])], true));
return wrappedName;
}
function trackRegisteredImports(importDecl) {
const { node } = importDecl;
const childFile = (0, _marko_compiler_babel_utils.loadFileForImport)((0, _marko_compiler_babel_utils.getFile)(), node.source.value);
if (!childFile) return;
for (const specifier of importDecl.get("specifiers")) {
let importedName = "default";
if (specifier.isImportSpecifier()) importedName = getLiteralName(specifier.node.imported);
else if (!specifier.isImportDefaultSpecifier()) continue;
const local = specifier.node.local.name;
if (importedName === "default") trackImportedTemplate(importDecl, local, childFile);
else trackImport(importDecl, local, resolveRegisteredExport(childFile, importedName));
}
}
//#endregion
//#region src/translator/util/static-text.ts
function isStaticText(node) {
switch (node?.type) {
case "MarkoText": return true;
case "MarkoPlaceholder": return node.escape && !!getStaticPlaceholderText(node);
}
}
function followsStaticText(path) {
let prev = path.getPrevSibling();
while (prev.node && (getNodeContentType(prev, "endType") === null || prev.isMarkoPlaceholder() && getStaticPlaceholderText(prev.node) === "")) prev = prev.getPrevSibling();
return isStaticText(prev.node);
}
function getStaticPlaceholderText(placeholder) {
const { confident, computed } = evaluate(placeholder.value);
if (confident) return placeholder.escape ? _escape(computed) : _unescaped(computed);
}
//#endregion
//#region src/translator/visitors/placeholder.ts
const kSiblingText = Symbol("placeholder has sibling text");
var placeholder_default = {
analyze: {
enter(placeholder) {
if (isInTextBody(placeholder)) return;
const { node } = placeholder;
const valueExtra = node.value.extra ??= {};
if (getStaticPlaceholderText(node) === "") return;
if (!isStaticText(node)) {
const section = ensureSection(placeholder);
const nodeBinding = (node.extra ??= {}).nodeBinding = createBinding("#text", 0, section);
analyzeSiblingText(placeholder);
addSetupExpr(section, node.value);
addReasonExprs(ensureSlot(nodeBinding), valueExtra);
}
},
exit(placeholder) {
if (isInTextBody(placeholder)) return;
const { node: node$2 } = placeholder;
const staticText = getStaticPlaceholderText(node$2);
if (staticText === "") return;
const extra = node$2.extra || {};
if (staticText !== void 0 && node$2.escape) writeTextTo(placeholder, staticText);
else {
const siblingText = extra[kSiblingText];
const nodeBinding = extra.nodeBinding;
const { content } = getSection(placeholder);
if (siblingText === 1 || siblingText === 2 || !node$2.escape && content.singleChild && content.startType === 2) marker(placeholder, nodeBinding);
else {
writeTextTo(placeholder, " ");
node(placeholder, nodeBinding);
}
}
if (!isStaticText(node$2) || !followsStaticText(placeholder)) enterShallow(placeholder);
}
},
translate: { exit: translateExit }
};
function translateExit(placeholder) {
if (isInTextBody(placeholder)) return;
const { node } = placeholder;
const { value } = node;
if (node.extra?.needsTextCoercion) injectTextCoercion(value);
if (getStaticPlaceholderText(node) === "") {
placeholder.remove();
return;
}
const { confident, computed } = evaluate(value);
const isHTML = isOutputHTML();
const write = writeTo$1(placeholder);
const extra = node.extra || {};
const nodeBinding = extra.nodeBinding;
const canWriteHTML = isHTML || confident && node.escape;
const method = canWriteHTML ? node.escape ? "_escape" : "_unescaped" : node.escape ? "_text" : "_html";
if (confident && canWriteHTML) {
if (isHTML) write`${node.escape ? _escape(computed) : _unescaped(computed)}`;
} else {
const section = getSection(placeholder);
const siblingText = extra[kSiblingText];
const markerReason = nodeBinding && getWriteReason(nodeBinding);
if (isHTML) {
if (markerReason) {
const guard = getWriteGuard(section, markerReason, true);
write`${callRuntime(node.escape ? "_text_resume" : "_html_resume", getScopeIdIdentifier(section), getScopeAccessorLiteral(nodeBinding), value, siblingText === 1 ? guard ? _marko_compiler.types.binaryExpression("*", guard, _marko_compiler.types.numericLiteral(2)) : _marko_compiler.types.numericLiteral(2) : guard)}`;
} else write`${method === "_escape" ? buildEscapedTextExpression(value) : callRuntime(method, value)}`;
} else addStatement("render", section, getReferencedBindings(value.extra), method === "_text" ? callRuntime("_text", createScopeReadExpression(nodeBinding), value) : callRuntime("_html", scopeIdentifier, value, getScopeAccessorLiteral(nodeBinding)), true);
}
placeholder.remove();
}
function buildEscapedTextExpression(value) {
switch (value.type) {
case "StringLiteral":
case "NumericLiteral":
case "BooleanLiteral": return _marko_compiler.types.stringLiteral(_escape(value.value));
case "NullLiteral": return _marko_compiler.types.stringLiteral("");
case "ConditionalExpression": return _marko_compiler.types.conditionalExpression(value.test, buildEscapedTextExpression(value.consequent), buildEscapedTextExpression(value.alternate));
case "TemplateLiteral": {
const parts = [];
value.quasis.forEach((quasi, i) => {
parts.push(_escape(quasi.value.cooked ?? ""));
const expression = value.expressions[i];
if (expression) parts.push(callRuntime("_escape", _marko_compiler.types.templateLiteral([_marko_compiler.types.templateElement({ raw: "" }), _marko_compiler.types.templateElement({ raw: "" }, true)], [expression])));
});
return buildStringExpression(parts) ?? _marko_compiler.types.stringLiteral("");
}
default: return callRuntime("_escape", value);
}
}
function analyzeSiblingText(placeholder) {
placeholder.node.extra[kSiblingText] = mayMergeWithText(placeholder, true) ? 1 : mayMergeWithText(placeholder, false) ? 2 : 0;
}
function mayMergeWithText(placeholder, before) {
let sibling = getSibling(placeholder, before);
let parent = placeholder.parentPath;
for (;;) if (!sibling.node) {
const inlinedTag = getInlinedBodyTag(parent);
if (!inlinedTag) return parent.isProgram();
sibling = getSibling(inlinedTag, before);
parent = inlinedTag.parentPath;
} else {
const contentType = getNodeContentType(sibling, before ? "endType" : "startType");
if (contentType !== null) return contentType === 4 || contentType === 1 || contentType === 2;
sibling = getSibling(sibling, before);
}
}
function getSibling(path, before) {
return before ? path.getPrevSibling() : path.getNextSibling();
}
function getInlinedBodyTag(parent) {
if (parent.isMarkoTagBody()) {
const tag = parent.parentPath;
const facts = getTagFacts(tag);
if (facts.controlFlow && facts.inlineBody) return tag;
}
}
//#endregion
//#region src/translator/util/analyze-errors.ts
const [hasAnalyzeErrors, setHasAnalyzeErrors] = createProgramState(() => false);
function reportAnalyzeError(path, error) {
const { filename } = error;
if (!(error instanceof Error) || filename !== void 0 && filename !== (0, _marko_compiler_babel_utils.getFile)().opts.filename) throw error;
const { label = error.message, loc } = error;
setHasAnalyzeErrors(true);
(0, _marko_compiler_babel_utils.diagnosticError)(path, {
label,
loc: loc ?? path.node.loc ?? void 0
});
}
//#endregion
//#region src/translator/util/entry-builder.ts
const kState = Symbol();
const builder = {
build(entryFile, exportInit) {
const state = entryFile[kState];
assertVisited(entryFile, state);
const body = [];
const isPage = entryFile.path.node.extra.page;
const initHelper = isPage ? "init" : "initEmbedded";
for (const asset of state.assets) body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(asset)));
if (state.init || state.hasClientStatement) {
if (state.init) {
body.push(_marko_compiler.types.importDeclaration([_marko_compiler.types.importSpecifier(_marko_compiler.types.identifier(initHelper), _marko_compiler.types.identifier(initHelper))], _marko_compiler.types.stringLiteral(getRuntimePath("dom"))));
if (state.lazy) body.push(getRuntimeFeatureImport("lazy"));
}
for (const root of state.roots) body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(root)));
} else for (const asset of state.bundledAssets) body.push(_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(asset)));
if (!state.init) {
if (exportInit) body.push(_marko_compiler.types.exportDefaultDeclaration(_marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([]))));
return body;
}
const { runtimeId } = entryFile.markoOpts;
const readyId = !isPage && (0, _marko_compiler_babel_utils.getTemplateId)(entryFile.markoOpts, entryFile.opts.filename);
const initExpression = _marko_compiler.types.callExpression(_marko_compiler.types.identifier(initHelper), readyId ? runtimeId ? [_marko_compiler.types.stringLiteral(readyId), _marko_compiler.types.stringLiteral(runtimeId)] : [_marko_compiler.types.stringLiteral(readyId)] : runtimeId ? [_marko_compiler.types.stringLiteral(runtimeId)] : []);
body.push(exportInit ? _marko_compiler.types.exportDefaultDeclaration(_marko_compiler.types.arrowFunctionExpression([], initExpression)) : _marko_compiler.types.expressionStatement(initExpression));
return body;
},
visit(file, entryFile, visitChild = (id, reach = 0) => {
const resolved = resolveRelativeToEntry(entryFile, file, id);
if (markReached(entryFile[kState].visited, resolved, reach)) {
const childFile = (0, _marko_compiler_babel_utils.loadFileForImport)(entryFile, resolved);
if (childFile) builder.visit(childFile, entryFile);
}
}) {
const state = entryFile[kState] ||= {
init: false,
hasClientStatement: false,
lazy: false,
bundledDepth: 0,
lazyDepth: 0,
roots: [],
assets: /* @__PURE__ */ new Set(),
bundledAssets: /* @__PURE__ */ new Set(),
visited: createVisited(entryFile)
};
const programExtra = file.path.node.extra;
const { analyzedTags, assetImports } = file.metadata.marko;
const { loadImports } = programExtra;
const init = !!(programExtra.isInteractive || programExtra.needsCompat);
const hasClientStatement = !!programExtra.hasClientStatement;
const isRoot = !state.bundledDepth && (init || hasClientStatement || !!programExtra.hasResumes);
if (init) state.init = true;
if (hasClientStatement) state.hasClientStatement = true;
if (loadImports) state.lazy = true;
if (isRoot) state.roots.push((0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, file.opts.filename));
if (assetImports && !state.lazyDepth) {
const assets = isRoot || state.bundledDepth ? state.bundledAssets : state.assets;
for (const request of assetImports) assets.add(resolveRelativeToEntry(entryFile, file, request));
}
if (isRoot) state.bundledDepth++;
for (const tag of analyzedTags ? [...analyzedTags] : []) {
const lazy = loadImports?.has(tag);
if (lazy) {
state.bundledDepth++;
state.lazyDepth++;
}
visitChild(tag, state.lazyDepth ? 2 : state.bundledDepth ? 1 : 0);
if (lazy) {
state.bundledDepth--;
state.lazyDepth--;
}
}
if (isRoot) state.bundledDepth--;
}
};
function assertVisited(entryFile, state) {
if (!state) throw entryFile.path.buildCodeFrameError("Unable to build hydrate code, no files were visited before finalizing the build");
}
function createVisited(entryFile) {
return /* @__PURE__ */ new Map([[(0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, entryFile.opts.filename), 0]]);
}
function resolveRelativeToEntry(entryFile, file, req) {
return file === entryFile ? (0, _marko_compiler_babel_utils.resolveRelativePath)(file, req) : (0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, req[0] === "." ? path.default.join(file.opts.filename, "..", req) : req);
}
function markReached(visited, resolved, reach) {
const seen = visited.get(resolved);
if (seen !== void 0 && seen <= reach) return false;
visited.set(resolved, reach);
return true;
}
//#endregion
//#region src/translator/util/get-style-file.ts
function getStyleFile(file) {
const { filename } = file.opts;
const fs = file.markoOpts.fileSystem;
const base = getBase(filename);
const styleMatch = new RegExp(`^(${escapeRegExp(base)}\\.${"index" === base ? "|" : ""})style\\.\\w+$`);
let dirFiles;
try {
dirFiles = fs.readdirSync(path.default.dirname(filename)).sort();
} catch {
return;
}
for (const file of dirFiles) if (styleMatch.test(file)) return `./${file}`;
}
/**
* Given a filename, gets the base name, strips off the file extension
* and removes any arc flags (https://github.com/eBay/arc).
*
* @example
* getBase("/dir/foo.marko") // => "foo"
* getBase("/dir/foo.bar.marko") // => "foo.bar"
* getBase("/dir/foo[bar].marko") // => "foo"
* getBase("/dir/foo[bar].baz.marko") // => "foo.baz"
*/
function getBase(filename) {
const start = filename.lastIndexOf(path.default.sep) + 1;
const leftDot = filename.indexOf(".", start);
if (leftDot === -1) return filename.slice(start);
const rightDot = filename.lastIndexOf(".");
const closeBracket = leftDot - 1;
if (filename[closeBracket] === "]") {
const openBracket = filename.lastIndexOf("[", closeBracket);
if (openBracket > start) return filename.slice(start, openBracket) + filename.slice(leftDot, rightDot);
}
return filename.slice(start, rightDot);
}
const regexpCharsReg = /[\\^$.*+?()[\]{}|]/g;
function escapeRegExp(str) {
return str.replace(regexpCharsReg, "\\$&");
}
//#endregion
//#region src/translator/visitors/program/dom.ts
var dom_default = { translate: {
enter(program) {
const section = getSectionForBody(program);
forEachSectionReverse((childSection) => {
if (childSection !== section) forEach(childSection.referencedClosures, (closure) => {
if (closure.type !== 5) {
const closureSignal = getSignal(childSection, closure);
if (signalHasWork(closureSignal)) addStatement("render", childSection, void 0, _marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(isDynamicClosure(childSection, closure) ? closureSignal.identifier : _marko_compiler.types.memberExpression(closureSignal.identifier, _marko_compiler.types.identifier("_")), [scopeIdentifier])));
}
});
});
},
exit(program) {
forEachSectionReverse(getSectionMeta);
const section = getSectionForBody(program);
const exportNames = program.node.extra.exportNames;
const templateIdentifier = _marko_compiler.types.identifier(exportNames.template);
const walksIdentifier = _marko_compiler.types.identifier(exportNames.walks);
const setupIdentifier = _marko_compiler.types.identifier(exportNames.setup);
const inputBinding = program.node.params[0].extra?.binding;
const programInputSignal = inputBinding && !inputBinding.pruned ? initValue(inputBinding) : void 0;
const styleFile = program.node.extra.styleFile;
if (styleFile) (0, _marko_compiler_babel_utils.importDefault)((0, _marko_compiler_babel_utils.getFile)(), styleFile);
forEachSectionReverse((childSection) => {
if (childSection !== section) {
const tagParamsSignal = childSection.params && initValue(childSection.params);
forEach(childSection.localClosures, (closure) => {
initValue(closure).build = void 0;
});
const tagParamsIdentifier = tagParamsSignal && signalHasWork(tagParamsSignal) ? tagParamsSignal.identifier : void 0;
const { writes } = getSectionMeta(childSection);
const walks = trimTrailingExits(getSectionMeta(childSection).walks);
const written = writeSignals(childSection);
const setup = getSetup(childSection);
const setupIdentifier = setup && written.has(setup) ? setup.identifier : void 0;
if (!isSectionRendererElided(childSection)) {
if (childSection.branch) setBranchRendererArgs(childSection, [
writes,
walks,
setupIdentifier,
tagParamsIdentifier
]);
else {
const registerReason = getRendererReason(childSection);
const registerId = getResumeRegisterId(childSection, "content");
const objProps = [];
forEach(childSection.localClosures, (closure) => {
const closureSignal = getSignal(childSection, closure);
const key = toPropertyName(getScopeAccessor(closure, true));
if (signalHasWork(closureSignal)) {
const expr = buildSignalFn(closureSignal);
if (closureSignal.prependStatements) program.node.body.push(...closureSignal.prependStatements);
if (_marko_compiler.types.isFunction(expr) && _marko_compiler.types.isBlockStatement(expr.body)) objProps.push(_marko_compiler.types.objectMethod("method", key, expr.params, expr.body));
else objProps.push(_marko_compiler.types.objectProperty(key, expr));
}
});
const registerWrapper = !!(registerReason && objProps.length);
let renderer = callRuntime("_content", _marko_compiler.types.stringLiteral(registerId), ...trimEmptyArgs([
writes,
walks,
...markReturn(childSection, setupIdentifier, tagParamsIdentifier),
childSection.hoisted || childSection.isHoistThrough ? getSectionInstancesAccessorLiteral(childSection) : void 0
]));
if (!registerReason || registerWrapper) renderer = _marko_compiler.types.addComment(renderer, "leading", "@__PURE__");
if (objProps.length) renderer = callRuntime("_content_closures", renderer, _marko_compiler.types.objectExpression(objProps));
program.node.body.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(childSection.name), renderer)]));
if (registerReason && getDynamicTagContentClosures(childSection)) program.node.body.push(_marko_compiler.types.expressionStatement(callRuntime("_content_resume", _marko_compiler.types.identifier(childSection.name), registerWrapper && _marko_compiler.types.numericLiteral(1))));
else if (registerWrapper) program.node.body.push(_marko_compiler.types.expressionStatement(registerRuntimeValue(registerId, _marko_compiler.types.identifier(childSection.name))));
}
}
}
});
const written = writeSignals(section);
writeRegisteredFns();
const setup = getSetup(section);
const setupWritten = !!setup && written.has(setup);
assertSetupWorkFound(program, section, written);
if (!setupWritten) program.node.body.unshift(_marko_compiler.types.exportNamedDeclaration(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(setupIdentifier, _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([])))])));
writeStructureExports(program);
writeModuleRegistrations(program);
program.node.body.push(_marko_compiler.types.exportDefaultDeclaration(callRuntime("_template", _marko_compiler.types.stringLiteral((0, _marko_compiler_babel_utils.getFile)().metadata.marko.id), ...trimEmptyArgs([
templateIdentifier,
walksIdentifier,
...markReturn(section, section.hasSetupWork ? setupIdentifier : void 0, programInputSignal?.identifier)
]))));
}
} };
function assertSetupWorkFound(program, section, written) {
const setup = getSetup(section);
if (!section.hasSetupWork && setup && written.has(setup)) throw program.buildCodeFrameError("Marko internal error: analysis found no setup work for a section whose translation produced setup statements. Please open an issue with a reproduction.");
}
function markReturn(section, setup, params) {
return section.returnValueExpr && !isOptimize() ? setup ? [callRuntime("_return_setup", setup), params] : [setup, callRuntime("_return_setup", params)] : [setup, params];
}
//#endregion
//#region src/translator/visitors/program/html.ts
var html_default = { translate: {
enter() {
const sectionDynamicSubscribers = /* @__PURE__ */ new Set();
forEachSection((section) => {
forEach(section.bindings, (binding) => {
for (const [hoistSection, hasReference] of binding.getters) if (hasReference) getHTMLSectionStatements(hoistSection || section).push(_marko_compiler.types.variableDeclaration("const", [hoistSection ? _marko_compiler.types.variableDeclarator(getBindingGetterIdentifier(binding, hoistSection), callRuntime("_hoist", getScopeIdIdentifier(hoistSection), _marko_compiler.types.stringLiteral(getResumeRegisterId(hoistSection, binding, "hoist")))) : _marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(binding.originalName), callRuntime("_el", getScopeIdIdentifier(section), _marko_compiler.types.stringLiteral(getResumeRegisterId(section, binding))))]));
});
forEach(section.hoisted, (binding) => {
const highestHoistSection = first(binding.hoists);
let currentSection = section;
while (currentSection && currentSection !== highestHoistSection) {
const parentSection = currentSection.parent;
if (!isOptionalBranch(currentSection) && !sectionDynamicSubscribers.has(currentSection)) {
const subscribersIdentifier = generateUidIdentifier(`${currentSection.name}__subscribers`);
sectionDynamicSubscribers.add(currentSection);
getHTMLSectionStatements(parentSection).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(subscribersIdentifier, _marko_compiler.types.newExpression(_marko_compiler.types.identifier("Set"), []))]));
addWriteScopeBuilder(currentSection, (expr) => callRuntime("_subscribe", subscribersIdentifier, expr));
writeSlot(findSectionSlot(currentSection, 10, parentSection), subscribersIdentifier);
}
currentSection = parentSection;
}
});
});
},
exit(program) {
if (program.node.extra.hasGlobalRead) getHTMLSectionStatements(getSection(program)).push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier("$global"), callRuntime("$global"))]));
writeHTMLResumeStatements(program);
traverseReplace(program.node, "body", replaceNode);
const renderContent = [];
const section = getSection(program);
renderContent.push(getScopeReasonStatement(section));
for (const child of program.get("body")) if (!isStatic(child)) {
renderContent.push(child.node);
child.remove();
} else if (child.isMarkoScriptlet()) {
if (child.node.target && child.node.target !== "server") child.remove();
else child.replaceWithMultiple(child.node.body);
}
writeModuleRegistrations(program);
const contentId = hasSharedUid("content") && ensureSharedUid("content");
const contentFn = _marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.identifier("input")], _marko_compiler.types.blockStatement(renderContent));
const exportDefault = _marko_compiler.types.exportDefaultDeclaration(callRuntime("_template", _marko_compiler.types.stringLiteral((0, _marko_compiler_babel_utils.getFile)().metadata.marko.id), contentId ? _marko_compiler.types.identifier(contentId) : contentFn, program.node.extra.page || !getMarkoOpts().linkAssets ? _marko_compiler.types.numericLiteral(1) : void 0));
if (contentId) program.node.body.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(contentId), contentFn)]), exportDefault);
else program.node.body.push(exportDefault);
}
} };
function replaceNode(node) {
return replaceBindingReadNode(node) || replaceRegisteredFunctionNode(node);
}
function replaceBindingReadNode(node) {
switch (node.type) {
case "Identifier":
case "MemberExpression":
case "OptionalMemberExpression": return getReadReplacement(node);
case "CallExpression":
case "OptionalCallExpression": {
const read = node.callee.extra?.read;
if (read && (read.getter !== void 0 || read.binding.type === 0)) return _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.cloneNode(node.callee)], node), [importRuntime(read.binding.type === 0 ? "_el_read_error" : "_hoist_read_error")]);
break;
}
}
}
function replaceRegisteredFunctionNode(node) {
switch (node.type) {
case "ClassMethod":
case "ClassPrivateMethod":
case "ObjectMethod": {
const replacement = buildResumeCall(node);
return replacement && replaceMethodNode(node, replacement);
}
case "ArrowFunctionExpression":
case "FunctionExpression": return buildResumeCall(node);
case "BlockStatement":
case "MarkoScriptlet": registerFunctionDeclarations(node.body);
}
}
function registerFunctionDeclarations(body) {
const len = body.length;
for (let i = 0; i < len; i++) {
const child = body[i];
if (child.type === "FunctionDeclaration" && isRegisteredFnExtra(child.extra)) body.push(_marko_compiler.types.expressionStatement(callRuntime("_resume", _marko_compiler.types.identifier(child.id.name), _marko_compiler.types.stringLiteral(child.extra.registerId))));
}
}
function buildResumeCall(node) {
const { extra } = node;
if (isRegisteredFnExtra(extra)) {
const referencedLocals = extra.referencedLocalBindingsInFunction;
if (referencedLocals) {
const localProperties = [];
forEach(referencedLocals, (binding) => {
localProperties.push(toObjectProperty(getLocalsScopeAccessor(binding), getDeclaredBindingExpression(binding)));
});
return callRuntime("_resume_locals", simplifyFunction(node), _marko_compiler.types.stringLiteral(extra.registerId), _marko_compiler.types.objectExpression(localProperties), (getReferencedBindingsInFunction(extra) || extra.referencesScope) && getScopeIdIdentifier(extra.section));
}
return callRuntime("_resume", simplifyFunction(node), _marko_compiler.types.stringLiteral(extra.registerId), (getReferencedBindingsInFunction(extra) || extra.referencesScope) && getScopeIdIdentifier(extra.section));
}
}
//#endregion
//#region src/translator/core/textarea.ts
function preAnalyze$1(tag) {
if (tag.node.body.body.length) {
const [firstChild] = tag.node.body.body;
if (firstChild.type === "MarkoText") firstChild.value = firstChild.value.replace(/^\r?\n/, "");
const parts = [];
for (const child of tag.node.body.body) if (child.type === "MarkoText") parts.push((0, _marko_compiler_babel_utils.decodeHTML)(child.value));
else if (child.type === "MarkoPlaceholder" && child.escape) parts.push(child.value);
else throw (0, _marko_compiler_babel_utils.getFile)().hub.buildError(child, "Unexpected content in textarea, only text and placeholders are supported.", SyntaxError);
const textValue = buildStringExpression(parts);
if (textValue) {
const valueAttr = tag.node.attributes.find((attr) => _marko_compiler.types.isMarkoAttribute(attr) && attr.name === "value");
if (valueAttr) throw (0, _marko_compiler_babel_utils.getFile)().hub.buildError(valueAttr, "A textarea cannot have both a value attribute and body content.", SyntaxError);
tag.node.attributes.push(_marko_compiler.types.markoAttribute("value", textValue));
}
tag.node.body.body = [];
}
}
//#endregion
//#region src/translator/visitors/program/pre-analyze.ts
const TAG_NAME_IDENTIFIER_REG = /^[A-Z][a-zA-Z0-9_$]*$/;
const BINDING_CHANGE_HANDLER = /* @__PURE__ */ new WeakMap();
function preAnalyze(program) {
normalizeBody(program.get("body"));
}
function normalizeBody(body) {
if (body?.length) {
for (const child of body) if (child.isMarkoTag()) {
flattenTextOnlyConditional(child);
if (child.isMarkoTag()) normalizeTag(child);
} else if (child.isMarkoPlaceholder()) splitStaticPlaceholderText(child);
}
}
function splitStaticPlaceholderText(placeholder) {
const { node } = placeholder;
const normalized = buildStringExpression([node.value]);
if (!normalized || !_marko_compiler.types.isTemplateLiteral(normalized)) return;
node.value = normalized;
const { quasis } = normalized;
const lastIndex = quasis.length - 1;
const leading = quasis[0].value.cooked ?? "";
const trailing = quasis[lastIndex].value.cooked ?? "";
if (leading && _escape(leading) === leading) {
insertStaticText(placeholder, leading, true);
quasis[0].value = {
raw: "",
cooked: ""
};
}
if (trailing && _escape(trailing) === trailing) {
insertStaticText(placeholder, trailing, false);
quasis[lastIndex].value = {
raw: "",
cooked: ""
};
}
}
function insertStaticText(placeholder, value, before) {
const sibling = before ? placeholder.getPrevSibling() : placeholder.getNextSibling();
if (sibling.isMarkoText()) sibling.node.value = before ? sibling.node.value + value : value + sibling.node.value;
else if (before) placeholder.insertBefore(_marko_compiler.types.markoText(value));
else placeholder.insertAfter(_marko_compiler.types.markoText(value));
}
function normalizeTag(tag) {
const { node } = tag;
const { name, attributes } = node;
let invalidNameReg = invalidAttrNameReg;
if (name.type === "StringLiteral") {
const tagName = name.value;
if (tag.scope.getBinding(tagName) && TAG_NAME_IDENTIFIER_REG.test(tagName)) node.name = withPreviousLocation(_marko_compiler.types.identifier(tagName), name);
}
normalizeBody(tag.get("body").get("body"));
normalizeBody(tag.get("attributeTags"));
if (node.var) {
const insertions = moveDefaultsToConstTags(node.var);
if (insertions) tag.insertAfter(insertions);
}
if (node.body.params.length && !node.body.attributeTags) {
const insertions = moveElementDefaultsToConstTags(node.body.params);
if (insertions && node.body.body.length) node.body.body = [...insertions, ...node.body.body];
}
const nativeTagDef = getStaticNativeTagDef(tag);
if (nativeTagDef) {
if (!_marko_compiler.types.isStringLiteral(node.name)) {
node.name = withPreviousLocation(_marko_compiler.types.stringLiteral(nativeTagDef.name), node.name);
node.tagDef = nativeTagDef;
}
invalidNameReg = invalidNativeAttrNameReg;
if (nativeTagDef.parseOptions?.openTagOnly && node.body.body.length) throw tag.hub.buildError(node.body.body[0], `The \`<${nativeTagDef.name}>\` tag cannot have content, so it does not support a body.`);
if (nativeTagDef.name === "textarea") preAnalyze$1(tag);
}
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i];
if (_marko_compiler.types.isMarkoAttribute(attr)) {
if (attr.bound) {
attributes.splice(++i, 0, buildChangeHandlerAttr(tag, attr));
attr.bound = false;
} else if (attr.modifier != null) attr.name += ":" + attr.modifier;
if (invalidNameReg.test(attr.name)) {
if (isUnresolvedKnownWrongTag(tag)) throw tagNotFoundError(tag);
throw buildAttrNameError(tag, attr, "Invalid attribute name.");
}
attr.modifier = null;
}
}
}
function getStaticNativeTagDef(tag) {
const { name } = tag.node;
if (_marko_compiler.types.isStringLiteral(name)) return (0, _marko_compiler_babel_utils.isNativeTag)(tag) ? (0, _marko_compiler_babel_utils.getTagDef)(tag) : void 0;
if (_marko_compiler.types.isTemplateLiteral(name) && name.quasis.length === 1) {
const tagDef = (0, _marko_compiler_babel_utils.getTagDefForTagName)((0, _marko_compiler_babel_utils.getFile)(), name.quasis[0].value.cooked);
if (tagDef?.taglibId === "marko-html" && tagDef.html && !tagDef.template && !tagDef.renderer) return tagDef;
}
}
function buildChangeHandlerAttr(tag, attr) {
const changeAttrName = attr.name + "Change";
let modifier;
if (attr.modifier != null) {
if (!_marko_compiler.types.isValidIdentifier(attr.modifier)) throw tag.hub.buildError(attr.value.loc?.end && { loc: {
start: {
line: attr.value.loc.start.line,
column: attr.value.loc.start.column - attr.modifier.length - 2
},
end: {
line: attr.value.loc.start.line,
column: attr.value.loc.start.column - 2
}
} }, "Bound attribute refinement shorthand must be a valid JavaScript identifier.");
modifier = withPreviousLocation(_marko_compiler.types.identifier(attr.modifier), attr);
}
if (_marko_compiler.types.isIdentifier(attr.value)) {
const binding = tag.scope.getBinding(attr.value.name);
if (!binding) return _marko_compiler.types.markoAttribute(changeAttrName, buildChangeHandlerFunction(attr.value, modifier));
const modifierKey = modifier?.name ?? "";
let handlerByModifier = BINDING_CHANGE_HANDLER.get(binding.identifier);
if (!handlerByModifier) BINDING_CHANGE_HANDLER.set(binding.identifier, handlerByModifier = /* @__PURE__ */ new Map());
const existingChangedAttr = handlerByModifier.get(modifierKey);
if (!existingChangedAttr) {
const bindingIdentifierPath = binding.path.getOuterBindingIdentifierPaths()[binding.identifier.name];
let changeAttrExpr = bindingIdentifierPath ? bindingIdentifierPath.parentPath === binding.path ? buildChangeHandlerFunction(attr.value, modifier) : bindingIdentifierPath.parentPath.isObjectProperty() ? ensureDestructuredChangeHandler(bindingIdentifierPath.parentPath) : void 0 : void 0;
if (!changeAttrExpr) throw tag.hub.buildError(attr.value, bindingIdentifierPath?.parentPath?.isArrayPattern() ? `Cannot two-way bind to \`${attr.value.name}\` because it comes from array destructuring, which has no change handler. Use object destructuring or pass an explicit \`${changeAttrName}\` attribute.` : bindingIdentifierPath?.parentPath?.isObjectProperty({ computed: true }) ? `Cannot two-way bind to \`${attr.value.name}\` because it is destructured with a dynamically computed key, so its change handler cannot be derived. Use a static key or pass an explicit \`${changeAttrName}\` attribute.` : "Unable to bind to value.");
if (modifier && _marko_compiler.types.isIdentifier(changeAttrExpr)) changeAttrExpr = _marko_compiler.types.logicalExpression("&&", changeAttrExpr, buildModifierForwarder(_marko_compiler.types.cloneNode(changeAttrExpr), modifier));
const changeHandlerAttr = _marko_compiler.types.markoAttribute(changeAttrName, changeAttrExpr);
handlerByModifier.set(modifierKey, changeHandlerAttr);
return changeHandlerAttr;
}
if (existingChangedAttr.type === "Identifier") return _marko_compiler.types.markoAttribute(changeAttrName, withPreviousLocation(_marko_compiler.types.identifier(existingChangedAttr.name), attr.value));
const markoRoot = isMarkoRoot(binding.path) ? binding.path : getMarkoRoot(binding.path);
if (!(markoRoot?.isMarkoTag() || markoRoot?.isMarkoTagBody())) throw tag.hub.buildError(attr.value, "Unable to bind to value.");
const changeHandlerId = generateUid(changeAttrName);
const changeHandlerConst = toConstTag(_marko_compiler.types.identifier(changeHandlerId), existingChangedAttr.value);
handlerByModifier.set(modifierKey, existingChangedAttr.value = _marko_compiler.types.identifier(changeHandlerId));
if (markoRoot.isMarkoTag()) markoRoot.insertAfter(changeHandlerConst);
else markoRoot.unshiftContainer("body", changeHandlerConst);
return _marko_compiler.types.markoAttribute(changeAttrName, withPreviousLocation(_marko_compiler.types.identifier(changeHandlerId), attr.value));
} else if (_marko_compiler.types.isMemberExpression(attr.value) || _marko_compiler.types.isOptionalMemberExpression(attr.value)) {
const prop = attr.value.property;
if (!_marko_compiler.types.isPrivateName(attr.value.property)) {
const memberObj = _marko_compiler.types.cloneNode(attr.value.object);
const memberProp = !attr.value.computed && prop.type === "Identifier" ? withPreviousLocation(_marko_compiler.types.identifier(prop.name + "Change"), prop) : _marko_compiler.types.binaryExpression("+", _marko_compiler.types.cloneNode(prop), _marko_compiler.types.stringLiteral("Change"));
const computed = memberProp.type !== "Identifier";
let changeAttrExpr = attr.value.optional ? _marko_compiler.types.optionalMemberExpression(memberObj, memberProp, computed, true) : _marko_compiler.types.memberExpression(memberObj, memberProp, computed);
if (modifier) changeAttrExpr = _marko_compiler.types.logicalExpression("&&", changeAttrExpr, buildModifierForwarder(_marko_compiler.types.memberExpression(memberObj, memberProp, computed), modifier));
return _marko_compiler.types.markoAttribute(changeAttrName, changeAttrExpr);
}
}
throw tag.hub.buildError(attr.value, "Attributes may only be bound to identifiers or member expressions");
}
function buildModifierForwarder(changeHandler, modifier) {
const newValueId = generateUid("next");
return _marko_compiler.types.arrowFunctionExpression([_marko_compiler.types.identifier(newValueId)], _marko_compiler.types.blockStatement([_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(changeHandler, [_marko_compiler.types.callExpression(_marko_compiler.types.cloneNode(modifier), [_marko_compiler.types.identifier(newValueId)])]))]));
}
function buildChangeHandlerFunction(id, modifier) {
const newId = "_new_" + id.name;
let newValue = withPreviousLocation(_marko_compiler.types.identifier(newId), id);
if (modifier) newValue = _marko_compiler.types.callExpression(modifier, [newValue]);
return _marko_compiler.types.arrowFunctionExpression([withPreviousLocation(_marko_compiler.types.identifier(newId), id)], _marko_compiler.types.blockStatement([_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("=", withPreviousLocation(_marko_compiler.types.identifier(id.name), id), newValue))]));
}
function ensureDestructuredChangeHandler(parent) {
let changeKey;
const pattern = parent.parentPath;
const keyName = getStaticKeyName(parent.node);
if (keyName === void 0) return;
const searchKey = `${keyName}Change`;
for (const prop of pattern.get("properties")) if (prop.isObjectProperty()) {
const propValue = prop.get("value");
if (getStaticKeyName(prop.node) === searchKey && propValue.isIdentifier()) {
changeKey = propValue.node;
break;
}
}
if (!changeKey) pattern.unshiftContainer("properties", _marko_compiler.types.objectProperty(_marko_compiler.types.stringLiteral(searchKey), changeKey = generateUidIdentifier(searchKey)));
return changeKey;
}
function getStaticKeyName(prop) {
return prop.computed && !_marko_compiler.types.isStringLiteral(prop.key) ? void 0 : getLiteralName(prop.key);
}
function moveDefaultsToConstTags(node, insertions) {
switch (node.type) {
case "ObjectPattern":
for (const prop of node.properties) if (prop.type === "ObjectProperty") {
if (prop.value.type === "AssignmentPattern") {
const { left, right } = prop.value;
const sourceName = generateUid(getLiteralName(left) || getLiteralName(prop.key) || "pattern");
prop.shorthand = false;
prop.value = _marko_compiler.types.identifier(sourceName);
(insertions ||= []).push(toConstTag(left, toFallbackExpr(sourceName, right)));
moveDefaultsToConstTags(left, insertions);
} else insertions = moveDefaultsToConstTags(prop.value, insertions);
}
break;
case "ArrayPattern": insertions = moveElementDefaultsToConstTags(node.elements, insertions);
}
return insertions;
}
function moveElementDefaultsToConstTags(elements, insertions) {
for (let i = 0, len = elements.length; i < len; i++) {
const el = elements[i];
if (el != null) {
if (el.type === "AssignmentPattern") {
const { left, right } = el;
const sourceName = generateUid(getLiteralName(left) || "pattern");
elements[i] = withPreviousLocation(_marko_compiler.types.identifier(sourceName), el);
(insertions ||= []).push(toConstTag(left, toFallbackExpr(sourceName, right)));
moveDefaultsToConstTags(left, insertions);
} else insertions = moveDefaultsToConstTags(el, insertions);
}
}
return insertions;
}
function toFallbackExpr(id, fallback) {
return _marko_compiler.types.conditionalExpression(_marko_compiler.types.binaryExpression("!==", _marko_compiler.types.buildUndefinedNode(), _marko_compiler.types.identifier(id)), _marko_compiler.types.identifier(id), fallback);
}
function toConstTag(id, expr) {
return _marko_compiler.types.markoTag(_marko_compiler.types.stringLiteral("const"), [_marko_compiler.types.markoAttribute("value", expr, null, null, true)], _marko_compiler.types.markoTagBody(), null, id);
}
//#endregion
//#region src/translator/visitors/program/index.ts
var program_default = {
migrate: {
enter(program) {
program.node.params = [_marko_compiler.types.identifier("input")];
},
exit(program) {
program.scope.crawl();
}
},
transform: { exit: preAnalyze },
analyze: {
enter(program) {
ensureBodySection(program);
trackParamsReferences(program, 2);
const programExtra = program.node.extra ??= {};
const inputBinding = program.node.params[0].extra?.binding;
if (inputBinding) inputBinding.nullable = false;
programExtra.exportNames = {
template: generateUid("template"),
walks: generateUid("walks"),
setup: generateUid("setup"),
params: /* @__PURE__ */ new Map(),
directContent: /* @__PURE__ */ new Map()
};
const styleFile = getStyleFile((0, _marko_compiler_babel_utils.getFile)());
if (styleFile) {
programExtra.styleFile = styleFile;
addAssetImport(styleFile);
}
},
exit(program) {
if (hasAnalyzeErrors()) return;
analyzeRecursiveTags();
finalizeReferences();
const programExtra = program.node.extra;
const paramsBinding = programExtra.binding;
if (paramsBinding && !paramsBinding.pruned) programExtra.paramsTree = exposeParamsTree(paramsBinding);
const section = programExtra.section;
forEachSection((childSection) => {
programExtra.hasResumes ||= !!(isUnconditionalReason(childSection.reason) || childSection !== section && !isSectionRendererElided(childSection) && getRendererReason(childSection));
});
finalizeSetupWork();
}
},
translate: {
enter(program) {
createScopeIdentifiers();
{
const markoOpts = getMarkoOpts();
const { output, entry, runtimeId } = markoOpts;
const isLoadEntry = entry === "load";
const isDOMPageEntry = output === "dom" && entry === "page" || output === "hydrate";
const isServerEntry = output === "html" && entry === "page";
if (entry && !markoOpts.linkAssets) throw program.buildCodeFrameError("The \"entry\" option requires the `linkAssets` compiler option to be configured.");
if (runtimeId && !/^[_a-z][_a-z0-9]*$/i.test(runtimeId)) throw program.buildCodeFrameError(`Invalid runtimeId: "${runtimeId}". The runtimeId must start with a letter or underscore and only contain letters, numbers, and underscores.`);
if (isLoadEntry) {
const entryFile = (0, _marko_compiler_babel_utils.getFile)();
const { filename } = entryFile.opts;
const readyId = getReadyId(entryFile);
const report = !markoOpts.optimize;
program.node.body = [_marko_compiler.types.importDeclaration([_marko_compiler.types.importSpecifier(_marko_compiler.types.identifier("ready"), _marko_compiler.types.identifier("ready")), ...report ? [_marko_compiler.types.importSpecifier(_marko_compiler.types.identifier("readyFailed"), _marko_compiler.types.identifier("readyFailed"))] : []], _marko_compiler.types.stringLiteral(getRuntimePath("dom"))), _marko_compiler.types.expressionStatement(dynamicImport((0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, filename), _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.callExpression(_marko_compiler.types.identifier("ready"), [_marko_compiler.types.stringLiteral(readyId)])), report && _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.callExpression(_marko_compiler.types.identifier("readyFailed"), [_marko_compiler.types.stringLiteral(readyId)]))))];
program.skip();
return;
}
if (isDOMPageEntry) {
const entryFile = (0, _marko_compiler_babel_utils.getFile)();
builder.visit(entryFile, entryFile);
program.node.body = builder.build(entryFile);
program.skip();
return;
}
if (isServerEntry) {
const entryFile = (0, _marko_compiler_babel_utils.getFile)();
const { filename } = entryFile.opts;
const relativeImport = (0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, filename);
const templateId = (0, _marko_compiler_babel_utils.getTemplateId)(markoOpts, filename);
const pageAssetArgs = [
_marko_compiler.types.identifier("template"),
_marko_compiler.types.identifier("flush"),
_marko_compiler.types.stringLiteral(templateId)
];
if (runtimeId) pageAssetArgs.push(_marko_compiler.types.stringLiteral(runtimeId));
markoOpts.linkAssets.onAsset("page", filename, templateId);
program.node.body = [
_marko_compiler.types.importDeclaration([_marko_compiler.types.importSpecifier(_marko_compiler.types.identifier("flush"), _marko_compiler.types.identifier("flush"))], _marko_compiler.types.stringLiteral(markoOpts.linkAssets.runtime)),
_marko_compiler.types.importDeclaration([_marko_compiler.types.importDefaultSpecifier(_marko_compiler.types.identifier("template"))], _marko_compiler.types.stringLiteral(relativeImport)),
_marko_compiler.types.importDeclaration([_marko_compiler.types.importSpecifier(_marko_compiler.types.identifier("withPageAssets"), _marko_compiler.types.identifier("withPageAssets"))], _marko_compiler.types.stringLiteral(getRuntimePath("html"))),
_marko_compiler.types.exportAllDeclaration(_marko_compiler.types.stringLiteral(relativeImport)),
_marko_compiler.types.exportDefaultDeclaration(_marko_compiler.types.callExpression(_marko_compiler.types.identifier("withPageAssets"), pageAssetArgs))
];
program.skip();
return;
}
}
if (isOutputHTML()) html_default.translate.enter();
else dom_default.translate.enter(program);
},
exit(program) {
if (isOutputHTML()) html_default.translate.exit(program);
else dom_default.translate.exit(program);
if (program.node.extra?.needsCompat) {
const compatFile = getCompatRuntimeFile();
const body = [void 0];
for (const child of program.node.body) if (child.type === "ImportDeclaration" && child.source.value === compatFile) body[0] = child;
else body.push(child);
body[0] ??= _marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(compatFile));
program.node.body = body;
}
}
}
};
//#endregion
//#region src/translator/visitors/referenced-identifier.ts
const kAbortId = Symbol("abort id");
const [getAbortResetEmitted] = createSectionState("abortResetEmitted", () => /* @__PURE__ */ new Set());
var referenced_identifier_default = {
migrate(identifier) {
const { name } = identifier.node;
if (identifier.scope.hasBinding(name)) return;
switch (name) {
case "out": if (_marko_compiler.types.isMemberExpression(identifier.parent) && _marko_compiler.types.isIdentifier(identifier.parent.property) && identifier.parent.property.name === "global") identifier.parentPath.replaceWith(_marko_compiler.types.identifier("$global"));
else throw identifier.buildCodeFrameError("Only `out.global` is supported for compatibility.");
}
},
analyze(identifier) {
const { name } = identifier.node;
if (identifier.scope.hasBinding(name)) return;
if (name === "$global") {
assertReferencedInRender(identifier, name);
setReferencesScope(identifier);
trackGlobalReference(identifier);
} else if (name === "$signal") {
assertReferencedInRender(identifier, name);
const section = ensureSection(identifier);
section.hasAbortSignal = true;
setReferencesScope(identifier);
const rootExtra = getExprRoot(identifier).node.extra ??= { section };
(identifier.node.extra ??= {}).exprRoot = rootExtra;
if (rootExtra[kAbortId] === void 0) rootExtra[kAbortId] = section.abortSignalExprs++;
}
},
translate(identifier) {
const { name } = identifier.node;
if (identifier.scope.hasBinding(name)) return;
switch (name) {
case "$global": {
if (isOutputHTML()) break;
const globalRead = _marko_compiler.types.memberExpression(scopeIdentifier, _marko_compiler.types.identifier(getAccessorProp().Global));
const key = !isOptimize() && getSignalGlobalKey(identifier);
if (key) identifier.parentPath.replaceWith(callRuntime("_global_read", globalRead, _marko_compiler.types.stringLiteral(key)));
else replaceWithExtra(identifier, globalRead);
break;
}
case "$signal": if (isOutputHTML()) replaceWithExtra(identifier, _marko_compiler.types.callExpression(_marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement([_marko_compiler.types.throwStatement(_marko_compiler.types.newExpression(_marko_compiler.types.identifier("Error"), [_marko_compiler.types.stringLiteral("Cannot use $signal in a server render.")]))])), []));
else {
const exprRoot = identifier.node.extra.exprRoot;
const canonicalExtra = getCanonicalExtra(exprRoot);
if (canonicalExtra.dropped) break;
const section = getSection(identifier);
const exprId = exprRoot[kAbortId];
const resetEmitted = getAbortResetEmitted(section);
if (!resetEmitted.has(exprRoot)) {
resetEmitted.add(exprRoot);
addStatement("render", section, getReferencedBindings(canonicalExtra), _marko_compiler.types.callExpression(importRuntime("$signalReset"), [scopeIdentifier, _marko_compiler.types.numericLiteral(exprId)]));
}
identifier.replaceWith(_marko_compiler.types.callExpression(importRuntime("$signal"), [scopeIdentifier, _marko_compiler.types.numericLiteral(exprId)]));
}
}
}
};
function replaceWithExtra(path, replacement) {
replacement.extra = path.node.extra;
path.replaceWith(replacement);
}
function getSignalGlobalKey(identifier) {
const { parent } = identifier;
if (!_marko_compiler.types.isMemberExpression(parent) || parent.computed || !_marko_compiler.types.isIdentifier(parent.property) || parent.object !== identifier.node) return;
const { name } = parent.property;
if (name === "runtimeId" || name === "renderId") return;
return getReferencedBindings(getExprRoot(identifier).node.extra) ? name : void 0;
}
//#endregion
//#region src/translator/visitors/scriptlet.ts
var scriptlet_default = {
analyze(scriptlet) {
if (!scriptlet.node.static) {
reportAnalyzeError(scriptlet, scriptlet.buildCodeFrameError("Scriptlets are not supported when using the tags api."));
scriptlet.skip();
return;
}
mergeReferences(ensureSection(scriptlet), scriptlet.node, scriptlet.node.body);
if (scriptlet.node.target === "client") (0, _marko_compiler_babel_utils.getProgram)().node.extra.hasClientStatement = true;
},
translate: { exit(scriptlet) {
const { node } = scriptlet;
const isHTML = isOutputHTML();
if (node.target && node.target !== (isHTML ? "server" : "client")) {
const ids = Object.keys(scriptlet.getOuterBindingIdentifiers());
const decl = ids.length && _marko_compiler.types.variableDeclaration("var", ids.map((key) => _marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(key))));
if (decl) {
if (isHTML) {
scriptlet.node.target = null;
scriptlet.node.body = [decl];
} else scriptlet.replaceWith(decl);
} else scriptlet.remove();
return;
}
if (isHTML) {} else {
traverseReplace(node, "body", replaceRegisteredFunctionNode$1);
scriptlet.replaceWithMultiple(node.body);
}
} }
};
//#endregion
//#region src/translator/visitors/tag/attribute-tag.ts
var attribute_tag_default = {
analyze: { enter(tag) {
(0, _marko_compiler_babel_utils.assertNoVar)(tag);
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
const body = tag.get("body");
const bodySection = ensureBodySection(body);
trackParamsReferences(body, 2);
if (!(0, _marko_compiler_babel_utils.findParentTag)(tag)) throw tag.get("name").buildCodeFrameError("[Attribute tags](https://markojs.com/docs/reference/language#attribute-tags) must be nested within another tag.");
const parentTag = getAttributeTagParent(tag);
if (bodySection && analyzeTagNameType(parentTag) === 2 && !parentTag.node.extra.defineBodySection) bodySection.branchExpr = parentTag.node.extra;
} },
translate: {
enter(tag) {
if (tag.node.extra.dropped) {
tag.remove();
return;
}
removeDroppedContent(tag);
if (isOutputHTML()) flushBefore(tag);
},
exit(tag) {
if (isOutputHTML()) writeHTMLResumeStatements(tag);
}
}
};
//#endregion
//#region src/translator/visitors/tag/custom-tag.ts
const [getLoadIdentifiers] = createProgramState(() => ({
triggers: /* @__PURE__ */ new Map(),
signals: /* @__PURE__ */ new Map(),
setups: /* @__PURE__ */ new Map()
}));
var custom_tag_default = {
analyze: { enter(tag) {
if (!(0, _marko_compiler_babel_utils.getTagTemplate)(tag)) throw tagNotFoundError(tag);
(0, _marko_compiler_babel_utils.assertAttributesOrSingleArg)(tag);
const childFile = (0, _marko_compiler_babel_utils.loadFileForTag)(tag);
if (!childFile) throw tag.get("name").buildCodeFrameError("Unable to resolve file for tag.");
const tagExtra = tag.node.extra ??= {};
const programExtra = (0, _marko_compiler_babel_utils.getProgram)().node.extra;
const childExtra = childFile.ast.program.extra;
const childSection = childExtra.section;
if (childExtra.page) programExtra.page ??= true;
if (tagExtra.tagNameLoad) {
if (tag.node.var) throw tag.get("var").buildCodeFrameError(`The \`${getTagNameHint(tag.node)}\` tag is lazily loaded, so it does not support a [tag variable](https://markojs.com/docs/reference/language#tag-variables). Remove the variable, or import the tag without \`load\`.`);
tagExtra.nodeBinding = createBinding("#text", 0, ensureSection(tag));
}
knownTagAnalyze(tag, childSection, childExtra.paramsTree);
const tagName = getTagNameHint(tag.node);
if (tagExtra.tagNameLoad) {
marker(tag, tagExtra.nodeBinding);
child(tag, tagName);
enterShallow(tag);
} else child(tag, tagName, {
kind: ExportRef,
program: childExtra,
path: getTagRelativePath(tag),
hint: tagName
});
} },
translate: {
enter(tag) {
removeDroppedContent(tag);
if (isOutputHTML()) flushBefore(tag);
},
exit(tag) {
if (isOutputHTML()) translateHTML(tag);
else translateDOM(tag);
}
}
};
function translateHTML(tag) {
const { node } = tag;
let tagIdentifier;
if (_marko_compiler.types.isStringLiteral(node.name)) {
const relativePath = getTagRelativePath(tag);
tagIdentifier = isCircularRequest((0, _marko_compiler_babel_utils.getFile)(), relativePath) ? _marko_compiler.types.identifier(ensureSharedUid("content")) : (0, _marko_compiler_babel_utils.importDefault)((0, _marko_compiler_babel_utils.getFile)(), relativePath, getTagName(tag));
} else tagIdentifier = node.name;
knownTagTranslateHTML(tag, tagIdentifier);
}
function translateDOM(tag) {
const { node } = tag;
const file = (0, _marko_compiler_babel_utils.getFile)();
const relativePath = getTagRelativePath(tag);
const programSection = (0, _marko_compiler_babel_utils.getProgram)().node.extra.section;
const childFile = (0, _marko_compiler_babel_utils.loadFileForTag)(tag);
const childExtra = childFile.ast.program.extra;
const childExports = childExtra.exportNames;
const childSection = childExtra.section;
const loadConfig = node.extra?.tagNameLoad;
const isLoad = !!loadConfig;
const tagName = getTagNameHint(node);
if (isLoad) {
const childFileName = childFile.opts.filename;
const { triggers, signals, setups } = getLoadIdentifiers();
let triggerIdent = triggers.get(loadConfig);
if (!triggerIdent) {
const triggerExpr = loadTriggersToExpression(loadConfig);
if (triggerExpr) {
triggerIdent = generateUidIdentifier(`load_${tagName}_trigger`);
triggers.set(loadConfig, triggerIdent);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(triggerIdent, triggerExpr)]));
}
}
knownTagTranslateDOM(tag, (binding) => {
const signalKey = `${triggerIdent ? triggerIdent.name : ""}\0${childFileName}\0${childExports.params.get(binding)}`;
return signals.get(signalKey) || createLoadIdentifier(signals, signalKey, `load_${tagName}_tag_${binding.name}`, "_load_signal", buildLoadSignalVirtualModule(file, childFileName, childExports.params.get(binding), binding.name), triggerIdent);
}, (section, childBinding) => {
const setupKey = `${triggerIdent ? triggerIdent.name : ""}\0${childFileName}`;
let setupIdent = setups.get(setupKey);
if (!setupIdent) {
importRuntimeFeature("catch");
setupIdent = createLoadIdentifier(setups, setupKey, `load_${tagName}_setup`, "_load_setup", buildLoadSetupVirtualModule(file, childFileName, childExports), triggerIdent);
}
addStatement("render", section, void 0, _marko_compiler.types.callExpression(setupIdent, [
scopeIdentifier,
createScopeReadExpression(childBinding, section),
createScopeReadExpression(node.extra.nodeBinding, section)
]));
});
} else if (programSection === childSection) knownTagTranslateDOM(tag, (binding, preferredName) => getSignal(programSection, binding, preferredName).identifier, childSection.hasSetupWork ? (section, childBinding) => {
addStatement("render", section, void 0, _marko_compiler.types.callExpression(_marko_compiler.types.identifier(childExports.setup), [createScopeReadExpression(childBinding, section)]));
} : void 0);
else {
knownTagTranslateDOM(tag, (binding, preferredName, directContent) => importOrSelfReferenceName((0, _marko_compiler_babel_utils.getFile)(), relativePath, directContent && childExports.directContent.get(binding) || childExports.params.get(binding), preferredName), childSection.hasSetupWork ? (section, childBinding) => {
addStatement("render", section, void 0, _marko_compiler.types.callExpression(importOrSelfReferenceName(file, relativePath, childExports.setup, tagName), [createScopeReadExpression(childBinding, section)]));
} : void 0);
(0, _marko_compiler_babel_utils.importNamed)(file, relativePath, childExports.template, `${tagName}_template`);
(0, _marko_compiler_babel_utils.importNamed)(file, relativePath, childExports.walks, `${tagName}_walks`);
}
tag.remove();
}
function createLoadIdentifier(cache, key, name, runtime, request, trigger) {
const id = generateUidIdentifier(name);
cache.set(key, id);
const load = _marko_compiler.types.arrowFunctionExpression([], dynamicImport(request));
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.variableDeclaration("let", [_marko_compiler.types.variableDeclarator(id, callRuntime(runtime, trigger ? _marko_compiler.types.addComment(_marko_compiler.types.callExpression(trigger, [load]), "leading", "@__PURE__") : load))]));
return id;
}
function buildLoadSetupVirtualModule(file, childFileName, childExports) {
const parts = `${childExports.template}, ${childExports.walks}, ${childExports.setup}`;
return getMarkoOpts().resolveVirtualDependency(file.opts.filename, {
virtualPath: `${(0, _marko_compiler_babel_utils.resolveRelativePath)(file, childFileName)}.setup.js`,
code: `import { ${parts} } from "./${path.default.basename(childFileName)}"\nexport const _ = [${parts}]`
});
}
function buildLoadSignalVirtualModule(file, childFileName, childExport, childBinding) {
return getMarkoOpts().resolveVirtualDependency(file.opts.filename, {
virtualPath: `${(0, _marko_compiler_babel_utils.resolveRelativePath)(file, childFileName)}.${childBinding}.js`,
code: `export { ${childExport} as _ } from "./${path.default.basename(childFileName)}"`
});
}
function loadTriggersToExpression(loadConfig) {
if (!loadConfig || loadConfig.render) return;
const triggers = loadConfig.triggers.map(toDOMTriggerExpression);
return triggers.length === 1 ? triggers[0] : callRuntime("_load_race_trigger", ...triggers);
}
function toDOMTriggerExpression(trigger) {
switch (trigger.type) {
case "visible": return callRuntime("_load_visible_trigger", _marko_compiler.types.stringLiteral(trigger.selector), optionalValueToNode(trigger.options));
case "idle": return callRuntime("_load_idle_trigger", optionalValueToNode(trigger.options));
case "media": return callRuntime("_load_media_trigger", _marko_compiler.types.stringLiteral(trigger.selector));
default: return callRuntime("_load_event_trigger", _marko_compiler.types.stringLiteral(trigger.type.slice(3)), _marko_compiler.types.stringLiteral(trigger.selector));
}
}
function optionalValueToNode(value) {
return value ? _marko_compiler.types.valueToNode(value) : void 0;
}
//#endregion
//#region src/translator/visitors/tag/dynamic-tag.ts
const [getAddedStatementKeys] = createProgramState(() => /* @__PURE__ */ new Set());
const [getCompatBoundaryCalls] = createProgramState(() => /* @__PURE__ */ new Map());
function pushStatementOnce(key, statement) {
const keys = getAddedStatementKeys();
if (keys.has(key)) return false;
keys.add(key);
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(statement);
return true;
}
var dynamic_tag_default = {
analyze: { enter(tag) {
if (tag.node.extra?.tagNameUnresolved) throw tagNotFoundError(tag);
(0, _marko_compiler_babel_utils.assertAttributesOrArgs)(tag);
const { node } = tag;
if (node.var && node.extra.featureType === "class") throw tag.get("var").buildCodeFrameError(`The Marko 5 (class API) tag \`${getTagNameHint(node)}\` cannot [\`<return>\`](https://markojs.com/docs/reference/core-tag#return) a value, so it does not support a [tag variable](https://markojs.com/docs/reference/language#tag-variables). Remove the variable, or migrate the tag to the tags API.`);
const definedBodySection = node.extra?.defineBodySection;
if (definedBodySection) {
knownTagAnalyze(tag, definedBodySection);
child(tag, getTagNameHint(tag.node), {
kind: SectionRef,
section: definedBodySection
});
return;
}
analyzeAttributeTags(tag);
const tagSection = ensureSection(tag);
const inputNodes = getAllTagReferenceNodes(node);
const tagExtra = mergeReferences(tagSection, node, [node.name, ...inputNodes]);
if (inputNodes.length) tagExtra.retained = true;
const tagBody = tag.get("body");
const hasVar = !!tag.node.var;
const usesVar = hasVar && isTagVarUsed(tag);
let isInteractive = usesVar;
for (const attr of node.attributes) if (_marko_compiler.types.isMarkoSpreadAttribute(attr)) isInteractive = true;
else if (isEventOrChangeHandler(attr.name)) {
isInteractive = true;
if (!isEventHandler(attr.name)) (attr.value.extra ??= {}).retained = true;
}
if (isInteractive) (0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
const nodeBinding = tagExtra.nodeBinding = createBinding("#text", 0, tagSection);
if (hasVar) {
trackVarReferences(tag, 4).returnedBy = nodeBinding;
reserveId(nodeBinding, 1);
}
const bodySection = ensureBodySection(tagBody);
if (bodySection) {
bodySection.branchExpr = tagExtra;
if (tagExtra.tagNameType === 1 && !node.arguments) setTagContentDerives(tag, getDynamicTagInputBindings(tagExtra), { value: tagExtra });
}
trackParamsReferences(tagBody, 2);
if (usesVar) addAlwaysReason(nodeBinding);
addReasonExprs(ensureSlot(nodeBinding), tagExtra);
if (!hasVar && !node.arguments && !node.attributes.length && !node.body.body.length) tagExtra.nameOnly = true;
marker(tag, nodeBinding);
enterShallow(tag);
if (bodySection && tagExtra.featureType === "class" && !(0, _marko_compiler_babel_utils.getTagTemplate)(tag)) bodySection.structure = null;
} },
translate: {
enter(tag) {
if (tag.node.extra?.featureType === "class" && !isOutputHTML() && !(0, _marko_compiler_babel_utils.getTagTemplate)(tag)) {
tag.remove();
return;
}
removeDroppedContent(tag);
if (isOutputHTML()) flushBefore(tag);
},
exit(tag) {
const { node } = tag;
const tagSection = getSection(tag);
const definedBodySection = node.extra?.defineBodySection;
if (definedBodySection) {
if (isOutputHTML()) knownTagTranslateHTML(tag, _marko_compiler.types.memberExpression(tag.node.name, _marko_compiler.types.identifier("content")));
else {
const directContentNames = (0, _marko_compiler_babel_utils.getProgram)().node.extra.exportNames.directContent;
knownTagTranslateDOM(tag, (binding, preferredName, directContent) => {
const directName = directContent && directContentNames.get(binding);
return directName ? _marko_compiler.types.identifier(directName) : getSignal(definedBodySection, binding, preferredName).identifier;
}, (section, childBinding) => {
if (definedBodySection.hasSetupWork) addStatement("render", section, void 0, _marko_compiler.types.callExpression(_marko_compiler.types.memberExpression(getSignal(definedBodySection, void 0).identifier, _marko_compiler.types.identifier("_")), [createScopeReadExpression(childBinding, section), getScopeExpression(section, definedBodySection.parent)]));
else if (definedBodySection.readsOwner) addStatement("render", section, void 0, _marko_compiler.types.assignmentExpression("=", toMemberExpression(createScopeReadExpression(childBinding, section), getAccessorProp().Owner), getScopeExpression(section, definedBodySection.parent)));
});
tag.remove();
}
return;
}
const tagExtra = node.extra;
const nodeBinding = tagExtra.nodeBinding;
const isClassAPI = tagExtra.featureType === "class";
const markerReason = getWriteReason(nodeBinding);
let tagExpression = node.name;
if (isClassAPI) {
const classTagTemplate = (0, _marko_compiler_babel_utils.getTagTemplate)(tag);
const classFile = classTagTemplate ? (0, _marko_compiler_babel_utils.loadFileForTag)(tag) : void 0;
const classHydration = classFile?.metadata.marko.classHydration;
if (!isOutputHTML() && isOptimize() && classTagTemplate && !markerReason && !classHydration) {
tag.remove();
return;
}
((0, _marko_compiler_babel_utils.getProgram)().node.extra ??= {}).needsCompat = true;
if (_marko_compiler.types.isStringLiteral(tagExpression)) tagExpression = (0, _marko_compiler_babel_utils.importDefault)((0, _marko_compiler_babel_utils.getFile)(), getTagRelativePath(tag), tagExpression.value);
if (classTagTemplate) {
const preserveBoundary = !markerReason && (classHydration === "descendant" || classHydration === "self" && !!classFile?.metadata.marko.hasComponentBrowser);
const classId = classFile.metadata.marko.id;
const registration = isOutputHTML() ? _marko_compiler.types.callExpression((0, _marko_compiler_babel_utils.importNamed)((0, _marko_compiler_babel_utils.getFile)(), getCompatRuntimeFile(), "s"), [
_marko_compiler.types.stringLiteral(classId),
_marko_compiler.types.identifier(tagExpression.name),
...preserveBoundary ? [_marko_compiler.types.stringLiteral("preserve")] : []
]) : void 0;
if (isOutputHTML() ? markerReason || classHydration : markerReason) {
if (pushStatementOnce(classId, registration ? _marko_compiler.types.markoScriptlet([_marko_compiler.types.expressionStatement(registration)], true) : _marko_compiler.types.expressionStatement(registerRuntimeValue(classId, _marko_compiler.types.identifier(tagExpression.name)))) && registration) getCompatBoundaryCalls().set(classId, registration);
}
if (!preserveBoundary) {
const emitted = getCompatBoundaryCalls().get(classId);
if (emitted) emitted.arguments.length = 2;
}
} else {
const rendererName = tagExpression.name;
pushStatementOnce(rendererName, _marko_compiler.types.markoScriptlet([_marko_compiler.types.expressionStatement(_marko_compiler.types.assignmentExpression("??=", _marko_compiler.types.memberExpression(_marko_compiler.types.identifier(rendererName), _marko_compiler.types.identifier("_")), _marko_compiler.types.identifier(rendererName)))], true));
}
} else if (_marko_compiler.types.isStringLiteral(tagExpression)) tagExpression = (0, _marko_compiler_babel_utils.importDefault)((0, _marko_compiler_babel_utils.getFile)(), getTagRelativePath(tag), tagExpression.value);
const { properties, statements } = translateAttrs(tag, void 0, void 0, void 0, isClassAPI ? "renderBody" : "content");
const args = [];
const contentProp = getTranslatedBodyContentProperty(properties);
let hasTagArgs = false;
if (node.arguments) {
hasTagArgs = true;
args.push(...node.arguments);
if (properties.length) args.push(propsToExpression(properties));
} else if (contentProp) {
properties.splice(properties.indexOf(contentProp), 1);
args.push(propsToExpression(properties), contentProp.value);
} else args.push(propsToExpression(properties));
if (isOutputHTML()) {
writeHTMLResumeStatements(tag);
const markerGuard = getWriteGuard(tagSection, markerReason, true);
const debugTagVar = !isOptimize() && node.var && _marko_compiler.types.numericLiteral(1);
const dynamicTagExpr = hasTagArgs ? callRuntime("_dynamic_tag", getScopeIdIdentifier(tagSection), getScopeAccessorLiteral(nodeBinding), tagExpression, _marko_compiler.types.arrayExpression(args), contentProp ? contentProp.value : _marko_compiler.types.numericLiteral(0), _marko_compiler.types.numericLiteral(1), markerGuard, debugTagVar) : callRuntime("_dynamic_tag", getScopeIdIdentifier(tagSection), getScopeAccessorLiteral(nodeBinding), tagExpression, args[0], args[1] || (markerGuard ? _marko_compiler.types.numericLiteral(0) : void 0), markerGuard ? _marko_compiler.types.numericLiteral(0) : void 0, markerGuard, debugTagVar);
if (node.var && isTagVarResumed(tag)) {
const dynamicScopeIdentifier = generateUidIdentifier(tag.get("name").toString() + "_scope");
const mutatesTagVar = isTagVarAssigned(tag);
statements.push(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(dynamicScopeIdentifier, callRuntime("_peek_scope_id"))]));
translateVar(tag, dynamicTagExpr, "let", statements);
statements.push(_marko_compiler.types.expressionStatement(callRuntime("_var", getScopeIdIdentifier(tagSection), getScopeOffsetAccessorLiteral(nodeBinding), dynamicScopeIdentifier, _marko_compiler.types.stringLiteral(getResumeRegisterId(tagSection, node.var.extra?.binding, "var")), mutatesTagVar ? getScopeAccessorLiteral(nodeBinding) : void 0)));
} else if (node.var) translateVar(tag, dynamicTagExpr, "let", statements);
else statements.push(_marko_compiler.types.expressionStatement(dynamicTagExpr));
for (const replacement of tag.replaceWithMultiple(statements)) replacement.skip();
} else {
const section = getSection(tag);
const bodySection = getSectionForBody(tag.get("body"));
const signal = getSignal(section, nodeBinding, "dynamicTag");
let tagVarSignal;
if (tag.node.var && isTagVarResumed(tag)) {
const varBinding = tag.node.var.extra.binding;
tagVarSignal = initValue(varBinding);
tagVarSignal.register = true;
tagVarSignal.referenced = true;
tagVarSignal.buildAssignment = (valueSection, value) => buildVarChange(_marko_compiler.types.memberExpression(getScopeExpression(tagVarSignal.section, valueSection), _marko_compiler.types.stringLiteral(getAccessorPrefix().BranchScopes + getScopeAccessor(nodeBinding)), true), value, varBinding);
}
signal.build = () => {
return callRuntime("_dynamic_tag", getScopeAccessorLiteral(nodeBinding, true), bodySection && getSectionRendererIdentifier(bodySection), tagVarSignal ? _marko_compiler.types.arrowFunctionExpression([], tagVarSignal.identifier) : void 0, hasTagArgs && _marko_compiler.types.numericLiteral(1));
};
const directBinding = getReferencedBindings(tagExtra);
const directName = directBinding && !Array.isArray(directBinding) && (0, _marko_compiler_babel_utils.getProgram)().node.extra.exportNames.directContent.get(directBinding);
if (directName) (0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.exportNamedDeclaration(_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(_marko_compiler.types.identifier(directName), callRuntime("_dynamic_tag_content", getScopeAccessorLiteral(nodeBinding, true)))])));
if (args.length) {
const argsOrInput = hasTagArgs ? _marko_compiler.types.arrayExpression(args) : args[0];
if (!_marko_compiler.types.isObjectExpression(argsOrInput) || argsOrInput.properties.length) signal.extraArgs = [_marko_compiler.types.arrowFunctionExpression([], statements.length ? _marko_compiler.types.blockStatement(statements.concat(_marko_compiler.types.returnStatement(argsOrInput))) : argsOrInput)];
}
enableDynamicTagVar(tag);
if (!isClassAPI) {
if (mayHaveNativeAttr(tag, isEventOrChangeHandler)) importRuntimeFeature("dynamic-tag-script");
if (mayHaveNativeAttr(tag, isControllableAttr)) importRuntimeFeature("controllable");
}
addValue(section, getReferencedBindings(tagExtra), signal, tagExpression);
tag.remove();
}
}
}
};
function enableDynamicTagVar(tag) {
if (!tag.node.var || !isTagVarResumed(tag)) return;
importRuntimeFeature("dynamic-tag-var");
if (tag.node.extra.tagNameType !== 1 && !tag.node.var.extra.binding.pruned) {
const accessor = getScopeAccessorLiteral(tag.node.extra.nodeBinding, true);
pushStatementOnce(`_dynamic_tag_var_resume ${accessor.value}`, _marko_compiler.types.expressionStatement(callRuntime("_dynamic_tag_var_resume", accessor)));
}
}
function mayHaveNativeAttr(tag, test) {
if (tag.node.extra.tagNameType === 1) return false;
for (const attr of tag.node.attributes) if (attr.type === "MarkoSpreadAttribute" || attr.type === "MarkoAttribute" && test(attr.name)) return true;
return false;
}
function getDynamicTagInputBindings(tagExtra) {
let inputBindings;
for (const childExtra of tagExtra.tagNameTemplates || []) {
if (childExtra.featureType === "class") return;
const inputBinding = childExtra.paramsTree?.props?.[0]?.binding;
if (inputBinding) inputBindings = concat(inputBindings, inputBinding);
}
return inputBindings;
}
function isTagVarResumed(tag) {
return !tag.node.var.extra.binding.pruned || isTagVarAssigned(tag);
}
//#endregion
//#region src/translator/visitors/tag/native-tag.ts
const kNodeOp = Symbol("native tag structure node");
const kNativeAttrs = Symbol("native tag attrs");
const htmlContentAttrTags = /* @__PURE__ */ new WeakSet();
const htmlSelectArgs = /* @__PURE__ */ new WeakMap();
var native_tag_default = {
analyze: {
enter(tag) {
(0, _marko_compiler_babel_utils.assertNoArgs)(tag);
(0, _marko_compiler_babel_utils.assertNoParams)(tag);
(0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
const { node: node$1 } = tag;
if (node$1.var && !_marko_compiler.types.isIdentifier(node$1.var)) throw tag.get("var").buildCodeFrameError("Tag variables on [native tags](https://markojs.com/docs/reference/native-tag) cannot be destructured.");
const tagName = getCanonicalTagName(tag);
const tagFacts = getTagFacts(tag);
if (tagFacts.pageElement) (0, _marko_compiler_babel_utils.getProgram)().node.extra.page ??= true;
if (tagName === "option") assertOptionInSelectWithValue(tag);
const isTextOnly = tagFacts.textBody;
const { attributes } = tag.node;
const tagSection = ensureSection(tag);
const indexByName = Object.create(null);
const delimitedAttrMetas = {};
const controllableAttrNames = controllableElements.get(tagName)?.attrs;
let own;
let handlers;
let content;
let controllable;
let spread;
let hasDynamicAttributes = false;
let hasEventHandlers = false;
for (let i = attributes.length; i--;) {
const attr = attributes[i];
if (_marko_compiler.types.isMarkoSpreadAttribute(attr)) {
const valueExtra = attr.value.extra ??= {};
valueExtra.isEffect = true;
valueExtra.retained = true;
hasEventHandlers = true;
hasDynamicAttributes = true;
if (!spread) {
spread = [];
controllable = getRelatedControllable(tagName, attributes, indexByName);
own = addOwnControllableAttrs(own, controllableAttrNames, indexByName, controllable);
if (controllable && !controllable.attrs.every(isDefined)) {
for (const index of controllable.attrs) if (index !== void 0) spread.push(index);
controllable = void 0;
}
}
spread.push(i);
} else if (indexByName[attr.name] !== void 0 || attr.name === "content" && tag.node.body.body.length) {
(0, _marko_compiler_babel_utils.diagnosticWarn)(tag, {
label: indexByName[attr.name] === void 0 ? `The \`content\` attribute on \`<${tagName}>\` is ignored; its body is rendered instead.` : `The \`${attr.name}\` attribute is set more than once on \`<${tagName}>\`; only the last value is used.`,
loc: attr.loc ?? void 0
});
dropNodes(attr.value);
} else {
const valueExtra = attr.value.extra ??= {};
const isEventHandlerAttr = isEventHandler(attr.name);
const isChangeHandlerAttr = !isEventHandlerAttr && isEventOrChangeHandler(attr.name);
indexByName[attr.name] = i;
assertValidNativeAttrName(tag, attr);
if (isEventHandlerAttr || isChangeHandlerAttr) assertNativeHandlerAttr(tag, attr);
assertNativeAttrValueType(tag, attr);
if (attr.name === "style") warnCamelCaseStyleKeys(tag, attr);
let delimitedAttrMeta;
if (attr.name === "class" || attr.name === "style") {
delimitedAttrMeta = delimitedAttrMetas[attr.name] = getDelimitedAttrMeta(tag, attr.name, attr.value);
if (attr.name === "class") assertUniqueClassToggles(tag, attr, delimitedAttrMeta);
}
if (isEventHandlerAttr) {
valueExtra.isEffect = true;
valueExtra.consumed = true;
valueExtra.invokeOnly = true;
hasEventHandlers = true;
addSetupExpr(tagSection, attr.value);
} else {
if (isChangeHandlerAttr) valueExtra.retained = true;
if (isDynamicAttr(attr.value, delimitedAttrMeta)) {
hasDynamicAttributes = true;
addSetupExpr(tagSection, attr.value);
} else if (attr.name === "content" && tagName !== "meta") addSetupExpr(tagSection, attr.value);
}
if (spread) spread.push(i);
else if (attr.name === "content" && tagName !== "meta") content = i;
else if (isEventHandlerAttr) (handlers ||= []).push(i);
else if (!controllableAttrNames?.includes(attr.name)) (own ||= []).push(i);
}
}
own?.reverse();
if (!spread) {
controllable = getRelatedControllable(tagName, attributes, indexByName);
if (controllable && controllable.stateIsAttr && controllable.attrs[1] === void 0 && evaluate(attributes[controllable.attrs.find(isDefined)].value).confident) controllable = void 0;
own = addOwnControllableAttrs(own, controllableAttrNames, indexByName, controllable);
}
if (controllable?.attrs[1] !== void 0) hasEventHandlers = true;
assertExclusiveAttrs(indexByName, (msg) => {
throw tag.get("name").buildCodeFrameError(msg);
}, isDefined);
const contentAttr = attrAt(attributes, indexByName.content);
if (contentAttr) {
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
if (tagDef?.parseOptions?.openTagOnly && !tagDef.attributes?.content) throw tag.hub.buildError(contentAttr, `The \`<${tagName}>\` tag cannot have content, so it does not support the \`content\` attribute.`);
if (isTextOnly) throw tag.hub.buildError(contentAttr, `The \`<${tagName}>\` tag takes its content from its body as text, so it does not support the \`content\` attribute.`);
}
const valueChangeAttr = tagName === "input" ? attrAt(attributes, indexByName.valueChange) : void 0;
const valueChangeEval = valueChangeAttr && evaluate(valueChangeAttr.value);
const typeAttr = attrAt(attributes, indexByName.type);
if (valueChangeEval && !(valueChangeEval.confident && valueChangeEval.computed == null) && getInputValueMode(typeAttr) === "attribute") {
const type = evaluate(typeAttr.value).computed;
throw tag.hub.buildError(valueChangeAttr, `\`valueChange\` cannot be used on a \`type="${type}"\` \`<input>\` — user interaction can never change its \`value\`.` + (/^[cr]/i.test(type) ? " Bind `checked` or `checkedValue` instead." : ""));
}
handlers?.reverse();
spread?.reverse();
const injectsNonce = (tagName === "script" || tagName === "style") && indexByName.nonce === void 0;
const tagExtra = node$1.extra ??= {};
let textPlaceholders;
if (isTextOnly) {
for (const child of tag.node.body.body) if (_marko_compiler.types.isMarkoPlaceholder(child)) (textPlaceholders ||= []).push(child.value);
else if (!_marko_compiler.types.isMarkoText(child)) throw tag.hub.buildError(child, `Only text is allowed inside a \`<${tagName}>\`.`);
}
if (node$1.var && isTagVarUsed(tag) || hasDynamicAttributes || hasEventHandlers || textPlaceholders || injectsNonce || content !== void 0 || controllable) {
const nodeBinding = tagExtra.nodeBinding = createBinding("#" + tagName.toLowerCase(), 0, tagSection, void 0, void 0, void 0, void 0, !!node$1.var);
if (hasEventHandlers) (0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
if (spread) {
const spreadExtra = mergeReferences(tagSection, tag.node, spread.map((index) => attributes[index].value));
spreadExtra.rendersContent = true;
spreadExtra.invokeOnly = true;
}
let exprExtras;
if (controllable) exprExtras = mergeReferenceGroup(tagSection, controllable.attrs.map((index) => index === void 0 ? void 0 : attributes[index].value));
if (own) for (const index of own) exprExtras = push(exprExtras, attributes[index].value.extra);
if (handlers) for (const index of handlers) exprExtras = push(exprExtras, attributes[index].value.extra);
if (content !== void 0) exprExtras = push(exprExtras, attributes[content].value.extra);
if (textPlaceholders) {
exprExtras = push(exprExtras, textPlaceholders.length === 1 ? textPlaceholders[0].extra ??= {} : mergeReferenceGroup(tagSection, textPlaceholders));
addSetupExpr(tagSection, textPlaceholders[0]);
}
if (injectsNonce && !spread) addSetupWork(tagSection);
if (controllable?.attrs[1] !== void 0) addSetupWork(tagSection);
if (hasEventHandlers || isTagVarUsed(tag)) addAlwaysReason(nodeBinding);
trackDomVarReferences(tag, nodeBinding);
addReasonExprs(ensureSlot(nodeBinding), push(exprExtras, tagExtra));
}
const write = writeTo(tag);
tagExtra[kNodeOp] = node(tag);
write`<${tagName}`;
if (own) for (const index of own) {
const { name, value } = attributes[index];
const { confident, computed } = evaluate(value);
if (confident) write`${getStaticAttrMarkup(name, computed)}`;
else if (name === "class" || name === "style") {
const meta = delimitedAttrMetas[name];
const { staticParts } = meta;
if (getDelimitedAttrItems(name, meta) && staticParts.length) {
if (staticParts.every(isLiteralPart)) write`${getStaticAttrMarkup(name, staticParts)}`;
else {
write` class="`;
for (let i = 0; i < staticParts.length; i++) {
const part = staticParts[i];
if (i) write` `;
if (isLiteralPart(part)) write`${escapeDoubleQuotedAttrValue(part)}`;
else writeModuleReadTo(tag, part);
}
write`"`;
}
}
}
}
write`>`;
enter(tag);
tagExtra[kNativeAttrs] = {
own,
handlers,
content,
controllable,
spread,
injectsNonce
};
},
exit(tag) {
const tagName = getCanonicalTagName(tag);
const tagExtra = tag.node.extra;
const nodeOp = tagExtra[kNodeOp];
if (nodeOp) nodeOp.binding = tagExtra.nodeBinding;
if (!(0, _marko_compiler_babel_utils.getTagDef)(tag)?.parseOptions?.openTagOnly) {
const write = writeTo(tag);
if (tagName !== "textarea" && getTagFacts(tag).textBody) {
const textLiteral = bodyToUncoercedText(tag.node.body);
if (_marko_compiler.types.isStringLiteral(textLiteral)) write`${textLiteral.value}`;
}
write`</${tagName}>`;
}
exit(tag);
}
},
translate: translateByTarget({
html: {
enter(tag) {
const tagName = getCanonicalTagName(tag);
const tagExtra = tag.node.extra;
const nodeBinding = tagExtra.nodeBinding;
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
const write = writeTo$1(tag);
const tagSection = getSection(tag);
const nodeAccessor = nodeBinding && getScopeAccessorLiteral(nodeBinding);
const { attributes } = tag.node;
const nativeAttrs = tagExtra[kNativeAttrs];
const { own, handlers, content, controllable, spread, injectsNonce } = nativeAttrs;
const contentAttr = attrAt(attributes, content);
const skipExpression = spread && buildSkipExpression(attributes, nativeAttrs);
let spreadExpression = spread && buildSpreadExpression(attributes, spread, injectsNonce);
if (!isOptimize() && nodeBinding) {
const changeAttr = attrAt(attributes, controllable?.attrs[1]);
if (changeAttr) {
const handler = evaluate(changeAttr.value);
if (!(handler.confident && handler.computed == null)) setSectionDebugVar(tagSection, getPrefixedScopeAccessor(nodeBinding, getAccessorPrefix().ControlledHandler), changeAttr.name, changeAttr.loc);
} else if (spreadExpression) {
const spreads = tag.node.attributes.filter((attr) => _marko_compiler.types.isMarkoSpreadAttribute(attr));
const spreadLoc = spreads.length === 1 && spreads[0].value.loc;
if (spreadLoc && spreadLoc.start.index != null) {
const name = "..." + (0, _marko_compiler_babel_utils.getFile)().code.slice(spreadLoc.start.index, spreadLoc.end.index);
for (const prefix of [getAccessorPrefix().ControlledHandler, getAccessorPrefix().EventAttributes]) if (prefix !== getAccessorPrefix().ControlledHandler || controllableElements.has(tagName)) setSectionDebugVar(tagSection, getPrefixedScopeAccessor(nodeBinding, prefix), name, spreadLoc);
}
}
}
if (tagName === "select" && (controllable || spreadExpression)) flushBefore(tag);
write`<${tagName}`;
if (injectsNonce && !spread) write`${callRuntime("_attr_nonce")}`;
if (controllable) {
if (tagName !== "select" && tagName !== "textarea") write`${callRuntime(getControllableHelper(tagName, controllable.state), getScopeIdIdentifier(tagSection), nodeAccessor, ...controllable.attrs.map((index) => attrAt(attributes, index)?.value))}`;
if (controllable.attrs[1] !== void 0) addHTMLEffectCall(tagSection, void 0);
}
let writeAtStartOfBody;
if (tagName === "html" && getMarkoOpts().linkAssets && !tag.node.body.body.some((child) => child.type === "MarkoTag" && child.name.type === "StringLiteral" && child.name.value === "head")) writeAtStartOfBody = callRuntime("_flush_head");
if (tagName === "select") {
if (controllable) htmlSelectArgs.set(tag.node, {
helper: "_attr_select_value",
args: [attrAt(attributes, controllable.attrs[0])?.value || _marko_compiler.types.buildUndefinedNode(), attrAt(attributes, controllable.attrs[1])?.value || _marko_compiler.types.buildUndefinedNode()]
});
else if (spreadExpression) {
const spreadIdentifier = declareConstBefore(tag, "select_input", spreadExpression);
htmlSelectArgs.set(tag.node, {
helper: "_attrs_select_value",
args: [spreadIdentifier]
});
spreadExpression = spreadIdentifier;
}
} else if (tagName === "textarea") {
if (controllable) {
const value = attrAt(attributes, controllable.attrs[0]);
const valueChange = attrAt(attributes, controllable.attrs[1]);
writeAtStartOfBody = valueChange ? callRuntime("_attr_textarea_value", getScopeIdIdentifier(tagSection), nodeAccessor, value?.value, valueChange.value) : callRuntime("_textarea_value", value.value);
} else if (spreadExpression) {
const spreadIdentifier = declareConstBefore(tag, "textarea_input", spreadExpression);
writeAtStartOfBody = callRuntime("_attrs_textarea_value", getScopeIdIdentifier(tagSection), nodeAccessor, spreadIdentifier);
spreadExpression = spreadIdentifier;
}
}
if (own) for (const index of own) {
const { name, value } = attributes[index];
const { confident, computed } = evaluate(value);
if (tagName === "option" && name === "value") {
write`${callRuntime("_attr_option_value", value)}`;
continue;
}
write`${confident ? getStaticAttrMarkup(name, computed) : factorAttrConditional(buildAttrExpression(tag, name, value))}`;
}
if (handlers) for (const index of handlers) addHTMLEffectCall(tagSection, getReferencedBindings(attributes[index].value.extra));
const isOpenOnly = !!(tagDef && tagDef.parseOptions?.openTagOnly);
const isTextOnly = getTagFacts(tag).textBody;
const spreadContent = !!spreadExpression && spreadRendersContent(tag, contentAttr, isTextOnly);
if (spreadExpression) {
addHTMLEffectCall(tagSection, getReferencedBindings(tagExtra));
if (!spreadContent) {
if (skipExpression) write`${callRuntime("_attrs_partial", spreadExpression, skipExpression, nodeAccessor, getScopeIdIdentifier(tagSection), _marko_compiler.types.stringLiteral(tagName))}`;
else write`${callRuntime("_attrs", spreadExpression, nodeAccessor, getScopeIdIdentifier(tagSection), _marko_compiler.types.stringLiteral(tagName))}`;
}
}
if (isOpenOnly || isTextOnly) write`>`;
else if (contentAttr) {
write`>`;
htmlContentAttrTags.add(tag.node);
tag.node.body.body = [_marko_compiler.types.expressionStatement(callRuntime("_attr_content", nodeAccessor, getScopeIdIdentifier(tagSection), contentAttr.value, getWriteGuard(tagSection, nodeBinding && getWriteReason(nodeBinding), true)))];
} else if (spreadContent) {
const markerGuard = getWriteGuard(tagSection, nodeBinding && getWriteReason(nodeBinding), true);
htmlContentAttrTags.add(tag.node);
tag.node.body.body = [skipExpression ? _marko_compiler.types.expressionStatement(callRuntime("_attrs_partial_content", spreadExpression, skipExpression, nodeAccessor, getScopeIdIdentifier(tagSection), _marko_compiler.types.stringLiteral(tagName), markerGuard)) : _marko_compiler.types.expressionStatement(callRuntime("_attrs_content", spreadExpression, nodeAccessor, getScopeIdIdentifier(tagSection), _marko_compiler.types.stringLiteral(tagName), markerGuard))];
} else write`>`;
if (writeAtStartOfBody) write`${writeAtStartOfBody}`;
},
exit(tag) {
const nodeBinding = tag.node.extra.nodeBinding;
const isOpenOnly = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.parseOptions?.openTagOnly;
const isTextOnly = getTagFacts(tag).textBody;
const selectArgs = htmlSelectArgs.get(tag.node);
const tagName = getCanonicalTagName(tag);
const tagSection = getSection(tag);
const skipEndTag = isEndTagWrittenByBranch(nodeBinding);
const markerReason = !skipEndTag && nodeBinding && getWriteReason(nodeBinding);
const write = writeTo$1(tag, tagName === "html" || !markerReason && tagName === "body");
if (htmlContentAttrTags.has(tag.node)) flushBefore(tag);
if (selectArgs) {
if (!skipEndTag) write`</${tagName}>`;
flushInto(tag);
tag.insertBefore(_marko_compiler.types.expressionStatement(callRuntime(selectArgs.helper, getScopeIdIdentifier(tagSection), nodeBinding && getScopeAccessorLiteral(nodeBinding), ...selectArgs.args, _marko_compiler.types.arrowFunctionExpression([], _marko_compiler.types.blockStatement(tag.node.body.body)))));
} else if (isTextOnly) {
const rawTextHelper = getRawTextEscapeHelper(tagName);
if (rawTextHelper) {
const body = bodyToText(tag.node.body);
write`${_marko_compiler.types.isStringLiteral(body) ? content_exports[rawTextHelper](body.value) : callRuntime(rawTextHelper, body)}`;
} else for (const child of tag.node.body.body) if (_marko_compiler.types.isMarkoText(child)) write`${child.value}`;
else if (_marko_compiler.types.isMarkoPlaceholder(child)) write`${callRuntime("_escape", child.value)}`;
} else tag.insertBefore(tag.node.body.body).forEach((child) => child.skip());
if (!skipEndTag && !isOpenOnly && !selectArgs) {
if (tagName === "head" && getMarkoOpts().linkAssets) write`${callRuntime("_flush_head")}`;
write`</${tagName}>`;
}
if (markerReason) markNode(tag, nodeBinding, markerReason, tagName === "html");
tag.remove();
}
},
dom: {
enter(tag) {
const tagExtra = tag.node.extra;
const { nodeBinding } = tagExtra;
if (!nodeBinding) return;
const tagName = getCanonicalTagName(tag);
const tagSection = getSection(tag);
const nodeAccessor = getScopeAccessorLiteral(nodeBinding);
const { attributes } = tag.node;
const nativeAttrs = tagExtra[kNativeAttrs];
const { own, handlers, content, controllable, spread, injectsNonce } = nativeAttrs;
const contentAttr = attrAt(attributes, content);
const skipExpression = spread && buildSkipExpression(attributes, nativeAttrs);
const spreadExpression = spread && buildSpreadExpression(attributes, spread, injectsNonce);
if (injectsNonce && !spread) addStatement("render", tagSection, void 0, callRuntime("_attr_nonce", scopeIdentifier, getScopeAccessorLiteral(nodeBinding)), true);
if (controllable) {
const hasChangeHandler = controllable.attrs[1] !== void 0;
const helper = getControllableHelper(tagName, controllable.state);
const defaultHelper = getDOMControllableDefaultHelper(helper, controllable);
const referencedBindings = getReferencedBindings(attrAt(attributes, controllable.attrs.find(isDefined)).value.extra);
const values = (hasChangeHandler ? controllable.attrs : controllable.attrs.toSpliced(1, 1)).map((index) => attrAt(attributes, index)?.value);
if (hasChangeHandler && defaultHelper !== `${helper}_default`) values.push(importRuntime(defaultHelper));
addStatement("render", tagSection, referencedBindings, callRuntime(hasChangeHandler ? helper : defaultHelper, scopeIdentifier, nodeAccessor, ...values));
if (hasChangeHandler) addStatement("effect", tagSection, void 0, callRuntime(`${helper}_script`, scopeIdentifier, nodeAccessor));
}
if (own) for (const index of own) {
const { name, value } = attributes[index];
const { confident } = evaluate(value);
const valueReferences = getReferencedBindings(value.extra);
switch (name) {
case "class":
case "style":
if (!confident) {
const meta = getDelimitedAttrMeta(tag, name, value);
const items = getDelimitedAttrItems(name, meta);
const calls = [];
const assert = buildClassTogglesAssert(meta);
if (assert) calls.push(assert);
if (!items) calls.push(callRuntime(`_attr_${name}`, createScopeReadExpression(nodeBinding), value));
else {
const single = [];
for (const { key, value } of items) if (isLiteralPart(key) && !/\s/.test(key)) single.push({
key,
value
});
else calls.push(callRuntime("_attr_class_names", createScopeReadExpression(nodeBinding), toClassPartExpression(key), value));
if (single.length === 1) calls.push(callRuntime(`_attr_${name}_item`, createScopeReadExpression(nodeBinding), _marko_compiler.types.stringLiteral(single[0].key), single[0].value));
else if (single.length) calls.push(callRuntime(`_attr_${name}_items`, createScopeReadExpression(nodeBinding), _marko_compiler.types.objectExpression(single.map(({ key, value }) => _marko_compiler.types.objectProperty(toPropertyName(key), value)))));
}
for (const call of calls) addStatement("render", tagSection, valueReferences, call, true);
}
break;
default: if (confident) break;
else addStatement("render", tagSection, valueReferences, callRuntime("_attr", createScopeReadExpression(nodeBinding), _marko_compiler.types.stringLiteral(name), value), true);
}
}
if (handlers) for (const index of handlers) {
const { name, value } = attributes[index];
addStatement("effect", tagSection, getReferencedBindings(value.extra), callRuntime("_on", createScopeReadExpression(nodeBinding), _marko_compiler.types.stringLiteral(getEventType(name)), value));
}
if (spreadExpression) {
const spreadContent = spreadRendersContent(tag, contentAttr, getTagFacts(tag).textBody);
const name = tag.get("name");
const staticName = name.isStringLiteral() ? name.node.value : void 0;
const element = staticName === void 0 ? void 0 : controllableElements.get(staticName);
const spreadHelper = !controllable && element?.spreadHelper;
if (skipExpression) addStatement("render", tagSection, getReferencedBindings(tagExtra), callRuntime(spreadContent ? "_attrs_partial_content" : "_attrs_partial", scopeIdentifier, nodeAccessor, spreadExpression, skipExpression, spreadHelper && importRuntime(spreadHelper)));
else addStatement("render", tagSection, getReferencedBindings(tagExtra), callRuntime(spreadContent ? "_attrs_content" : "_attrs", scopeIdentifier, nodeAccessor, spreadExpression, spreadHelper && importRuntime(spreadHelper)));
if (staticName === void 0) importRuntimeFeature("controllable");
else if (element) importRuntimeFeature(element.feature);
addStatement("effect", tagSection, getReferencedBindings(tagExtra), callRuntime("_attrs_script", scopeIdentifier, nodeAccessor));
}
if (contentAttr) addStatement("render", tagSection, getReferencedBindings(contentAttr.value.extra), callRuntime("_attr_content", scopeIdentifier, nodeAccessor, contentAttr.value), true);
},
exit(tag) {
const nodeBinding = tag.node.extra.nodeBinding;
const openTagOnly = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.parseOptions?.openTagOnly;
const tagName = getCanonicalTagName(tag);
if (!openTagOnly) {
if (tagName !== "textarea" && getTagFacts(tag).textBody) {
const textLiteral = bodyToText(tag.node.body, tagName === "title");
if (!_marko_compiler.types.isStringLiteral(textLiteral)) addStatement("render", getSection(tag), getReferencedBindings(textLiteral.extra), callRuntime("_text_content", createScopeReadExpression(nodeBinding), textLiteral), true);
} else tag.insertBefore(tag.node.body.body).forEach((child) => child.skip());
}
tag.remove();
}
}
})
};
function getRelatedControllable(tagName, attributes, indexByName) {
switch (tagName) {
case "input":
if ("checked" in indexByName || "checkedChange" in indexByName) return {
state: "checked",
stateIsAttr: true,
attrs: [indexByName.checked, indexByName.checkedChange]
};
if ("checkedValue" in indexByName || "checkedValueChange" in indexByName) return {
state: "checkedValue",
stateIsAttr: false,
attrs: [
indexByName.checkedValue,
indexByName.checkedValueChange,
indexByName.value
]
};
if ("value" in indexByName || "valueChange" in indexByName) {
const valueMode = getInputValueMode(attrAt(attributes, indexByName.type));
if (valueMode === "attribute" && !indexByName.valueChange) break;
return {
state: "value",
stateIsAttr: true,
attrs: [indexByName.value, indexByName.valueChange],
valueMode
};
}
break;
case "select":
case "textarea":
if ("value" in indexByName || "valueChange" in indexByName) return {
state: "value",
stateIsAttr: false,
attrs: [indexByName.value, indexByName.valueChange]
};
break;
case "details":
case "dialog": if ("open" in indexByName || "openChange" in indexByName) return {
state: "open",
stateIsAttr: true,
attrs: [indexByName.open, indexByName.openChange]
};
}
}
function addOwnControllableAttrs(own, controllableAttrNames, indexByName, controllable) {
if (controllableAttrNames) for (const name of controllableAttrNames) {
const index = indexByName[name];
if (index !== void 0 && !controllable?.attrs.includes(index)) (own ||= []).push(index);
}
return own;
}
function attrAt(attributes, index) {
return index === void 0 ? void 0 : attributes[index];
}
function isDefined(value) {
return value !== void 0;
}
function getInputValueMode(typeAttr) {
if (!typeAttr) return;
const type = evaluate(typeAttr.value);
if (!type.confident) return "dynamic";
if (typeof type.computed === "string") switch (type.computed.toLowerCase()) {
case "button":
case "checkbox":
case "hidden":
case "image":
case "radio":
case "reset":
case "submit": return "attribute";
}
}
function getDOMControllableDefaultHelper(helper, { valueMode }) {
return helper === "_attr_input_value" && valueMode ? `_attr_input_value_${valueMode}_default` : `${helper}_default`;
}
function spreadRendersContent(tag, staticContentAttr, isTextOnly) {
return !(staticContentAttr || tag.node.body.body.length || isTextOnly || (0, _marko_compiler_babel_utils.getTagDef)(tag)?.parseOptions?.openTagOnly);
}
function buildSpreadExpression(attributes, spread, injectsNonce) {
const props = [];
if (injectsNonce) props.push(_marko_compiler.types.objectProperty(_marko_compiler.types.identifier("nonce"), _marko_compiler.types.memberExpression(isOutputHTML() ? callRuntime("$global") : toMemberExpression(scopeIdentifier, getAccessorProp().Global), _marko_compiler.types.identifier("cspNonce"))));
for (const index of spread) {
const attr = attributes[index];
props.push(_marko_compiler.types.isMarkoSpreadAttribute(attr) ? _marko_compiler.types.spreadElement(attr.value) : toObjectProperty(attr.name, attr.value));
}
return propsToExpression(props);
}
function buildSkipExpression(attributes, { own, handlers, controllable }) {
const skipProps = /* @__PURE__ */ new Set();
if (controllable) {
for (const index of controllable.attrs) if (index !== void 0) skipProps.add(attributes[index].name);
}
if (own) for (const index of own) skipProps.add(attributes[index].name);
if (handlers) for (const index of handlers) {
const { name } = attributes[index];
skipProps.add(`on-${getEventType(name)}`);
}
if (skipProps.size) return _marko_compiler.types.objectExpression(Array.from(skipProps, toSkipProperty));
}
function toSkipProperty(name) {
return toObjectProperty(name, _marko_compiler.types.numericLiteral(1));
}
function getControllableHelper(tagName, state) {
switch (state) {
case "checked": return "_attr_input_checked";
case "checkedValue": return "_attr_input_checkedValue";
case "open": return tagName === "details" ? "_attr_details_open" : "_attr_dialog_open";
case "value": return tagName === "select" ? "_attr_select_value" : tagName === "textarea" ? "_attr_textarea_value" : "_attr_input_value";
}
}
function assertValidNativeAttrName(tag, attr) {
const suggestion = getWrongAttrSuggestion(attr.name);
if (suggestion) throw buildAttrNameError(tag, attr, `\`${attr.name}\` is not a valid attribute, did you mean \`${suggestion}\`?`);
}
function assertNativeAttrValueType(tag, attr) {
const { name } = attr;
if (lowercaseOnAttrReg.test(name)) {
const { value } = attr;
let invalid = _marko_compiler.types.isFunction(value);
if (!invalid) {
const { confident, computed } = evaluate(value);
invalid = confident && !!computed && typeof computed !== "string";
}
if (invalid) {
const suggestion = "on" + name[2].toUpperCase() + name.slice(3);
throw tag.hub.buildError(value, `The \`${name}\` attribute on a [native tag](https://markojs.com/docs/reference/native-tag) must be a string or a falsey value (\`null\`, \`undefined\`, \`false\`, \`0\`, …). To attach an event listener, use the \`${suggestion}\` [event handler attribute](https://markojs.com/docs/reference/event-handling) instead.`, Error);
}
return;
}
if (name === "class" || name === "style" || name === "content" || isEventOrChangeHandler(name)) return;
if (_marko_compiler.types.isFunction(attr.value)) throw tag.hub.buildError(attr, `The \`${name}\` attribute cannot be a function.`, Error);
if (_marko_compiler.types.isObjectExpression(attr.value)) throw tag.hub.buildError(attr, `The \`${name}\` attribute cannot be a plain object (it would render as \`[object Object]\`).`, Error);
}
function warnCamelCaseStyleKeys(tag, attr) {
const { value } = attr;
const objects = value.type === "ObjectExpression" ? [value] : value.type === "ArrayExpression" ? value.elements.filter((el) => el?.type === "ObjectExpression") : [];
for (const object of objects) for (const prop of object.properties) {
if (prop.type !== "ObjectProperty" || prop.computed) continue;
const { key } = prop;
const name = getLiteralName(key);
if (name && !name.startsWith("--") && !name.includes("-") && /[A-Z]/.test(name)) {
const kebab = name.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()).replace(/^ms-/, "-ms-");
(0, _marko_compiler_babel_utils.diagnosticWarn)(tag, {
label: `\`${name}\` is not a CSS property name; the [\`style=\` object](https://markojs.com/docs/reference/native-tag#style) writes keys out verbatim (unlike the camelCased DOM style API), so this renders as invalid CSS the browser ignores. Use the kebab-case name \`${kebab}\`.`,
loc: key.loc ?? void 0
});
}
}
}
function assertNativeHandlerAttr(tag, attr) {
if (_marko_compiler.types.isObjectExpression(attr.value)) throw tag.hub.buildError(attr.value, `The \`${attr.name}\` ${isEventHandler(attr.name) ? "event handler" : "change handler"} on a [native tag](https://markojs.com/docs/reference/native-tag) must be a function. Attribute values in Marko are plain JavaScript expressions, not JSX; remove the wrapping \`{ }\` (e.g. \`${attr.name}=myHandler\` or \`${attr.name}() { ... }\`).`, Error);
if ((0, _marko_compiler_babel_utils.computeNode)(attr.value)?.value) throw tag.hub.buildError(attr.value, `The \`${attr.name}\` ${isEventHandler(attr.name) ? "event handler" : "change handler"} on a [native tag](https://markojs.com/docs/reference/native-tag) must be a function or a falsey value (\`null\`, \`undefined\`, \`false\`, \`0\`, …).`, Error);
}
function getCanonicalTagName(tag) {
const tagName = getTagName(tag);
switch (tagName) {
case "html-script": return "script";
case "html-style": return "style";
default: return tagName;
}
}
function assertOptionInSelectWithValue(tag) {
let parent = tag.parentPath;
while (parent) {
if (parent.isMarkoTag()) {
if (analyzeTagNameType(parent) === 0) {
const parentName = getCanonicalTagName(parent);
if (parentName === "select") {
if (parent.node.attributes.some((attr) => _marko_compiler.types.isMarkoAttribute(attr) && (attr.name === "value" || attr.name === "valueChange"))) {
let hasValue = false;
const attributes = tag.get("attributes");
for (let i = 0; i < attributes.length; i++) {
const attr = attributes[i].node;
if (!_marko_compiler.types.isMarkoAttribute(attr) || attr.name === "value") hasValue = true;
else if (attr.name === "selected") throw attributes[i].buildCodeFrameError("The `selected` attribute is not supported on an `<option>` within a `<select>` that has a `value` attribute; include the option's `value` in the select's `value` instead.");
}
if (!hasValue) throw tag.buildCodeFrameError("An `<option>` within a `<select>` that has a `value` attribute must also have a `value` attribute.");
}
return;
}
if (parentName !== "optgroup") return;
} else if (!getTagFacts(parent).controlFlow) return;
} else if (parent.isProgram()) return;
parent = parent.parentPath;
}
}
function getRawTextEscapeHelper(tagName) {
switch (tagName) {
case "script": return "_escape_script";
case "style": return "_escape_style";
}
}
function getStaticAttrMarkup(name, computed) {
switch (name) {
case "class": return _attr_class(computed);
case "style": return _attr_style(computed);
default: return _attr(name, computed);
}
}
function buildAttrExpression(tag, name, value) {
if (value.type === "ConditionalExpression") return _marko_compiler.types.conditionalExpression(value.test, buildAttrExpression(tag, name, value.consequent), buildAttrExpression(tag, name, value.alternate));
const { confident, computed } = evaluate(value);
if (confident) return _marko_compiler.types.stringLiteral(getStaticAttrMarkup(name, computed));
switch (name) {
case "class": return buildClassAttrExpression(tag, value) || callRuntime("_attr_class", value);
case "style": return buildStyleAttrAnd(value) || callRuntime("_attr_style", value);
default: return buildLogicalAttr(name, value) || callRuntime("_attr", _marko_compiler.types.stringLiteral(name), value);
}
}
function factorAttrConditional(value) {
if (value.type !== "ConditionalExpression") return value;
const consequent = factorAttrConditional(value.consequent);
const alternate = factorAttrConditional(value.alternate);
if (consequent.type === "StringLiteral" && alternate.type === "StringLiteral") {
const a = consequent.value;
const b = alternate.value;
const end = commonAttrPrefixEnd([a, b]);
if (end) return buildStringExpression([a.slice(0, end), _marko_compiler.types.conditionalExpression(value.test, _marko_compiler.types.stringLiteral(a.slice(end)), _marko_compiler.types.stringLiteral(b.slice(end)))]);
}
return _marko_compiler.types.conditionalExpression(value.test, consequent, alternate);
}
function commonAttrPrefixEnd(strings) {
let prefix = strings[0];
for (let i = 1; i < strings.length && prefix; i++) {
const s = strings[i];
const len = Math.min(prefix.length, s.length);
let j = 0;
while (j < len && prefix[j] === s[j]) j++;
prefix = prefix.slice(0, j);
}
return prefix.lastIndexOf("=") + 1;
}
function buildLogicalAttr(name, value) {
if (value.type !== "LogicalExpression") return;
const { confident, computed } = evaluate(value.right);
if (!confident) return;
const attr = _attr(name, computed);
return callRuntime(value.operator === "&&" ? "_attr_and" : value.operator === "||" ? "_attr_or" : "_attr_nullish", _marko_compiler.types.stringLiteral(name), value.left, _marko_compiler.types.stringLiteral(attr));
}
function buildStyleAttrAnd(value) {
if (value.type === "LogicalExpression" && value.operator === "&&") {
const { confident, computed } = evaluate(value.right);
if (confident) return _marko_compiler.types.conditionalExpression(value.left, _marko_compiler.types.stringLiteral(getStaticAttrMarkup("style", computed)), _marko_compiler.types.stringLiteral(""));
}
}
const MAX_PRECOMPUTED_CLASS_TOGGLES = 4;
function buildClassAttrExpression(tag, value) {
const meta = getDelimitedAttrMeta(tag, "class", value);
if (meta.needsWholeValue) return;
const markup = buildClassMarkup(meta);
const assert = markup && buildClassTogglesAssert(meta);
return assert ? _marko_compiler.types.sequenceExpression([assert, markup]) : markup;
}
function buildClassMarkup({ staticParts, toggles = [] }) {
if (toggles.length > MAX_PRECOMPUTED_CLASS_TOGGLES) {
if (staticParts.length) return callRuntime("_attr_class", buildClassString(staticParts, toggles));
return;
}
const combos = [];
for (let mask = 0; mask < 1 << toggles.length; mask++) {
const parts = [...staticParts];
for (let i = 0; i < toggles.length; i++) {
const { key, alternate } = toggles[i];
const part = mask & 1 << i ? key : alternate;
if (part) parts.push(part);
}
combos.push(parts);
}
if (combos.every((parts) => parts.every(isLiteralPart))) return buildPrecomputedClass(combos.map((parts) => _attr_class(parts.join(" "))), toggles);
const table = ensureModuleClassMarkup(combos);
return toggles.length ? _marko_compiler.types.memberExpression(table, buildToggleIndex(toggles), true) : table;
}
function buildPrecomputedClass(combos, toggles) {
if (!toggles.length) return _marko_compiler.types.stringLiteral(combos[0]);
if (toggles.length === 1) return _marko_compiler.types.conditionalExpression(toggles[0].value, _marko_compiler.types.stringLiteral(combos[1]), _marko_compiler.types.stringLiteral(combos[0]));
const end = commonAttrPrefixEnd(combos);
const table = generateUidIdentifier("class");
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.markoScriptlet([_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(table, _marko_compiler.types.arrayExpression(combos.map((combo) => _marko_compiler.types.stringLiteral(combo.slice(end)))))])], true));
const lookup = _marko_compiler.types.memberExpression(_marko_compiler.types.cloneNode(table), buildToggleIndex(toggles), true);
return buildStringExpression([combos[0].slice(0, end), lookup]);
}
const [getModuleClassMarkups] = createProgramState(() => /* @__PURE__ */ new Map());
function ensureModuleClassMarkup(combos) {
const key = JSON.stringify(combos);
const moduleClassMarkups = getModuleClassMarkups();
let id = moduleClassMarkups.get(key);
if (!id) {
const markups = combos.map((parts) => parts.length ? callRuntime("_attr_class", buildClassString(parts, [])) : _marko_compiler.types.stringLiteral(""));
moduleClassMarkups.set(key, id = generateUidIdentifier("class"));
(0, _marko_compiler_babel_utils.getProgram)().node.body.push(_marko_compiler.types.markoScriptlet([_marko_compiler.types.variableDeclaration("const", [_marko_compiler.types.variableDeclarator(id, markups.length === 1 ? markups[0] : _marko_compiler.types.arrayExpression(markups))])], true));
}
return _marko_compiler.types.cloneNode(id);
}
function buildClassTogglesAssert({ staticParts, toggles }) {
if (isOptimize() || !toggles || [...staticParts, ...toggles.flatMap(({ key, alternate }) => [key, alternate])].every((part) => part === void 0 || isLiteralPart(part))) return;
return callRuntime("_assert_class_toggles", buildClassString(staticParts, []), _marko_compiler.types.arrayExpression(toggles.map(({ key, alternate }) => buildClassString(alternate ? [key, alternate] : [key], []))));
}
function buildToggleIndex(toggles) {
let index = _marko_compiler.types.conditionalExpression(toggles[0].value, _marko_compiler.types.numericLiteral(1), _marko_compiler.types.numericLiteral(0));
for (let i = 1; i < toggles.length; i++) index = _marko_compiler.types.binaryExpression("+", index, _marko_compiler.types.conditionalExpression(toggles[i].value, _marko_compiler.types.numericLiteral(1 << i), _marko_compiler.types.numericLiteral(0)));
return index;
}
function buildClassString(parts, toggles) {
const strs = [];
for (let i = 0; i < parts.length; i++) {
if (i) strs.push(" ");
strs.push(toClassPartExpression(parts[i]));
}
for (const { key, value, alternate } of toggles) strs.push(_marko_compiler.types.conditionalExpression(value, toSpacedClassPart(key), toSpacedClassPart(alternate)));
return buildStringExpression(strs) || _marko_compiler.types.stringLiteral("");
}
function toClassPartExpression(part) {
return isLiteralPart(part) ? _marko_compiler.types.stringLiteral(part) : toModuleReadExpression(part);
}
function toSpacedClassPart(part) {
return part === void 0 ? _marko_compiler.types.stringLiteral("") : isLiteralPart(part) ? _marko_compiler.types.stringLiteral(" " + part) : _marko_compiler.types.binaryExpression("+", _marko_compiler.types.stringLiteral(" "), toModuleReadExpression(part));
}
const delimitedAttrStringify = {
class: [" ", stringifyClassEntry],
style: [";", stringifyStyleEntry]
};
function assertUniqueClassToggles(tag, attr, { staticParts, toggles = [] }) {
const written = new Set(staticParts.flatMap(getClassNames));
for (const { key, alternate } of toggles) {
const names = /* @__PURE__ */ new Set([...getClassNames(key), ...getClassNames(alternate)]);
for (const name of names) if (written.has(name)) throw tag.hub.buildError(attr, `The toggled class \`${name}\` is also written by another part of the \`class\` value; a toggled [class name](https://markojs.com/docs/reference/native-tag#class) may appear only once.`, Error);
for (const name of names) written.add(name);
}
}
function getClassNames(part) {
return part === void 0 ? [] : isLiteralPart(part) ? part.split(/\s+/).filter(Boolean) : [part.join(".")];
}
function isDynamicAttr(value, delimitedAttrMeta) {
return (!delimitedAttrMeta || delimitedAttrMeta.needsWholeValue || !!delimitedAttrMeta.toggles) && !evaluate(value).confident;
}
function getDelimitedAttrItems(name, { needsWholeValue, toggles }) {
if (needsWholeValue) return;
const items = [];
if (!toggles) return items;
const keys = /* @__PURE__ */ new Set();
for (const { key, value, alternate } of toggles) {
if (alternate !== void 0 || name === "style" && (!isLiteralPart(key) || /\s/.test(key) || keys.size === keys.add(key).size)) return;
items.push({
key,
value
});
}
return items;
}
function isLiteralPart(part) {
return typeof part === "string";
}
function getDelimitedAttrMeta(tag, name, value) {
const meta = {
needsWholeValue: false,
staticParts: [],
toggles: void 0
};
addDelimitedAttrItem(tag, name, value, meta);
return meta;
}
function addDelimitedAttrItem(tag, name, item, meta) {
switch (item.type) {
case "ArrayExpression":
for (const child of item.elements) if (child) addDelimitedAttrItem(tag, name, child, meta);
return;
case "SpreadElement":
if (item.argument.type === "ArrayExpression") addDelimitedAttrItem(tag, name, item.argument, meta);
else meta.needsWholeValue = true;
return;
case "ObjectExpression":
addDelimitedAttrObject(tag, name, item, meta);
return;
}
const part = getDelimitedAttrPart(tag, name, item);
if (part !== void 0) {
if (part) meta.staticParts.push(part);
} else if (name === "class" && item.type === "LogicalExpression") {
const key = item.operator === "&&" && getDelimitedAttrPart(tag, name, item.right);
if (key) addToggle(meta, key, item.left, void 0);
else meta.needsWholeValue = true;
} else if (name === "class" && item.type === "ConditionalExpression") {
const key = getDelimitedAttrPart(tag, name, item.consequent);
const alternate = getDelimitedAttrPart(tag, name, item.alternate);
if (key && alternate !== void 0) addToggle(meta, key, item.test, alternate || void 0);
else meta.needsWholeValue = true;
} else meta.needsWholeValue = true;
}
function addDelimitedAttrObject(tag, name, obj, meta) {
for (const prop of obj.properties) {
const key = prop.type === "ObjectProperty" ? getDelimitedAttrKey(tag, name, prop) : void 0;
if (!key || prop.type !== "ObjectProperty") {
meta.needsWholeValue = true;
return;
}
const value = prop.value;
const { confident, computed } = evaluate(value);
if (!confident) addToggle(meta, key, value, void 0);
else if (!isLiteralPart(key)) {
if (computed) meta.staticParts.push(key);
} else {
const part = delimitedAttrStringify[name][1](key, computed);
if (part) meta.staticParts.push(part);
}
}
}
function getDelimitedAttrKey(tag, name, prop) {
if (!prop.computed && prop.key.type === "Identifier") return prop.key.name;
const key = prop.key;
const { confident, computed } = evaluate(key);
if (confident) return typeof computed === "string" || typeof computed === "number" ? computed + "" : void 0;
if (name === "class") return getStyleImportRead(tag, key);
}
function getDelimitedAttrPart(tag, name, value) {
const { confident, computed } = evaluate(value);
if (confident) {
const [delimiter, stringify] = delimitedAttrStringify[name];
return toDelimitedString(computed, delimiter, stringify);
}
if (name === "class") return getStyleImportRead(tag, value);
}
function addToggle(meta, key, value, alternate) {
(meta.toggles ||= []).push({
key,
value,
alternate
});
}
//#endregion
//#region src/translator/visitors/tag/index.ts
const kAnalyzeFailed = Symbol("analyze failed");
var tag_default = {
analyze: {
enter(tag) {
try {
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
const type = analyzeTagNameType(tag);
const hook = tagDef?.analyzer?.hook;
if (hook) {
enterHook(hook, tag);
return;
}
if (type === 0) {
native_tag_default.analyze.enter(tag);
return;
}
switch (type) {
case 1:
custom_tag_default.analyze.enter(tag);
break;
case 3:
attribute_tag_default.analyze.enter(tag);
break;
case 2: dynamic_tag_default.analyze.enter(tag);
}
} catch (err) {
(tag.node.extra ??= {})[kAnalyzeFailed] = true;
reportAnalyzeError(tag, err);
tag.skip();
}
},
exit(tag) {
if (tag.node.extra?.[kAnalyzeFailed]) return;
try {
const hook = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.analyzer?.hook;
if (hook) {
exitHook(hook, tag);
return;
}
if (analyzeTagNameType(tag) === 0) native_tag_default.analyze.exit(tag);
} catch (err) {
(tag.node.extra ??= {})[kAnalyzeFailed] = true;
reportAnalyzeError(tag, err);
return;
}
}
},
translate: {
enter(tag) {
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
if (tagDef?.translator) {
if (tagDef.translator.path) (0, _marko_compiler_babel_utils.getFile)().metadata.marko.watchFiles.push(tagDef.translator.path);
enterHook(tagDef.translator.hook, tag);
return;
}
for (const attr of tag.get("attributes")) if (attr.isMarkoAttribute()) {
if (attr.node.arguments) throw attr.buildCodeFrameError(`Unsupported arguments on the \`${attr.node.name}\` attribute.`);
}
switch (analyzeTagNameType(tag)) {
case 0:
native_tag_default.translate.enter(tag);
break;
case 1:
custom_tag_default.translate.enter(tag);
break;
case 2:
dynamic_tag_default.translate.enter(tag);
break;
case 3: attribute_tag_default.translate.enter(tag);
}
},
exit(tag) {
const translator = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.translator;
if (translator) {
exitHook(translator.hook, tag);
return;
}
switch (analyzeTagNameType(tag)) {
case 0:
native_tag_default.translate.exit(tag);
break;
case 1:
custom_tag_default.translate.exit(tag);
break;
case 2:
dynamic_tag_default.translate.exit(tag);
break;
case 3: attribute_tag_default.translate.exit(tag);
}
}
}
};
//#endregion
//#region src/translator/visitors/text.ts
var text_default = {
analyze: { exit(text) {
if (isInTextBody(text)) return;
writeTextTo(text, text.node.value);
if (!followsStaticText(text)) enterShallow(text);
} },
translate: { exit(text) {
if (isInTextBody(text)) return;
if (isOutputHTML()) writeTo$1(text)`${text.node.value}`;
text.remove();
} }
};
//#endregion
//#region src/translator/interop/build-aggregate-error.ts
function buildAggregateError(file, rootMsg, ...paths) {
const err = /* @__PURE__ */ new SyntaxError();
const fileName = path.default.relative(_marko_compiler_modules.cwd, file.opts.filename);
const finalMsg = `${rootMsg}:\n\n${paths.map(([msg, path$10]) => `\x1b[90m${msg} at ${getFileNameWithLoc(fileName, path$10)}:\x1b[0m\n${getFrame(file, path$10)}`).join("\n\n")}`;
if (!("MARKO_DEBUG" in process.env)) err.stack = finalMsg;
Object.defineProperty(err, "message", {
get() {
return finalMsg;
},
set() {}
});
return err;
}
function getFrame(file, { node: { loc } }) {
return loc ? (0, _marko_compiler_internal_babel.codeFrameColumns)(file.code, {
start: {
line: loc.start.line,
column: loc.start.column + 1
},
end: loc.end && loc.start.line === loc.end.line ? {
line: loc.end.line,
column: loc.end.column + 1
} : void 0
}, { highlightCode: true }) : "";
}
function getFileNameWithLoc(fileName, { node: { loc } }) {
if (loc) return `${fileName}(${loc.start.line},${loc.start.column + 1})`;
return fileName;
}
//#endregion
//#region src/translator/interop/constants/feature-type.ts
const Class = "class";
const Tags = "tags";
//#endregion
//#region src/translator/interop/feature-detection.ts
function isTagsAPI(file = (0, _marko_compiler_babel_utils.getFile)()) {
const program = file.path;
const programExtra = program.node.extra ??= {};
let { featureType } = programExtra;
if (!featureType) {
const lookup = (0, _marko_compiler_babel_utils.getTaglibLookup)(file);
const tagsDir = getTagsDir(lookup, file.opts.filename);
const state = {};
if (tagsDir && !lookup.manualTagsDirs?.has(tagsDir)) addFeature(state, Tags, "Template file within a tags directory", program);
scanBody(state, program.get("body"));
featureType = file.metadata.marko.api = programExtra.featureType = state.feature?.type || (lookup.exclusiveTagDiscoveryDirs === "tags" ? "tags" : "class");
}
return featureType === Tags;
}
function getTagsDir(lookup, filename) {
let nearest;
for (const dir of lookup.discoveryDirs || []) if (filename.startsWith(dir) && (filename[dir.length] === "/" || filename[dir.length] === "\\") && (!nearest || dir.length > nearest.length)) nearest = dir;
return !!nearest && /[/\\]tags$/.test(nearest) && nearest;
}
function scanBody(state, body) {
if (body?.length) for (const child of body) switch (child.type) {
case "MarkoTag":
scanTag(state, child);
break;
case "MarkoComment":
if (/^\s*use tags\s*$/.test(child.node.value)) addFeature(state, Tags, "<!-- use tags -->", child);
else if (/^\s*use class\s*$/.test(child.node.value)) addFeature(state, Class, "<!-- use class -->", child);
break;
case "MarkoScriptlet":
if (!child.node.static) addFeature(state, Class, "Scriptlet", child);
break;
case "MarkoClass": addFeature(state, Class, "Class block", child.get("body"));
}
}
function scanTag(state, tag) {
if (tag.node.var) addFeature(state, Tags, "Tag variable", tag.get("var"));
const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
if (tagDef) {
if (tagDef.name === "style") {
if (/^style(?:(?:\.[^.\s\\/:*?"<>|({]+)+)?\s*\{/.test(tag.node.rawValue || "")) addFeature(state, Class, `style block`, tag.get("name"));
} else if (tagDef.taglibId === runtime_info_default.taglibId) {
const feature = getFeatureTypeFromCoreTagName(tagDef.name);
if (feature) addFeature(state, feature, `<${tagDef.name}> tag`, tag.get("name"));
}
}
if (!tagDef?.parseOptions?.rawOpenTag) {
for (const attr of tag.get("attributes")) if (attr.isMarkoAttribute()) {
if (attr.node.arguments?.length) {
addFeature(state, Class, "Attribute arguments", attr.get("arguments")[0]);
break;
} else if (attr.node.bound) {
addFeature(state, Tags, "Bound attribute", attr);
break;
}
}
}
scanBody(state, tag.get("body").get("body"));
scanBody(state, tag.get("attributeTags"));
}
function getFeatureTypeFromCoreTagName(tagName) {
switch (tagName) {
case "await-reorderer":
case "class":
case "include-html":
case "include-text":
case "init-components":
case "macro":
case "module-code":
case "while": return Class;
case "attrs":
case "const":
case "debug":
case "define":
case "effect":
case "id":
case "let":
case "lifecycle":
case "log":
case "return":
case "show":
case "try": return Tags;
default: return;
}
}
function addFeature(state, type, name, path) {
if (state.feature) {
if (state.feature.type !== type) throw buildAggregateError((0, _marko_compiler_babel_utils.getFile)(), "Cannot mix Tags API and Class API features in the same file", [state.feature.name, state.feature.path], [name, path]);
} else state.feature = {
name,
path,
type
};
}
//#endregion
//#region src/translator/interop/index.ts
function createInteropTranslator(translate5) {
return {
version: translate5.version ?? "0.0.0",
preferAPI: translate5.preferAPI,
transform: mergeVisitors(translate5.transform, transform),
analyze: mergeVisitors(translate5.analyze, analyze),
translate: withInteropEntryBuilder(mergeVisitors(translate5.translate, translate)),
tagDiscoveryDirs: [...tagDiscoveryDirs, ...translate5.tagDiscoveryDirs],
taglibs: mergeTaglibs(_marko_compiler.taglib.resolveOptionalTaglibs(translate5.optionalTaglibs).concat(translate5.taglibs), taglibs),
getRuntimeEntryFiles(output, optimize) {
return [...translate5.getRuntimeEntryFiles(output, optimize), ...getRuntimeEntryFiles(output, optimize)];
}
};
function withInteropEntryBuilder(visitor) {
const { Program } = visitor;
const kState = Symbol();
const entryBuilder = {
build(entryFile) {
const state = entryFile[kState];
assertVisited(entryFile, state);
if (state.has5) {
if (state.has6) {
const filename = entryFile.opts.filename;
const baseName = `./${path.default.basename(filename)}`;
const generatorOpts = {
...entryFile.opts.generatorOpts,
sourceMaps: false
};
const { resolveVirtualDependency } = entryFile.markoOpts;
const importEntryProgram = (name, statements) => {
return _marko_compiler.types.importDeclaration([_marko_compiler.types.importDefaultSpecifier(_marko_compiler.types.identifier(`init${name}`))], _marko_compiler.types.stringLiteral(resolveVirtualDependency(filename, {
code: (0, _marko_compiler_internal_babel.generator)(_marko_compiler.types.program(statements), generatorOpts).code,
virtualPath: `${baseName}.hydrate-${name}.js`
})));
};
return [
...state.needsCompat ? [_marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(getCompatRuntimeFile()))] : [],
...Array.from(state.classFnFiles, (classFnFile) => _marko_compiler.types.importDeclaration([], _marko_compiler.types.stringLiteral(classFnFile))),
importEntryProgram("6", builder.build(entryFile, true)),
importEntryProgram("5", translate5.internalEntryBuilder.build(entryFile, true)),
_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(_marko_compiler.types.identifier("init6"), [])),
_marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(_marko_compiler.types.identifier("init5"), []))
];
} else return translate5.internalEntryBuilder.build(entryFile);
} else return builder.build(entryFile);
},
visit(file, entryFile, visitChild) {
const state = entryFile[kState] ||= {
has5: false,
has6: false,
needsCompat: false,
classFnFiles: /* @__PURE__ */ new Set()
};
if (isTagsAPI(file)) {
state.has6 = true;
builder.visit(file, entryFile, visitChild);
} else {
state.has5 = true;
if (file.path.node.extra?.resumesCompat) state.needsCompat = true;
if (file.path.node.extra?.resumesClassFns) state.classFnFiles.add((0, _marko_compiler_babel_utils.resolveRelativePath)(entryFile, file.opts.filename));
translate5.internalEntryBuilder.visit(file, entryFile, visitChild);
}
}
};
const enterProgram = getVisitorEnter(Program);
return {
...visitor,
Program: {
enter(program, state) {
const entryFile = (0, _marko_compiler_babel_utils.getFile)();
const { output, entry } = entryFile.markoOpts;
if (!(output === "dom" && entry === "page" || output === "hydrate")) return enterProgram?.call(this, program, state);
const visitedFiles = createVisited(entryFile);
entryBuilder.visit(entryFile, entryFile, function visitChild(resolved, reach = 0) {
if (!markReached(visitedFiles, resolved, reach)) return;
const file = (0, _marko_compiler_babel_utils.loadFileForImport)(entryFile, resolved);
if (file) entryBuilder.visit(file, entryFile, (id, childReach = 0) => visitChild(resolveRelativeToEntry(entryFile, file, id), childReach > reach ? childReach : reach));
});
program.node.body = entryBuilder.build(entryFile);
program.skip();
},
exit: getVisitorExit(Program)
}
};
}
}
function mergeVisitors(visitor5, visitor6) {
return mergeObjects(visitor5, visitor6, (_, value5, value6) => mergeVisit(value5, value6));
}
function mergeVisit(visit5, visit6) {
const enter = mergeHook(getVisitorEnter(visit5), getVisitorEnter(visit6));
const exit = mergeHook(getVisitorExit(visit5), getVisitorExit(visit6));
return exit ? enter ? {
enter,
exit
} : { exit } : enter;
}
function mergeHook(hook5, hook6) {
return (hook5 || hook6) && function(path$9, state) {
return (isTagsAPI() ? hook6 : hook5)?.call(this, path$9, state);
};
}
function mergeTaglibs(libs5, libs6) {
const libs5Map = new Map(libs5);
const libs6Map = new Map(libs6);
const merged = [];
for (const taglibId of /* @__PURE__ */ new Set([...libs5Map.keys(), ...libs6Map.keys()])) merged.push([taglibId, mergeObjects(libs5Map.get(taglibId), libs6Map.get(taglibId), (key, value5, value6) => {
switch (key) {
case "migrate":
case "analyze":
case "transform":
case "translate": return mergeVisitors(normalizeVisitor(value5), normalizeVisitor(value6));
default:
if (key[0] === "<") return mergeTagDef(value5, value6);
return value5 ?? value6;
}
})]);
return merged;
}
function mergeTagDef(def5, def6) {
return mergeObjects(normalizeTagDef(def5), normalizeTagDef(def6), (key, value5, value6) => {
switch (key) {
case "parse":
case "migrate":
case "transform":
case "analyze":
case "translate": return mergeVisit(normalizeVisit(value5), normalizeVisit(value6));
default: return value5 ?? value6;
}
});
}
function mergeObjects(a, b, cb) {
const merged = {};
const assign = (key, aValue, bValue) => {
const value = cb(key, aValue, bValue);
if (value !== void 0) merged[key] = value;
};
if (a) {
if (b) {
for (const key in a) assign(key, a[key], b[key]);
for (const key in b) if (!(key in a)) assign(key, void 0, b[key]);
} else for (const key in a) assign(key, a[key], void 0);
} else if (b) for (const key in b) assign(key, void 0, b[key]);
return merged;
}
function normalizeTagDef(tagDef) {
if (tagDef) {
const normalized = {};
for (const key in tagDef) normalized[normalizeTagDefKey(key)] = tagDef[key];
return normalized;
}
}
function normalizeTagDefKey(key) {
switch (key) {
case "code-generator":
case "codeGenerator": return "translate";
case "migrator": return "migrate";
case "node-factory":
case "nodeFactory": return "parse";
case "parse-options": return "parseOptions";
case "transformer": return "transform";
default: return key;
}
}
function normalizeVisitor(visitor) {
return visitor?.default ?? visitor;
}
function normalizeVisit(visitor) {
if (Array.isArray(visitor)) throw new Error("A core tag's hook must be a single visitor for the interop merge, not a list.");
return typeof visitor === "function" ? visitor : normalizeVisitor(visitor);
}
function getVisitorEnter(visit) {
return typeof visit === "function" ? visit : visit?.enter;
}
function getVisitorExit(visit) {
return typeof visit === "object" ? visit?.exit : void 0;
}
//#endregion
//#region src/translator/index.ts
const version = package_json.default.version;
const cheatsheet = "../../cheatsheet.md";
const visitors = extractVisitors({
Program: program_default,
Function: function_default,
ReferencedIdentifier: referenced_identifier_default,
ImportDeclaration: import_declaration_default,
ExportNamedDeclaration: export_declaration_default,
ExportAllDeclaration: export_declaration_default,
MarkoDocumentType: document_type_default,
MarkoDeclaration: declaration_default,
MarkoCDATA: cdata_default,
MarkoText: text_default,
MarkoTag: tag_default,
MarkoPlaceholder: placeholder_default,
MarkoScriptlet: scriptlet_default,
MarkoComment: comment_default
});
const tagDiscoveryDirs = ["tags"];
const preferAPI = "tags";
const { transform, analyze, translate } = visitors;
const taglibs = [[core_default.taglibId, {
...core_default,
migrate: visitors.migrate
}]];
function getRuntimeEntryFiles(output, optimize) {
const runtime = `${runtime_info_default.name}${optimize ? "" : "/debug"}`;
if (output === "html") return [`${runtime}/html`];
return [`${runtime}/dom`, ...domRuntimeFeatures.map((feature) => `${runtime}/dom/${feature}.feat`)];
}
//#endregion
exports.analyze = analyze;
exports.cheatsheet = cheatsheet;
exports.createInteropTranslator = createInteropTranslator;
exports.getRuntimeEntryFiles = getRuntimeEntryFiles;
exports.internalEntryBuilder = builder;
exports.preferAPI = preferAPI;
exports.tagDiscoveryDirs = tagDiscoveryDirs;
exports.taglibs = taglibs;
exports.transform = transform;
exports.translate = translate;
exports.version = version;