UNPKG

marko

Version:

Optimized runtime for Marko templates.

1,296 lines (1,295 loc) 96.9 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); //#region src/common/attr-tag.ts const empty = []; const rest = Symbol("Attribute Tag"); function attrTag(attrs) { attrs[Symbol.iterator] = attrTagIterator; attrs[rest] = empty; return attrs; } function attrTags(first, attrs) { if (first) { if (first[rest] === empty) first[rest] = [attrs]; else first[rest].push(attrs); return first; } return attrTag(attrs); } function* attrTagIterator() { yield this; yield* this[rest]; } //#endregion //#region src/common/constants/accessor-prefix.debug.ts const BranchScopes$1 = "BranchScopes:"; const ClosureScopes = "ClosureScopes:"; const ClosureSignalIndex = "ClosureSignalIndex:"; const ConditionalRenderer = "ConditionalRenderer:"; const ControlledObserver = "ControlledObserver:"; const ControlledHandler = "ControlledHandler:"; const ControlledType = "ControlledType:"; const ControlledValue = "ControlledValue:"; const DynamicHTMLLastChild = "DynamicHTMLLastChild:"; const EventAttributes = "EventAttributes:"; const KeyedScopes = "KeyedScopes:"; const Lifecycle = "Lifecycle:"; const Promise$1 = "Promise:"; const TagVariableChange$1 = "TagVariableChange:"; //#endregion //#region src/common/constants/accessor-prop.debug.ts const Global = "$global"; const AbortControllers = "#AbortControllers"; const AbortScopes = "#AbortScopes"; const AwaitCounter = "#AwaitCounter"; const BranchAccessor = "#BranchAccessor"; const BranchScopes = "#BranchScopes"; const CatchContent = "#CatchContent"; const ClosestBranch = "#ClosestBranch"; const ClosestBranchId = "#ClosestBranchId"; const Gen$1 = "#Gen"; const DetachedAwait = "#DetachedAwait"; const EndNode = "#EndNode"; const Load = "#Load"; const LoopKey = "#LoopKey"; const ParentBranch = "#ParentBranch"; const PendingEffects = "#PendingEffects"; const PendingRenders = "#PendingRenders"; const PendingScopes = "#PendingScopes"; const PlaceholderBranch = "#PlaceholderBranch"; const PlaceholderContent = "#PlaceholderContent"; const Renderer = "#Renderer"; const StartNode = "#StartNode"; const Subscriptions = "#Subscriptions"; const TagVariable = "#TagVariable"; const TagVariableChange = "#TagVariableChange"; //#endregion //#region src/common/constants/closure-signal-prop.debug.ts const ScopeInstancesAccessor = "scopeInstancesAccessor"; const SignalIndexAccessor = "signalIndexAccessor"; const Index = "index"; //#endregion //#region src/common/constants/keyed-scopes-prop.debug.ts const PreviousKey = "PreviousKey:"; //#endregion //#region src/common/constants/load-signal-value.debug.ts const Value$1 = "value"; const Signal$1 = "signal"; const Scope = "scope"; const Signal = "signal"; const Value = "value"; const Pending = "pending"; const Clone = "clone"; const Setup = "setup"; const Params = "params"; const Owner = "owner"; const Accessor = "accessor"; const LocalClosures = "localClosures"; const LocalClosureValues = "localClosureValues"; //#endregion //#region src/common/helpers.ts const htmlAttrNameReg = /^[^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 _call(fn, v) { fn(v); return v; } function stringifyClassObject(name, value) { return value ? name : ""; } const warnedStyleKeys = /* @__PURE__ */ new Set(); function stringifyStyleObject(name, value) { if (/[A-Z]/.test(name) && !name.includes("-") && !warnedStyleKeys.has(name)) { warnedStyleKeys.add(name); console.warn(`\`${name}\` is not a CSS property name; \`style\` object keys are written verbatim, so it renders as invalid CSS. Use \`${name.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()).replace(/^ms-/, "-ms-")}\`.`); } 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 getEventHandlerName(name) { return name[2] === "-" ? name.slice(3) : name.slice(2).toLowerCase(); } function isNotVoid(value) { return value != null && value !== false; } function isPromise(value) { return value != null && typeof value.then === "function"; } function normalizeDynamicRenderer(value) { if (value) { if (typeof value === "string") return value; const normalized = value.content || value.default || value; if (!((typeof normalized === "object" || typeof normalized === "function") && "id" in normalized)) { if (value.content) throw new Error(`A dynamic tag must be a string tag name (like \`"div"\`) or a Marko template/component, but received an object whose \`content\` is not a template/component.`); if (typeof value !== "object" && typeof value !== "function") throw new Error(`A dynamic tag must be a string tag name (like \`"div"\`) or a Marko template/component, but received a ${typeof value}.`); } if ("id" in normalized) return normalized; } } //#endregion //#region src/common/errors.ts const lowercaseEventHandlerReg = /^on[a-z]/; function assertValidAttrValue(name, value) { if (value && typeof value !== "string" && lowercaseEventHandlerReg.test(name)) throw new Error(`The \`${name}\` attribute must be a string or a falsey value (\`null\`, \`undefined\`, \`false\`, \`0\`, …), but received type "${typeof value}". To attach an event listener, use the \`on${name[2].toUpperCase()}${name.slice(3)}\` event handler instead.`); if (typeof value === "function") throw new Error(`The \`${name}\` attribute cannot be a function.${/Change$/.test(name) ? " A change handler is only used when its matching controllable attribute combination applies." : ""}`); const unrenderable = describeUnrenderable(value); if (unrenderable) throw new Error(`The \`${name}\` attribute cannot be ${unrenderable}.`); } function assertValidTextValue(value) { const unrenderable = describeUnrenderable(value); if (unrenderable) throw new Error(`Text content cannot be ${unrenderable}.`); } function describeUnrenderable(value) { if (typeof value === "symbol") return "a symbol"; if (typeof value === "object" && value !== null) { let stringified; try { stringified = `${value}`; } catch { stringified = "[object Object]"; } if (/^\[object \w+\]$/.test(stringified)) return stringified === "[object Promise]" ? "a promise (use the `<await>` tag to render its resolved value)" : stringified === "[object Object]" ? "a plain object (it would render as `[object Object]`)" : `a value that renders as \`${stringified}\``; } } function assertValidLoopKey(key, seenKeys) { if (typeof key !== "string" && typeof key !== "number") throw new Error(`A \`<for>\` tag's \`by\` attribute must return a string or number for each item, but received ${key === null ? "null" : `type "${typeof key}"`}.`); if (seenKeys) { if (seenKeys.has(key)) throw new Error(`A \`<for>\` tag's \`by\` attribute must return a unique value for each item, but \`${key}\` was used more than once.`); seenKeys.add(key); } } function assertValidList(value) { if (value && typeof value[Symbol.iterator] !== "function") throw new Error(`A \`<for>\` tag's \`of\` attribute must be an iterable, such as an array, but received ${describeForValue(value)}.`); } function assertValidRangeBound(name, value) { if (!isFinite(value)) throw new Error(`A \`<for>\` tag's \`${name}\` attribute must be a finite number, but received ${describeForValue(value)}.`); } function describeForValue(value) { return typeof value === "number" || typeof value === "bigint" ? `\`${value}\`` : value === null ? "null" : `type "${typeof value}"`; } function assertValidAttrName(name) { if (htmlAttrNameReg.test(name)) throw new Error(`Invalid attribute name: ${JSON.stringify(name)}`); const suggestion = getWrongAttrSuggestion(name); if (suggestion) throw new Error(`\`${name}\` is not a valid attribute, did you mean \`${suggestion}\`?`); } function _el_read_error() { throw new Error("Element references can only be read in scripts and event handlers."); } function _hoist_read_error() { throw new Error("Hoisted values can only be read in scripts and event handlers."); } function _assert_hoist(value) { if (typeof value !== "function") throw new Error(`Hoisted values must be functions, received type "${typeof value}".`); } function assertExclusiveAttrs(attrs, onError = throwErr) { if (attrs) { let exclusiveAttrs; if (attrs.checkedChange) (exclusiveAttrs ||= []).push("checkedChange"); if ("checkedValue" in attrs) { (exclusiveAttrs ||= []).push("checkedValue"); if ("checked" in attrs) exclusiveAttrs.push("checked"); } else if (attrs.checkedValueChange) { (exclusiveAttrs ||= []).push("checkedValueChange"); if ("checked" in attrs) exclusiveAttrs.push("checked"); } if (attrs.valueChange) (exclusiveAttrs ||= []).push("valueChange"); if (exclusiveAttrs && exclusiveAttrs.length > 1) onError(`The attributes ${joinWithAnd(exclusiveAttrs)} are mutually exclusive.`); } } function assertHandlerIsFunction(name, value) { if (value && typeof value !== "function") throw new Error(`The \`${name}\` handler must be a function or a falsey value (\`null\`, \`undefined\`, \`false\`, \`0\`, …), but received type "${typeof value}".`); } function assertValidTagName(tagName) { if (!/^[a-z][a-z0-9._-]*$/i.test(tagName)) throw new Error(`Invalid tag name: "${tagName}". Tag names must start with a letter and contain only letters, numbers, periods, hyphens, and underscores.`); } 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/common/for.ts function forIn(obj, cb) { for (const key in obj) cb(key, obj[key]); } function forOf(list, cb) { assertValidList(list); if (list) { let i = 0; for (const item of list) cb(item, i++); } } function forTo(to, from, step, cb) { assertValidRangeBound("to", to); const start = from || 0; const delta = step || 1; for (let steps = (to - start) / delta, i = 0; i <= steps; i++) cb(start + i * delta); } function forUntil(until, from, step, cb) { assertValidRangeBound("until", until); const start = from || 0; const delta = step || 1; for (let steps = (until - start) / delta, i = 0; i < steps; i++) cb(start + i * delta); } //#endregion //#region src/common/meta.ts const DYNAMIC_TAG_SCRIPT_REGISTER_ID = "_dynamicTagScript"; //#endregion //#region src/common/opt.ts function toArray(opt) { return opt ? Array.isArray(opt) ? opt : [opt] : []; } function forEach(opt, cb) { if (opt) if (Array.isArray(opt)) for (const item of opt) cb(item); else cb(opt); } function push(opt, item) { return opt ? Array.isArray(opt) ? (opt.push(item), opt) : [opt, item] : item; } //#endregion //#region src/dom/event.ts function _on(element, type, handler) { assertHandlerIsFunction("on" + type[0].toUpperCase() + type.slice(1), handler); if (element["$" + type] === void 0) delegate(type, handleDelegated); element["$" + type] = handler || null; } const delegate = (type, handler) => handler[type] ||= (document.addEventListener(type, handler, true), 1); function handleDelegated(ev) { let target = !rendering && ev.target; Object.defineProperty(ev, "currentTarget", { configurable: true, get() { console.error("Event.currentTarget is not supported in Marko's delegated events. Instead use an element reference or the second parameter of the event handler."); return null; } }); while (target) { target["$" + ev.type]?.(ev, target); target = ev.bubbles && !ev.cancelBubble && target.parentNode; } delete ev.currentTarget; } //#endregion //#region src/dom/parse-html.ts const parsers = {}; function parseHTML(html, ns) { const parser = parsers[ns] ||= document.createElementNS(ns, "template"); parser.innerHTML = html; return parser.content || parser; } //#endregion //#region src/dom/scope.ts let nextScopeId = 1e6; let collectingScopes; function createScope($global, closestBranch) { const scope = { ["#Id"]: nextScopeId++, [Gen$1]: runId, [ClosestBranch]: closestBranch, [Global]: $global }; collectingScopes?.push(scope); return scope; } function syncGen(scope) { scope[Gen$1] = runId; } function _assert_init(scope, accessor) { if (scope["#Gen"] === runId || !(accessor in scope)) throw new ReferenceError(`Cannot access '${accessor}' before initialization`); return scope[accessor]; } function collectScopes(fn) { const prev = collectingScopes; collectingScopes = []; try { fn(); return collectingScopes; } finally { collectingScopes = prev; } } function skipScope() { return nextScopeId++; } function findBranchWithKey(scope, key) { let branch = scope[ClosestBranch]; while (branch && branch[key] == null) branch = branch[ParentBranch]; return branch; } function destroyBranch(branch) { branch[ParentBranch]?.[BranchScopes]?.delete(branch); destroyNestedScopes(branch); } function destroyScope(scope) { if (scope["#Gen"]) { destroyNestedScopes(scope); cleanupScope(scope); } } const destroyNestedScopes = function destroyNestedScopes(scope) { scope[Gen$1] = 0; scope[BranchScopes]?.forEach(destroyNestedScopes); scope[AbortScopes]?.forEach(cleanupScope); }; function cleanupScope(scope) { scope[Subscriptions]?.forEach(unsubscribe, scope); for (const id in scope[AbortControllers]) $signalReset(scope, id); } function unsubscribe(subscribers) { subscribers.delete(this); } function removeAndDestroyBranch(branch) { destroyBranch(branch); removeChildNodes(branch[StartNode], branch[EndNode]); } function insertBranchBefore(branch, parentNode, nextSibling) { insertChildNodes(parentNode, nextSibling, branch[StartNode], branch[EndNode]); } function tempDetachBranch(branch) { const fragment = new DocumentFragment(); fragment.namespaceURI = branch[StartNode].parentNode.namespaceURI; insertChildNodes(fragment, null, branch[StartNode], branch[EndNode]); } //#endregion //#region src/dom/schedule.ts let runTask; let isScheduled; let channel; function schedule() { if (!isScheduled) { if (console.createTask) { const task = console.createTask("queue"); runTask = () => task.run(run); } else runTask = run; isScheduled = 1; queueMicrotask(flushAndWaitFrame); } } function flushAndWaitFrame() { requestAnimationFrame(triggerMacroTask); runTask(); } function triggerMacroTask() { if (!channel) { channel = new MessageChannel(); channel.port1.onmessage = () => { isScheduled = 0; { const run = runTask; runTask = void 0; run(); } }; } channel.port2.postMessage(0); } //#endregion //#region src/dom/signals.ts function _let(id, fn) { const valueAccessor = id.slice(0, id.lastIndexOf("/")); id = +id.slice(id.lastIndexOf("/") + 1); return (scope, value) => { if (rendering) { if (scope["#Gen"] === runId) { scope[valueAccessor] = value; fn?.(scope); } } else if ((scope[valueAccessor] !== value || !(valueAccessor in scope)) && (scope[valueAccessor] = value, fn)) { schedule(); queueRender(scope, fn, id); } return value; }; } function _let_change(id, fn) { const valueAccessor = id.slice(0, id.lastIndexOf("/")); const valueChangeAccessor = TagVariableChange$1 + valueAccessor; const base = _let(id, fn); return (scope, value, valueChange) => { if (rendering) if ((scope[valueChangeAccessor] = valueChange) && (scope[valueAccessor] !== value || !(valueAccessor in scope))) { scope[valueAccessor] = value; fn?.(scope); } else base(scope, value); else if (scope[valueChangeAccessor]) scope[valueChangeAccessor](value); else base(scope, value); return value; }; } function _const(valueAccessor, fn) { return ((scope, value) => { if (scope[valueAccessor] !== value || !(valueAccessor in scope)) { scope[valueAccessor] = value; fn?.(scope); } }); } function _or(id, fn, defaultPending = 1, scopeIdAccessor = "#Id") { return (scope) => { if (scope["#Gen"] === runId) if (~id in scope) { if (!--scope[~id]) fn(scope); } else scope[~id] = defaultPending; else queueRender(scope, fn, id, 0, scope[scopeIdAccessor]); }; } function _for_closure(ownerLoopNodeAccessor, fn) { const scopeAccessor = BranchScopes$1 + ownerLoopNodeAccessor; const ownerSignal = (ownerScope) => { const scopes = toArray(ownerScope[scopeAccessor]); if (scopes.length) queueRender(ownerScope, () => { for (const scope of scopes) if (scope["#Gen"] > 0 && scope["#Gen"] < runId) fn(scope); }, -1, 0, scopes[0]["#Id"]); }; ownerSignal._ = fn; return ownerSignal; } function _for_selector(ownerLoopNodeAccessor, ownerValueAccessor, keyValueAccessor, fn) { const scopeAccessor = BranchScopes$1 + ownerLoopNodeAccessor; const mapAccessor = KeyedScopes + ownerLoopNodeAccessor; const prevKeyProp = `${PreviousKey}${ownerValueAccessor}`; const ownerSignal = (ownerScope) => { const scopes = toArray(ownerScope[scopeAccessor]); if (ownerScope["#Gen"] < runId && scopes.length) { const nextKey = ownerScope[ownerValueAccessor]; queueRender(ownerScope, () => { const map = keyedScopes(ownerScope, scopeAccessor, mapAccessor, keyValueAccessor); if (map && prevKeyProp in map) { const prevScope = map.get(map[prevKeyProp]); const nextScope = map.get(nextKey); if (prevScope !== nextScope) { runLiveBranch(prevScope, fn); runLiveBranch(nextScope, fn); } } else for (const scope of toArray(ownerScope[scopeAccessor])) runLiveBranch(scope, fn); if (map) map[prevKeyProp] = nextKey; }, -1, 0, scopes[0]["#Id"]); } }; ownerSignal._ = fn; return ownerSignal; } function keyedScopes(ownerScope, scopeAccessor, mapAccessor, keyValueAccessor) { const map = ownerScope[mapAccessor] ||= /* @__PURE__ */ new Map(); if (!map.size) for (const scope of toArray(ownerScope[scopeAccessor])) { const key = scope["#LoopKey"] ?? scope[keyValueAccessor]; if (key === void 0) return ownerScope[mapAccessor] = null; scope[LoopKey] = key; map.set(key, scope); } return map; } function runLiveBranch(scope, fn) { if (scope && scope["#Gen"] > 0 && scope["#Gen"] < runId) fn(scope); } function _if_closure(ownerConditionalNodeAccessor, branch, fn) { const scopeAccessor = BranchScopes$1 + ownerConditionalNodeAccessor; const branchAccessor = ConditionalRenderer + ownerConditionalNodeAccessor; const ownerSignal = (scope) => { const ifScope = scope[scopeAccessor]; if (ifScope && ifScope["#Gen"] > 0 && ifScope["#Gen"] < runId && (scope[branchAccessor] || 0) === branch) queueRender(ifScope, fn, -1); }; ownerSignal._ = fn; return ownerSignal; } function subscribeToScopeSet(ownerScope, accessor, scope) { const subscribers = ownerScope[accessor] ||= /* @__PURE__ */ new Set(); const { size } = subscribers; if (subscribers.add(scope).size !== size) trackCleanup(scope, subscribers); } function _closure(...closureSignals) { const [firstSignal] = closureSignals; const scopeInstances = firstSignal[ScopeInstancesAccessor]; const signalIndex = firstSignal[SignalIndexAccessor]; for (let i = closureSignals.length; i--;) closureSignals[i][Index] = i; return (scope) => { if (scope[scopeInstances]) { for (const childScope of scope[scopeInstances]) if (childScope["#Gen"] > 0 && childScope["#Gen"] < runId) queueRender(childScope, closureSignals[childScope[signalIndex] || 0], -1); } }; } function _closure_get(valueAccessor, fn, getOwnerScope, resumeId) { const closureSignal = ((scope) => { scope[closureSignal[SignalIndexAccessor]] = closureSignal[Index]; fn(scope); subscribeToScopeSet(getOwnerScope ? getOwnerScope(scope) : scope["_"], closureSignal[ScopeInstancesAccessor], scope); }); closureSignal[ScopeInstancesAccessor] = ClosureScopes + valueAccessor; closureSignal[SignalIndexAccessor] = ClosureSignalIndex + valueAccessor; resumeId && _resume(resumeId, closureSignal); return closureSignal; } function _child_setup(setup) { setup._ = (scope, owner) => { scope["_"] = owner; queueRender(scope, setup, -1); }; return setup; } function _var(scope, childAccessor, signal) { scope[childAccessor][TagVariable] = (value) => signal(scope, value); } const _return = (scope, value) => scope[TagVariable]?.(value); function _return_change(scope, changeHandler) { if (changeHandler) scope[TagVariableChange] = changeHandler; } const _var_change = (scope, value, name = "This") => { if (typeof scope["#TagVariableChange"] !== "function") throw new TypeError(`${name} is a readonly tag variable.`); scope[TagVariableChange](value); }; const tagIdsByGlobal = /* @__PURE__ */ new WeakMap(); function _id({ [Global]: $global }) { const id = tagIdsByGlobal.get($global) || 0; tagIdsByGlobal.set($global, id + 1); return "c" + $global.runtimeId + $global.renderId + id.toString(36); } function _script(id, fn) { _resume(id, fn); return (scope) => { queueEffect(scope, fn); }; } function _el_read(value) { if (rendering) _el_read_error(); return value; } function* traverse(scope, path, i = path.length - 1) { if (rendering) _hoist_read_error(); if (scope) if (Symbol.iterator in scope) for (const childScope of scope.values()) yield* traverse(childScope, path, i); else { const item = scope[path[i]]; if (i) yield* traverse(item, path, i - 1); else yield typeof item === "function" ? item() : item; } } function _hoist(...path) { return (scope) => { const fn = () => traverse(scope, path).next().value; fn[Symbol.iterator] = () => traverse(scope, path); return fn; }; } function _hoist_resume(id, ...path) { return _resume(id, _hoist(...path)); } //#endregion //#region src/dom/walker.ts /** Cloned templates are small, where a TreeWalker's per-step cost dominates. */ let currentNode; function walk(startNode, walkCodes, branch) { currentNode = startNode; walkInternal(0, walkCodes, branch); } const walkInternal = function walkInternal(currentWalkIndex, walkCodes, scope) { let value; let currentMultiplier; let storedMultiplier = 0; let currentScopeIndex = 0; for (; currentWalkIndex < walkCodes.length;) { value = walkCodes.charCodeAt(currentWalkIndex++); currentMultiplier = storedMultiplier; storedMultiplier = 0; if (value === 32) scope[getDebugKey(currentScopeIndex++, currentNode)] = currentNode; else if (value === 37 || value === 49) { currentNode.replaceWith(currentNode = scope[getDebugKey(currentScopeIndex++, "#text")] = new Text()); if (value === 49) scope[getDebugKey(currentScopeIndex++, "#scopeOffset")] = skipScope(); } else if (value === 38) return currentWalkIndex; else if (value === 47 || value === 48) { currentWalkIndex = walkInternal(currentWalkIndex, walkCodes, scope[getDebugKey(currentScopeIndex++, "#childScope")] = createScope(scope[Global], scope[ClosestBranch])); if (value === 48) scope[getDebugKey(currentScopeIndex++, "#scopeOffset")] = skipScope(); } else if (value < 92) { value = 25 * currentMultiplier + value - 67; while (value--) walkNextNode(); } else if (value < 107) { value = 10 * currentMultiplier + value - 97; while (value--) walkNextSibling(); } else if (value < 117) { value = 10 * currentMultiplier + value - 107; while (value--) currentNode = currentNode.parentNode || currentNode; walkNextSibling(); } else { if (value < 117 || value > 126) throw new Error(`Unknown walk code: ${value}`); storedMultiplier = currentMultiplier * 10 + value - 117; } } }; function getDebugKey(index, node) { if (typeof node === "string") return `${node}/${index}`; else if (node.nodeType === 3) return `#text/${index}`; else if (node.nodeType === 8) return `#comment/${index}`; else if (node.nodeType === 1) return `#${node.tagName.toLowerCase()}/${index}`; return index; } const walkNextNode = () => { if (currentNode.firstChild) return currentNode = currentNode.firstChild; while (!currentNode.nextSibling && currentNode.parentNode) currentNode = currentNode.parentNode; walkNextSibling(); }; const walkNextSibling = () => currentNode = currentNode.nextSibling || currentNode; //#endregion //#region src/dom/resume.ts const registeredValues = {}; let curRenders; let branchesEnabled; let embedRenders; let readyIds; function enableBranches() { if (!branchesEnabled) { branchesEnabled = 1; skipDestroyedRenders(); } } function ready(readyId) { (readyIds ||= /* @__PURE__ */ new Set()).add(readyId); for (const renderId in curRenders) runResumeEffects(curRenders[renderId]); } function initEmbedded(readyId, runtimeId) { if (!embedRenders) { embedRenders = /* @__PURE__ */ new Map(); new MutationObserver(() => { for (const [anchor, [renderId, scopes]] of embedRenders) if (!anchor.isConnected) { embedRenders.delete(anchor); delete curRenders[renderId]; for (const id in scopes) destroyScope(scopes[id]); } }).observe(document, { childList: true, subtree: true }); } ready(readyId); init(runtimeId); } function init(runtimeId = "M") { if (curRenders) { if (curRenders !== self[runtimeId]) throw new Error(`Marko initialized multiple times with different $global.runtimeId's.`); return; } const renders = self[runtimeId]; const defineRuntime = (desc) => Object.defineProperty(self, runtimeId, desc); const initRuntime = (renders) => { defineRuntime({ value: curRenders = ((renderId) => { const render = curRenders[renderId] = renders[renderId] || renders(renderId); const walk = render.w; const scopeLookup = {}; const getScope = (id) => scopeLookup[id] || (+id ? initScope(scopeLookup[id] = { ["#Id"]: +id }) : initGlobal()); const initGlobal = () => scopeLookup[0] ||= { runtimeId, renderId }; const initScope = (scope) => { scope[Gen$1] = 1; scope[Global] = initGlobal(); if (branchesEnabled && scope["#ClosestBranchId"]) scope[ClosestBranch] = getScope(scope[ClosestBranchId]); return scope; }; const applyScopes = (partials) => { let scopeId = partials[0]; for (let i = 1; i < partials.length; i++) { const partial = partials[i]; if (typeof partial === "number") scopeId += partial; else { if (scopeId) initScope(Object.assign(scopeLookup[scopeId] ||= (partial["#Id"] = scopeId, partial), partial)); else Object.assign(initGlobal(), partial); scopeId++; } } }; const serializeContext = ((data, registryId) => typeof data === "number" ? registryId ? registeredValues[registryId](getScope(data)) : getScope(data) : applyScopes(data)); const createVisitBranches = (branchScopesStack = [], branchStarts = [], orphanBranches = [], deferredOwners = [], curBranchScopes) => { return (branchId, branch, endedBranches, accessor, singleNode, parent = visit.parentNode, startVisit = visit, i = orphanBranches.length, j = deferredOwners.length) => { if (visitType !== "[") { visitScope[nextToken()] = visitType === ")" || visitType === "}" ? parent : visit; accessor = BranchScopes$1 + lastToken; singleNode = visitType !== "]" && visitType !== ")"; nextToken(); } while (branchId = +lastToken) { (endedBranches ||= []).push(branch = getScope(branchId)); setParentBranch(branch, branch[ClosestBranch]); if (branch["#AwaitCounter"] = render.p?.[branchId]) branch[AwaitCounter].m = render.m; if (singleNode) { while (startVisit.previousSibling && ~visits.indexOf(startVisit = startVisit.previousSibling)); branch["_"] ??= visitScope; branch[EndNode] = branch[StartNode] = startVisit; if (visitType === "'") branch[getDebugKey(0, startVisit)] = startVisit; } else { curBranchScopes = push(curBranchScopes, branch); if (accessor) { visitScope[accessor] = curBranchScopes; forEach(curBranchScopes, (scope) => scope["_"] ??= visitScope); curBranchScopes = branchScopesStack.pop(); } startVisit = branchStarts.pop(); if (parent !== startVisit.parentNode) parent.prepend(startVisit); branch[StartNode] = startVisit; branch[EndNode] = visit.previousSibling === startVisit ? startVisit : parent.insertBefore(new Text(), visit); } while (i && orphanBranches[i - 1]["#Id"] > branchId) { i--; setParentBranch(orphanBranches.pop(), branch); } while (j && deferredOwners[j - 1]["#Id"] > branchId) { j--; const owner = deferredOwners.pop(); if (owner["#ClosestBranch"] !== owner) owner[ClosestBranch] = branch; } nextToken(); } if (endedBranches) { for (const ended of endedBranches) orphanBranches.push(ended); if (singleNode) visitScope[accessor] = endedBranches.length > 1 ? endedBranches.reverse() : endedBranches[0]; } if (visitType === "[") { if (!endedBranches) { branchScopesStack.push(curBranchScopes); curBranchScopes = void 0; } branchStarts.push(visit); } else deferredOwners.push(visitScope); }; }; const nextToken = () => lastToken = visitText.slice(lastTokenIndex, (lastTokenIndex = visitText.indexOf(" ", lastTokenIndex) + 1 || visitText.length + 1) - 1); const processResumes = (resumes = [], effects) => { let i = 0; for (; i < resumes.length; i++) { const serialized = resumes[i]; if (typeof serialized === "string") { lastTokenIndex = 0; visitText = serialized; while (nextToken()) if (/\D/.test(lastToken)) lastEffect = registeredValues[lastToken]; else effects.push(lastEffect, getScope(lastToken)); } else if (Array.isArray(serialized)) { if (!(readyIds && serialized.every((dep) => readyIds.has(dep) && !render.b[dep].length))) break; } else if (readyIds && typeof serialized === "number") break; else { const scopes = serialized(serializeContext); if (Array.isArray(scopes)) applyScopes(scopes); } } resumes.splice(0, i); return i; }; let lastEffect; let visits; let visit; let visitText; let visitType; let visitScope; let lastToken; let lastTokenIndex; let visitBranches; let embedAnchor; serializeContext._ = registeredValues; if (render.m) throw new Error(`Marko rendered multiple times with $global.runtimeId as ${JSON.stringify(runtimeId)} and $global.renderId as ${JSON.stringify(renderId)}. Ensure each render into a page has a unique $global.renderId.`); render.m = (effects) => { processResumes(render.r, effects); if (readyIds && render.b) for (let progress = 1; progress;) { progress = 0; for (const readyId of readyIds) { const resumes = render.b[readyId]; if (resumes && processResumes(resumes, effects)) progress = 1; } } let retained = 0; for (visit of visits = render.v) { lastTokenIndex = render.i.length; visitText = visit.data; visitType = visitText[lastTokenIndex++]; visitScope = getScope(nextToken()); if (visitType === "*") { const prev = visit.previousSibling; visitScope[nextToken()] = prev && (prev.nodeType < 8 || prev.data) ? prev : visit.parentNode.insertBefore(new Text(), visit); } else if (branchesEnabled) (visitBranches ||= createVisitBranches())(); else if (render.b) visits[retained++] = visit; } if (embedRenders && !embedAnchor && visit) embedRenders.set(embedAnchor = visit.parentNode.insertBefore(new Text(), visit.nextSibling), [renderId, scopeLookup]); visits.length = retained; return effects; }; render.w = () => { walk(); runResumeEffects(render); }; return render; }) }); }; if (renders) { initRuntime(renders); for (const renderId in renders) runResumeEffects(curRenders(renderId)); } else defineRuntime({ configurable: true, set: initRuntime }); } let isResuming; function runResumeEffects(render) { try { isResuming = 1; runEffects(render.m([]), 1); } finally { isResuming = 0; } } function getRegisteredWithScope(id, scope) { const val = registeredValues[id]; return scope ? val(scope) : val; } function _resume(id, obj) { return registeredValues[id] = obj; } function _var_resume(id, signal) { _resume(id, (scope) => (value) => signal(scope, value)); return signal; } function _el(id, accessor) { return _resume(id, (scope) => () => _el_read(scope[accessor])); } //#endregion //#region src/dom/renderer.ts function createBranch($global, renderer, parentScope, parentNode) { const branch = createScope($global); branch["_"] = renderer["owner"] || parentScope; setParentBranch(branch, parentScope?.[ClosestBranch]); branch[Renderer] = renderer; renderer[Clone]?.(branch, parentNode.namespaceURI); return branch; } function setParentBranch(branch, parentBranch) { if (parentBranch) { branch[ParentBranch] = parentBranch; (parentBranch[BranchScopes] ||= /* @__PURE__ */ new Set()).add(branch); } branch[ClosestBranch] = branch; } function createAndSetupBranch($global, renderer, parentScope, parentNode) { return setupBranch(renderer, createBranch($global, renderer, parentScope, parentNode)); } function setupBranch(renderer, branch) { if (renderer["setup"]) queueRender(branch, renderer[Setup], -1); return branch; } function _content(id, template, walks, setup, params, dynamicScopesAccessor) { walks = walks ? walks.replace(/[^\0-1]+$/, "") : ""; setup = setup ? setup._ || setup : void 0; params ||= void 0; const clone = template ? (branch, ns) => { ((cloneCache[ns] ||= {})[template] ||= createCloneableHTML(template, ns))(branch, walks); } : (branch) => { walk(branch[StartNode] = branch[EndNode] = new Text(), walks, branch); }; return (owner) => { return { ["id"]: id, [Clone]: clone, [Owner]: owner, [Setup]: setup, [Params]: params, [Accessor]: dynamicScopesAccessor }; }; } function _content_resume(id, template, walks, setup, params, dynamicScopesAccessor) { return _resume(id, _content(id, template, walks, setup, params, dynamicScopesAccessor)); } function _content_closures(renderer, closureFns) { const closureSignals = {}; for (const key in closureFns) closureSignals[key] = _const(key, closureFns[key]); return (owner, closureValues) => { const instance = renderer(owner); instance[LocalClosures] = closureSignals; instance[LocalClosureValues] = closureValues; return instance; }; } const cloneCache = {}; function createCloneableHTML(html, ns) { const { firstChild, lastChild } = parseHTML(html, ns); const parent = document.createElementNS(ns, "t"); insertChildNodes(parent, null, firstChild, lastChild); return firstChild === lastChild && firstChild.nodeType < 8 ? (branch, walks) => { walk(branch[StartNode] = branch[EndNode] = firstChild.cloneNode(true), walks, branch); } : (branch, walks) => { const clone = parent.cloneNode(true); walk(clone.firstChild, walks, branch); branch[StartNode] = clone.firstChild; branch[EndNode] = clone.lastChild; }; } //#endregion //#region src/dom/dom.ts function _to_text(value) { assertValidTextValue(value); return value || value === 0 ? value + "" : ""; } function _attr(element, name, value) { assertValidAttrValue(name, value); setAttribute(element, name, normalizeAttrValue(value)); } function setAttribute(element, name, value) { if (element.getAttribute(name) != value) if (value === void 0) element.removeAttribute(name); else element.setAttribute(name, value); } function _attr_class(element, value) { setAttribute(element, "class", toDelimitedString(value, " ", stringifyClassObject) || void 0); } function _attr_class_items(element, items) { for (const key in items) _attr_class_item(element, key, items[key]); } function _attr_class_item(element, name, value) { element.classList.toggle(name, !!value); } function _attr_style(element, value) { setAttribute(element, "style", toDelimitedString(value, ";", stringifyStyleObject) || void 0); } function _attr_style_items(element, items) { for (const key in items) _attr_style_item(element, key, items[key]); } function _attr_style_item(element, name, value) { element.style.setProperty(name, _to_text(value)); } function _style_shell(scope, nodeAccessor) { const element = scope[nodeAccessor]; const id = _id(scope); _attr_nonce(scope, nodeAccessor); element.className = id; _text_content(element, "." + id + "~*{}"); } function _style_rule_item(element, name, value) { const text = element.textContent; const decl = name + ":" + escapeStyleValue(_to_text(value)) + ";"; let start = text.indexOf("{" + name + ":"); if (!~start) start = text.indexOf(";" + name + ":"); _text_content(element, ~start ? text.slice(0, ++start) + decl + text.slice(text.indexOf(";", start) + 1) : text.slice(0, -1) + decl + "}"); } function _attr_nonce(scope, nodeAccessor) { _attr(scope[nodeAccessor], "nonce", scope[Global].cspNonce); } function _text(node, value) { const normalizedValue = _to_text(value); if (node.data !== normalizedValue) node.data = normalizedValue; } function _text_content(node, value) { const normalizedValue = _to_text(value); if (node.textContent !== normalizedValue) node.textContent = normalizedValue; } function _attrs(scope, nodeAccessor, nextAttrs, controllable) { const el = scope[nodeAccessor]; for (let i = el.attributes.length; i--;) { const { name } = el.attributes.item(i); if (!(nextAttrs && (name in nextAttrs || hasAttrAlias(el, name, nextAttrs)))) el.removeAttribute(name); } assertExclusiveAttrs(nextAttrs); attrsInternal(scope, nodeAccessor, nextAttrs, controllable); } function _attrs_content(scope, nodeAccessor, nextAttrs, controllable) { _attrs(scope, nodeAccessor, nextAttrs, controllable); _attr_content(scope, nodeAccessor, nextAttrs?.content); } function hasAttrAlias(element, attr, nextAttrs) { return attr === "checked" && element.tagName === "INPUT" && "checkedValue" in nextAttrs; } function _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable) { const el = scope[nodeAccessor]; const partial = {}; for (let i = el.attributes.length; i--;) { const { name } = el.attributes.item(i); if (!skip[name] && !(nextAttrs && name in nextAttrs)) el.removeAttribute(name); } for (const name in nextAttrs) { const key = isEventHandler(name) ? `on-${getEventHandlerName(name)}` : name; if (!skip[key]) partial[key] = nextAttrs[name]; } assertExclusiveAttrs({ ...nextAttrs, ...skip }); attrsInternal(scope, nodeAccessor, partial, controllable); } function _attrs_partial_content(scope, nodeAccessor, nextAttrs, skip, controllable) { _attrs_partial(scope, nodeAccessor, nextAttrs, skip, controllable); _attr_content(scope, nodeAccessor, nextAttrs?.content); } function attrsInternal(scope, nodeAccessor, nextAttrs, controllable) { const el = scope[nodeAccessor]; let events = scope[EventAttributes + nodeAccessor]; let skip = void 0; for (const name in events) events[name] = 0; if (controllable) { scope[ControlledType + nodeAccessor] = 5; scope[ControlledHandler + nodeAccessor] = 0; if (nextAttrs) skip = controllable(scope, nodeAccessor, nextAttrs); } for (const name in nextAttrs) { const value = nextAttrs[name]; switch (name) { case "class": _attr_class(el, value); break; case "style": _attr_style(el, value); break; default: assertValidAttrName(name); if (isEventHandler(name)) (events ||= scope[EventAttributes + nodeAccessor] = {})[getEventHandlerName(name)] = value; else if (!(skip?.test(name) || name === "content" && el.tagName !== "META")) _attr(el, name, value); break; } } } function _attr_content(scope, nodeAccessor, value) { const content = normalizeClientRender(value); if (scope["ConditionalRenderer:" + nodeAccessor] !== (scope["ConditionalRenderer:" + nodeAccessor] = content?.["id"])) { setConditionalRenderer(scope, nodeAccessor, content, createAndSetupBranch); if (content?.["accessor"]) subscribeToScopeSet(content[Owner], content[Accessor], scope[BranchScopes$1 + nodeAccessor]); } for (const accessor in content?.[LocalClosures]) content[LocalClosures][accessor](scope[BranchScopes$1 + nodeAccessor], content[LocalClosureValues][accessor]); } function _attrs_script(scope, nodeAccessor) { const el = scope[nodeAccessor]; const events = scope[EventAttributes + nodeAccessor]; controllableScripts[scope[ControlledType + nodeAccessor]]?.(scope, nodeAccessor); for (const name in events) _on(el, name, events[name]); } function _html(scope, value, accessor) { const firstChild = scope[accessor]; const parentNode = firstChild.parentNode; const lastChild = scope["DynamicHTMLLastChild:" + accessor] || firstChild; const newContent = parseHTML(_to_text(value), parentNode.namespaceURI); insertChildNodes(parentNode, firstChild, scope[accessor] = newContent.firstChild || newContent.appendChild(new Text()), scope[DynamicHTMLLastChild + accessor] = newContent.lastChild); removeChildNodes(firstChild, lastChild); } function normalizeClientRender(value) { const renderer = normalizeDynamicRenderer(value); if (renderer) if (renderer["id"]) return renderer; else throw new Error(`Invalid \`content\` attribute. Received ${typeof value}`); } function normalizeAttrValue(value) { if (isNotVoid(value)) return value === true ? "" : value + ""; } function _lifecycle(scope, thisObj, index = 0) { const accessor = Lifecycle + index; const instance = scope[accessor]; if (instance) { Object.assign(instance, thisObj); instance.onUpdate?.(); } else { scope[accessor] = thisObj; { const snapshot = { ...thisObj }; Object.assign(thisObj, thisObj.onMount?.()); for (const prop in snapshot) if (!Object.is(snapshot[prop], thisObj[prop])) throw new Error(`Tried to overwrite existing property "${prop}" in <lifecycle> onMount.`); } $signal(scope, accessor).onabort = () => thisObj.onDestroy?.(); } } function removeChildNodes(startNode, endNode) { const stop = endNode.nextSibling; while (startNode !== stop) { const next = startNode.nextSibling; startNode.remove(); startNode = next; } } function insertChildNodes(parentNode, referenceNode, startNode, endNode) { if (parentNode.isConnected) parentNode.insertBefore(toInsertNode(startNode, endNode), referenceNode); else { const stop = endNode.nextSibling; while (startNode !== stop) { const next = startNode.nextSibling; parentNode.insertBefore(startNode, referenceNode); startNode = next; } } return parentNode; } function toInsertNode(startNode, endNode) { return startNode === endNode ? startNode : insertChildNodes(new DocumentFragment(), null, startNode, endNode); } //#endregion //#region src/dom/resolve-cursor-position.ts const R = /[^\p{L}\p{N}]/gu; function resolveCursorPosition(inputType, initialPosition, initialValue, updatedValue) { if ((initialPosition || initialPosition === 0) && (initialPosition !== initialValue.length || /kw/.test(inputType))) { const before = initialValue.slice(0, initialPosition); const after = initialValue.slice(initialPosition); if (updatedValue.startsWith(before)) return initialPosition; if (updatedValue.endsWith(after)) return updatedValue.length - after.length; let count = before.replace(R, "").length; let pos = 0; while (count && updatedValue[pos]) if (updatedValue[pos++].replace(R, "")) count--; return pos; } return -1; } //#endregion //#region src/dom/controllable.ts let inputType = ""; function _attr_input_checked_default(scope, nodeAccessor, checked) { const el = scope[nodeAccessor]; const normalizedChecked = isNotVoid(checked); if (el.defaultChecked !== normalizedChecked) { const restoreValue = scope["#Gen"] < runId ? el.checked : normalizedChecked; el.defaultChecked = normalizedChecked; if (restoreValue !== normalizedChecked) el.checked = restoreValue; } } /** Filled by the latches a compiled page emits, so a page carries only the * control kinds its tags can be (`_attrs_script` resolves the kind at run time). */ const controllableScripts = {}; /** The render pass equivalent, for a tag whose name is only known at run time; * a statically named tag passes its claim to `_attrs` instead. */ const controllableRenders = {}; function _enable_controllable_input() { controllableScripts[0] = _attr_input_checked_script; controllableScripts[1] = _attr_input_checkedValue_script; controllableScripts[2] = _attr_input_value_script; } function _enable_controllable_textarea() { controllableScripts[2] = _attr_input_value_script; } function _enable_controllable_select() { controllableScripts[3] = _attr_select_value_script; } function _enable_controllable_open() { controllableScripts[4] = _attr_details_or_dialog_open_script; } /** A run-time tag name can be any controllable, so its page enables them all. */ function _enable_controllable() { _enable_controllable_input(); _enable_controllable_select(); _enable_controllable_open(); controllableRenders.INPUT = _controllable_input; controllableRenders.TEXTAREA = _controllable_textarea; controllableRenders.SELECT = _controllable_select; controllableRenders.DETAILS = controllableRenders.DIALOG = _controllable_open; } function _attr_input_checked(scope, nodeAccessor, checked, checkedChange) { const el = scope[nodeAccessor]; const normalizedChecked = isNotVoid(checked); assertHandlerIsFunction("checkedChange", checkedChange); scope[ControlledHandler + nodeAccessor] = checkedChange; scope[ControlledType + nodeAccessor] = checkedChange ? 0 : 5; if (checkedChange && scope["#Gen"] < runId) el.checked = normalizedChecked; else _attr_input_checked_default(scope, nodeAccessor, normalizedChecked); } function _attr_input_checked_script(scope, nodeAccessor) { const el = scope[nodeAccessor]; syncControllableFormInput(el, hasCheckboxChanged, () => { const checkedChange = scope[ControlledHandler + nodeAccessor]; if (checkedChange) { const newValue = el.checked; el.checked = !newValue; checkedChange(newValue); run(); } }); } function _attr_input_checkedValue_default(scope, nodeAccessor, checkedValue, value) { const multiple = Array.isArray(checkedValue); const normalizedValue = normalizeStrProp(value); const normalizedCheckedValue = multiple ? checkedValue.map(normalizeStrProp) : normalizeStrProp(checkedValue); _attr(scope[nodeAccessor], "value", value); _attr_input_checked_default(scope, nodeAccessor, multiple ? normalizedCheckedValue.includes(normalizedValue) : normalizedValue === normalizedCheckedValue); } function _attr_input_checkedValue(scope, nodeAccessor, checkedValue, checkedValueChange, value) { const el = scope[nodeAccessor]; const multiple = Array.isArray(checkedValue); const normalizedCheckedValue = scope[ControlledValue + nodeAccessor] = multiple ? checkedValue.map(normalizeStrProp) : normalizeStrProp(checkedValue); assertHandlerIsFunction("checkedValueChange", checkedValueChange); scope[ControlledHandler + nodeAccessor] = checkedValueChange; scope[ControlledType + nodeAccessor] = checkedValueChange ? 1 : 5; if (checkedValueChange && scope["#Gen"] < runId) { el.checked = multiple ? normalizedCheckedValue.includes(normalizeStrProp(value)) : normalizeStrProp(value) === normalizedCheckedValue; _attr(el, "value", value); } else _attr_input_checkedValue_default(scope, nodeAccessor, checkedValue, value); } function _attr_input_checkedValue_script(scope, nodeAccessor) { const el = scope[nodeAccessor]; if (isResuming && el.defaultChecked) if (scope["ControlledValue:" + nodeAccessor]) scope[ControlledValue + nodeAccessor].push(el.value); else scope[ControlledValue + nodeAccessor] = el.value; syncControllableFormInput(el, hasCheckboxChanged, () => { const checkedValueChange = scope[ControlledHandler + nodeAccessor]; if (checkedValueChange) { const controlledValueKey = ControlledValue + nodeAccessor; const oldValue = scope[controlledValueKey]; let newValue = Array.isArray(oldValue) ? updateList(oldValue, el.value, el.checked) : el.checked ? el.value : void 0; if (el.name && el.type[0] === "r") { for (const radio of document.querySelectorAll(`[type=radio][name=${CSS.escape(el.name)}]`)) if (radio.form === el.form) { if (newValue === void 0 && radio.defaultChecked) newValue = radio.value;