diff --git a/dist/_hyperscript-max.js b/dist/_hyperscript-max.js
index 5f3000b32..53f580bd8 100644
--- a/dist/_hyperscript-max.js
+++ b/dist/_hyperscript-max.js
@@ -4185,8 +4185,8 @@
parser.raiseError("Cannot take a property of a non-symbol: " + urRoot.type);
}
var attribute = urRoot.type === "attributeRef";
- var style = urRoot.type === "styleRef" || urRoot.type === "computedStyleRef";
- var attributeElt = attribute || style ? urRoot : null;
+ var style2 = urRoot.type === "styleRef" || urRoot.type === "computedStyleRef";
+ var attributeElt = attribute || style2 ? urRoot : null;
var prop = urRoot.name;
var propertyAccess = new _OfExpression(
urRoot.token,
@@ -4272,15 +4272,15 @@
if (apostrophe) {
parser.requireToken("s");
}
- var attribute, style, prop;
+ var attribute, style2, prop;
attribute = parser.parseElement("attributeRef");
if (attribute == null) {
- style = parser.parseElement("styleRef");
- if (style == null) {
+ style2 = parser.parseElement("styleRef");
+ if (style2 == null) {
prop = parser.requireTokenType("IDENTIFIER");
}
}
- var propertyAccess = new _PossessiveExpression(root, attribute || style, prop);
+ var propertyAccess = new _PossessiveExpression(root, attribute || style2, prop);
return parser.parseElement("indirectExpression", propertyAccess);
}
}
@@ -9101,7 +9101,18 @@
return new _BreakpointCommand();
}
resolve(ctx) {
- debugger;
+ var handled = false;
+ if (config.debugMode) {
+ var runtime2 = ctx.meta.runtime;
+ var target = ctx.meta.owner || ctx.me;
+ handled = !runtime2.triggerEvent(target, "hyperscript:breakpoint", {
+ command: this,
+ ctx
+ });
+ }
+ if (!handled) {
+ debugger;
+ }
return this.findNext(ctx);
}
};
@@ -10564,14 +10575,701 @@
self._hyperscript = _hyperscript;
}
+ // src/ext/debugger.module.css
+ var debugger_default = `@scope (#hs-debugger) {
+
+ :scope {
+ all: initial;
+ display: block;
+ position: fixed;
+ z-index: 2147483647;
+ overflow: auto;
+ overscroll-behavior: none;
+ font-family: "IBM Plex Sans", -apple-system, "Segoe UI", system-ui, sans-serif;
+ font-size: 13px;
+ color: #222;
+ line-height: 1.4;
+ }
+
+ :scope.hs-bottom {
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: 320px;
+ }
+
+ :scope.hs-right {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 420px;
+ }
+
+ :scope.hs-hidden {
+ display: none !important;
+ }
+
+ .d-root {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ background: #fff;
+ border-top: 2px solid #b0b0b0;
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, .12);
+ }
+
+ :scope.hs-right .d-root {
+ border-top: none;
+ border-left: 2px solid #b0b0b0;
+ box-shadow: -2px 0 8px rgba(0, 0, 0, .12);
+ }
+
+ .d-resize {
+ position: absolute;
+ z-index: 1;
+ }
+
+ :scope.hs-bottom .d-resize {
+ top: -4px;
+ left: 0;
+ right: 0;
+ height: 8px;
+ cursor: ns-resize;
+ }
+
+ :scope.hs-right .d-resize {
+ top: 0;
+ left: -4px;
+ bottom: 0;
+ width: 8px;
+ cursor: ew-resize;
+ }
+
+ .d-resize:hover {
+ background: #4a84c4;
+ opacity: .3;
+ }
+
+ .d-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ padding: 3px 10px;
+ background: #ebebeb;
+ border-bottom: 1px solid #b0b0b0;
+ user-select: none;
+ flex-shrink: 0;
+ }
+
+ .d-logo {
+ height: 32px;
+ width: auto;
+ margin-right: 8px;
+ }
+
+ .d-title {
+ font-family: system-ui, sans-serif;
+ font-size: 20px;
+ font-weight: bold;
+ margin-right: auto;
+ }
+
+ .d-title em {
+ color: #4a84c4;
+ font-style: normal;
+ }
+
+ .d-btn {
+ background: none;
+ border: 1px solid #d4d4d4;
+ color: #666;
+ cursor: pointer;
+ padding: 2px 8px;
+ border-radius: 3px;
+ font: inherit;
+ font-size: 12px;
+ }
+
+ .d-btn:hover {
+ color: #222;
+ background: #e0e8f4;
+ border-color: #b0b0b0;
+ }
+
+ .d-btn.active {
+ color: #4a84c4;
+ background: #e8f0fb;
+ border-color: #4a84c4;
+ }
+
+ .d-dock {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 3px 6px;
+ line-height: 0;
+ }
+
+ .d-dock svg {
+ display: block;
+ }
+
+ .d-btn-close {
+ font-size: 16px;
+ padding: 0 4px;
+ margin-left: 4px;
+ border: none
+ }
+
+ /* Body lays out four panes inline (bottom dock) or stacked (right dock):
+ list \xB7 split \xB7 detail \xB7 split \xB7 timeline \xB7 split \xB7 console.
+ Track sizes are set inline by the splitter logic; this is the fallback. */
+ .d-body {
+ display: grid;
+ grid-template-columns: 200px 6px 1fr 6px 260px 6px 300px;
+ flex: 1;
+ overflow: hidden;
+ min-height: 0
+ }
+
+ :scope.hs-right .d-body {
+ grid-template-columns: 1fr;
+ grid-template-rows: 200px 6px 1fr 6px 260px 6px 300px
+ }
+
+ .d-el-list {
+ min-width: 0;
+ min-height: 0;
+ border-right: 1px solid #d4d4d4;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden
+ }
+
+ :scope.hs-right .d-el-list {
+ border-right: none;
+ border-bottom: 1px solid #d4d4d4
+ }
+
+ .d-el-search {
+ display: block;
+ box-sizing: border-box;
+ padding: 4px 8px;
+ margin: 6px;
+ width: calc(100% - 12px);
+ border: 1px solid #8a8a8a;
+ border-radius: 3px;
+ background: #fff;
+ color: #222;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 11px;
+ outline: none;
+ flex-shrink: 0;
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, .28)
+ }
+
+ .d-el-search::placeholder {
+ color: #999
+ }
+
+ .d-el-search:focus {
+ border-color: #4a84c4;
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, .28), 0 0 0 2px rgba(74, 132, 196, .25)
+ }
+
+ .d-el-items {
+ flex: 1;
+ min-height: 0;
+ overflow-y: auto
+ }
+
+ .d-el-item {
+ padding: 4px 10px;
+ cursor: pointer;
+ border-bottom: 1px solid #d4d4d4;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 12px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis
+ }
+
+ .d-el-item:hover {
+ background: #e0e8f4
+ }
+
+ .d-el-item.selected {
+ background: #4a84c4;
+ color: #fff
+ }
+
+ .d-el-item.selected :is(.d-tag,.d-id,.d-cls) {
+ color: inherit
+ }
+
+ .d-tag {
+ color: #4a84c4
+ }
+
+ .d-id {
+ color: #2b6b1f
+ }
+
+ .d-cls {
+ color: #8a6d00
+ }
+
+ .d-detail {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ overflow: hidden
+ }
+
+ /* Persistent, always-visible debug toolbar row pinned at the top of the
+ detail pane. Never wiped or moved, so the controls stay put. */
+ .d-detail-toolbar {
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 10px;
+ border-bottom: 1px solid #e2e2e2;
+ background: #f4f4f4
+ }
+
+ /* Scrollable area below the toolbar that selectElement/resetDetail rebuild. */
+ .d-detail-content {
+ flex: 1 1 auto;
+ overflow-y: auto;
+ padding: 10px;
+ min-height: 0;
+ display: flex;
+ flex-direction: column
+ }
+
+ .d-dbg-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ min-height: 26px;
+ margin: 12px 0 6px
+ }
+
+ .d-dbg-toolbar .d-label {
+ margin: 0
+ }
+
+ .d-dbg-btns {
+ display: flex;
+ gap: 2px
+ }
+
+ :scope.hs-right .d-detail {
+ min-width: auto
+ }
+
+ .d-code {
+ white-space: pre-wrap;
+ word-break: break-word;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 12px;
+ line-height: 1.5;
+ padding: 8px;
+ background: #f6f6f6;
+ border-radius: 4px;
+ border: 1px solid #d4d4d4
+ }
+
+ .d-code-area {
+ display: flex;
+ flex: 1;
+ min-height: 80px;
+ gap: 8px
+ }
+
+ .d-editor {
+ flex: 1;
+ border: 1px solid #d4d4d4;
+ border-radius: 4px;
+ overflow: hidden
+ }
+
+ @keyframes hs-dbg-flash {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(255, 200, 80, 0)
+ }
+
+ 25% {
+ box-shadow: 0 0 0 4px rgba(255, 200, 80, .85)
+ }
+
+ 100% {
+ box-shadow: 0 0 0 0 rgba(255, 200, 80, 0)
+ }
+ }
+
+ .d-editor.hs-dbg-flash {
+ animation: hs-dbg-flash .5s ease-out
+ }
+
+ :scope.hs-paused .d-editor {
+ border-color: #4a84c4;
+ box-shadow: 0 0 0 2px rgba(74, 132, 196, .5)
+ }
+
+ .d-label {
+ font-family: system-ui, sans-serif;
+ font-size: 11px;
+ color: #666;
+ text-transform: uppercase;
+ letter-spacing: .05em;
+ margin: 0 0 4px
+ }
+
+ .d-label+.d-label,
+ .d-code+.d-label {
+ margin-top: 12px
+ }
+
+ .d-console {
+ display: flex;
+ flex-direction: column;
+ border-left: 2px solid #b0b0b0;
+ background: #1a0e00;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ cursor: text
+ }
+
+ :scope.hs-right .d-console {
+ border-left: none;
+ border-top: 2px solid #b0b0b0
+ }
+
+ .d-con-scroll {
+ flex: 1;
+ min-height: 0;
+ overflow-y: auto
+ }
+
+ .d-con-out {
+ padding: 6px 10px;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 13px;
+ font-weight: 700;
+ color: #ffe060;
+ background-image: repeating-linear-gradient(0deg, transparent, transparent 10px, rgba(255, 160, 30, .06) 10px, rgba(255, 160, 30, .06) 20px);
+ background-attachment: local
+ }
+
+ .d-con-entry {
+ padding: 3px 0
+ }
+
+ .d-con-in {
+ display: flex;
+ align-items: center;
+ padding: 2px 10px 6px
+ }
+
+ .d-prompt {
+ padding: 0 6px 0 0;
+ color: #ffdd60;
+ font-family: system-ui, sans-serif;
+ user-select: none;
+ font-size: 13px;
+ font-weight: 700;
+ line-height: 1.5;
+ white-space: nowrap
+ }
+
+ .d-input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: #ffdd60;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 13px;
+ font-weight: 700;
+ padding: 0;
+ outline: none;
+ caret-color: #ffdd60
+ }
+
+ .d-log-input {
+ color: #ffdd60;
+ font-weight: 700
+ }
+
+ .d-log-result {
+ color: #ffdd60;
+ font-weight: 700
+ }
+
+ .d-log-error {
+ color: #ff6040;
+ font-weight: 700
+ }
+
+ .d-log-coll {
+ color: #ffdd60;
+ font-weight: 700
+ }
+
+ .d-log-coll-item {
+ padding: 1px 0 1px 12px;
+ cursor: pointer;
+ color: #ffdd60;
+ font-weight: 700
+ }
+
+ .d-log-coll-item:hover {
+ text-decoration: underline
+ }
+
+ /* Generic pane splitter \u2014 col-resize in horizontal (bottom) dock,
+ row-resize in vertical (right) dock. */
+ .d-split {
+ cursor: col-resize;
+ background: #b0b0b0
+ }
+
+ .d-split:hover {
+ background: #4a84c4
+ }
+
+ :scope.hs-right .d-split {
+ cursor: row-resize
+ }
+
+ .d-empty {
+ color: #666;
+ text-align: center;
+ padding: 20px;
+ font-family: system-ui, sans-serif;
+ font-size: 12px
+ }
+
+ .d-dbg-btn {
+ background: #fff;
+ border: 1px solid #c0c0c0;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .1);
+ cursor: pointer;
+ padding: 3px 8px;
+ border-radius: 3px;
+ font-size: 13px;
+ line-height: 1;
+ color: #888
+ }
+
+ .d-dbg-btn:hover:not(:disabled) {
+ background: #f4f4f4;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, .15)
+ }
+
+ .d-dbg-btn:active:not(:disabled) {
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .12)
+ }
+
+ .d-dbg-btn:disabled {
+ opacity: .4;
+ cursor: default;
+ box-shadow: none
+ }
+
+ .d-step,
+ .d-continue,
+ .d-step-back,
+ .d-step-over {
+ color: #2b8a3e
+ }
+
+ .d-stop {
+ color: #c03030
+ }
+
+ .hs-dbg-bp-glyph {
+ background: #c03030;
+ border-radius: 50%;
+ width: 10px !important;
+ height: 10px !important;
+ margin-top: 4px;
+ margin-left: 4px
+ }
+
+ .hs-dbg-bp-line {
+ background: rgba(192, 48, 48, .1)
+ }
+
+ .hs-dbg-current-line {
+ background: rgba(255, 210, 60, .6) !important
+ }
+
+ .hs-dbg-current-glyph {
+ background: #ffc850;
+ border-radius: 2px;
+ width: 10px !important;
+ height: 10px !important;
+ margin-top: 4px;
+ margin-left: 4px
+ }
+
+ /* ============================================================ */
+ /* Timeline panel */
+ /* ============================================================ */
+
+ /* Timeline is one of the four panes in .d-body. Fills its grid track. */
+ .d-timeline {
+ display: flex;
+ flex-direction: column;
+ background: #fafafa;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ }
+
+ .d-tl-hdr {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 8px;
+ background: #ececec;
+ border-bottom: 1px solid #ddd;
+ flex: 0 0 auto;
+ }
+
+ .d-tl-title {
+ font-size: 11px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: .05em;
+ color: #555;
+ }
+
+ .d-tl-spacer {
+ flex: 1;
+ }
+
+ .d-tl-btn {
+ all: unset;
+ cursor: pointer;
+ font-size: 11px;
+ padding: 2px 8px;
+ border-radius: 3px;
+ background: #fff;
+ border: 1px solid #ccc;
+ color: #444;
+ }
+
+ .d-tl-btn:hover {
+ background: #4a84c4;
+ border-color: #4a84c4;
+ color: #fff;
+ }
+
+ .d-tl-body {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ min-height: 0;
+ overflow: hidden;
+ }
+
+ /* Vertical, scrollable list filling the timeline body. */
+ .d-tl-track-wrap {
+ flex: 1;
+ min-height: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ background: #f3f3f3;
+ }
+
+ .d-tl-track {
+ display: flex;
+ flex-direction: column;
+ padding: 4px 0;
+ }
+
+ .d-tl-tick {
+ all: unset;
+ cursor: pointer;
+ display: flex;
+ align-items: baseline;
+ gap: 8px;
+ font-family: "IBM Plex Mono", "SF Mono", "Consolas", monospace;
+ font-size: 11px;
+ padding: 3px 10px;
+ border-left: 2px solid transparent;
+ color: #444;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .d-tl-tick:hover {
+ background: #e6eef7;
+ color: #2b4a6b;
+ }
+
+ .d-tl-tick-idx {
+ color: #999;
+ font-size: 10px;
+ flex: 0 0 auto;
+ min-width: 28px;
+ }
+
+ .d-tl-tick-src {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex: 1 1 auto;
+ }
+
+ .d-tl-tick.async .d-tl-tick-idx::after {
+ content: ' \\2933';
+ }
+
+ .d-tl-tick.err {
+ background: #fbe9e9;
+ color: #c03030;
+ }
+
+ .d-tl-tick.err .d-tl-tick-idx {
+ color: #c03030;
+ }
+
+ .d-tl-tick.selected {
+ background: #ffc850;
+ color: #5a4500;
+ font-weight: 600;
+ }
+
+ .d-tl-tick.selected .d-tl-tick-idx {
+ color: #5a4500;
+ }
+
+ .d-tl-tick.current {
+ border-left-color: #4a84c4;
+ }
+
+ .d-tl-empty {
+ padding: 6px 8px;
+ color: #999;
+ font-size: 11px;
+ }
+
+}
+`;
+
+ // src/ext/debugger-logo.b64
+ var debugger_logo_default = "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\n";
+
// src/ext/debugger.js
- var DEFAULT_MAX_STEPS = 1e4;
- function getMaxSteps() {
- if (typeof location === "undefined") return DEFAULT_MAX_STEPS;
- const params = new URLSearchParams(location.search);
- const max = parseInt(params.get("_ttd_max"));
- return isNaN(max) ? DEFAULT_MAX_STEPS : max;
- }
+ var style = document.createElement("style");
+ style.textContent = debugger_default;
+ document.head.appendChild(style);
+ var MAX_STEPS = 1e4;
var _idCounter = 0;
function generateStreamId(ctx) {
const feature = ctx.meta.feature;
@@ -10615,35 +11313,6 @@
you: ctx.you
};
}
- function summarizeValue(value, maxLength) {
- maxLength = maxLength || 60;
- if (value === null) return "null";
- if (value === void 0) return "undefined";
- if (typeof value === "string") {
- const truncated = value.length > maxLength ? value.substring(0, maxLength - 3) + "..." : value;
- return '"' + truncated + '"';
- }
- if (typeof value === "number" || typeof value === "boolean") return String(value);
- if (typeof value === "function") {
- return value.hyperfunc ? "def " + (value.hypername || "(anonymous)") : "function " + (value.name || "(anonymous)");
- }
- if (typeof Element !== "undefined" && value instanceof Element) {
- return elementDescription(value);
- }
- if (Array.isArray(value)) {
- return "Array(" + value.length + ")";
- }
- if (value && value.constructor === Object) {
- const keys = Object.keys(value);
- return "{" + keys.slice(0, 3).join(", ") + (keys.length > 3 ? ", ..." : "") + "}";
- }
- try {
- const s = String(value);
- return s.length > maxLength ? s.substring(0, maxLength - 3) + "..." : s;
- } catch {
- return "[object]";
- }
- }
function enrichMutations(records) {
return records.map((record, i, arr) => {
const enriched = {
@@ -10897,12 +11566,12 @@
constructor(timeline, mutationBatcher) {
this._timeline = timeline;
this._batcher = mutationBatcher;
- this._streams = /* @__PURE__ */ new Map();
this._stepCounter = 0;
this._pendingSnapshot = null;
this._pendingGapMutations = [];
this.active = true;
this.timeTraveling = false;
+ this.onStep = null;
}
/** Attach event listeners to capture execution steps */
install() {
@@ -10910,7 +11579,6 @@
const { command, ctx } = evt.detail;
if (!ctx.meta.ttd_streamId) {
ctx.meta.ttd_streamId = generateStreamId(ctx);
- this._registerStream(ctx);
}
if (this.timeTraveling) {
evt.preventDefault();
@@ -10938,7 +11606,6 @@
const afterSnapshot = captureSnapshot(ctx);
const step = {
index: this._stepCounter++,
- streamId: ctx.meta.ttd_streamId,
timestamp: performance.now(),
// Command info
commandType: command.type || "unknown",
@@ -10956,19 +11623,15 @@
error: error || null
};
this._timeline.push(step);
+ if (this.onStep) {
+ try {
+ this.onStep(step);
+ } catch (e) {
+ }
+ }
this._pendingSnapshot = null;
this._pendingGapMutations = [];
}
- _registerStream(ctx) {
- const id = ctx.meta.ttd_streamId;
- this._streams.set(id, {
- id,
- featureName: ctx.meta.feature ? ctx.meta.feature.displayName || null : null,
- ownerElement: ctx.meta.owner || null,
- eventType: ctx.event ? ctx.event.type : null,
- startStep: this._stepCounter
- });
- }
};
function _safeSourceFor(command) {
try {
@@ -11000,66 +11663,13 @@
get length() {
return this._timeline.length;
}
- /** Whether recording is active */
- get recording() {
- return this._recorder.active && !this._recorder.timeTraveling;
- }
- /** Whether currently in time travel mode */
- get traveling() {
- return this._recorder.timeTraveling;
- }
- /** Max steps in ring buffer */
- get maxSteps() {
- return this._timeline.maxSize;
- }
// ==================================================================
// Navigation — Time Travel
// ==================================================================
- /** Step backward n steps with DOM restoration */
- back(n) {
- n = n || 1;
- this._enterTimeTravelIfNeeded();
- const targetPos = this._position - n;
- if (targetPos < this._timeline.firstIndex) {
- console.warn("[ttd] Cannot go back further \u2014 at the beginning of the timeline");
- return this;
- }
- for (let i = this._position; i > targetPos; i--) {
- const step = this._timeline.getStep(i);
- if (step) this._restorer.undoStep(step);
- }
- this._position = targetPos;
- this._printPosition();
- return this;
- }
- /** Step forward n steps with DOM restoration */
- forward(n) {
- n = n || 1;
- if (!this._recorder.timeTraveling) {
- console.log("[ttd] Not in time travel mode. Nothing to step forward to.");
- return this;
- }
- const targetPos = this._position + n;
- const maxPos = this._timeline.lastIndex;
- if (targetPos > maxPos) {
- console.warn("[ttd] Cannot go forward further \u2014 at the end of the timeline");
- return this;
- }
- for (let i = this._position + 1; i <= targetPos; i++) {
- const step = this._timeline.getStep(i);
- if (step) this._restorer.redoStep(step);
- }
- this._position = targetPos;
- this._printPosition();
- return this;
- }
- /** Jump to a specific step index with DOM restoration */
+ /** Jump to a specific step index with DOM restoration. Returns true on success. */
goto(n) {
if (n < this._timeline.firstIndex || n > this._timeline.lastIndex) {
- console.error(
- "[ttd] Step " + n + " is out of range. Valid range: " + this._timeline.firstIndex + " - " + this._timeline.lastIndex
- );
- return this;
+ return false;
}
this._enterTimeTravelIfNeeded();
if (n < this._position) {
@@ -11074,14 +11684,12 @@
}
}
this._position = n;
- this._printPosition();
- return this;
+ return true;
}
- /** Exit time travel mode and return to live state */
+ /** Exit time travel mode and return to live state. Returns true on success. */
resume() {
if (!this._recorder.timeTraveling) {
- console.log("[ttd] Not in time travel mode.");
- return this;
+ return false;
}
const latest = this._timeline.lastIndex;
if (this._position < latest) {
@@ -11093,456 +11701,33 @@
this._position = -1;
this._recorder.timeTraveling = false;
this._recorder.active = true;
- console.log("[ttd] Resumed live execution. Recording active.");
- return this;
- }
- /** Enter time-travel mode at the current end of the recorded timeline (public). */
- enter() {
- this._enterTimeTravelIfNeeded();
- return this;
+ return true;
}
_enterTimeTravelIfNeeded() {
if (!this._recorder.timeTraveling) {
this._recorder.timeTraveling = true;
this._recorder.active = false;
this._position = this._timeline.lastIndex;
- console.log("[ttd] Entered time travel mode. Execution paused.");
- }
- }
- _printPosition() {
- const step = this._timeline.getStep(this._position);
- if (!step) {
- console.log("[ttd] Position: " + this._position + " (no step data)");
- return;
}
- const total = this._timeline.length;
- const offset = this._position - this._timeline.firstIndex;
- console.log(
- "[ttd] Step " + step.index + " (" + (offset + 1) + "/" + total + ") [" + step.streamId + "] " + step.commandSource.trim()
- );
- }
- // ==================================================================
- // Inspection
- // ==================================================================
- /** Show detailed info about a step */
- inspect(n) {
- const step = this._resolveStep(n);
- if (!step) return void 0;
- console.group(
- "Step " + step.index + " [" + step.streamId + "] " + (step.error ? "[ERROR] " : "") + (step.isAsync ? "[async] " : "")
- );
- console.log("Command: " + step.commandSource.trim());
- console.log("Type: " + step.commandType);
- if (step.featureName) console.log("Feature: " + step.featureName);
- if (step.ownerElement) console.log("Owner: " + elementDescription(step.ownerElement));
- if (step.line) console.log("Line: " + step.line);
- console.log("Time: " + step.timestamp.toFixed(2) + "ms");
- if (step.error) {
- console.error("Error:", step.error);
- }
- const beforeLocals = step.snapshotBefore.locals;
- const afterLocals = step.snapshotAfter.locals;
- const allKeys = /* @__PURE__ */ new Set([...Object.keys(beforeLocals), ...Object.keys(afterLocals)]);
- if (allKeys.size > 0) {
- const rows = [];
- for (const key of allKeys) {
- const before = beforeLocals[key];
- const after = afterLocals[key];
- rows.push({
- Variable: key,
- Before: summarizeValue(before),
- After: summarizeValue(after),
- Changed: before !== after ? "YES" : ""
- });
- }
- console.log("--- Locals ---");
- console.table(rows);
- for (const key of allKeys) {
- const after = afterLocals[key];
- if (after !== null && after !== void 0 && typeof after === "object") {
- console.log(" " + key + ":", after);
- }
- }
- }
- if (step.snapshotBefore.result !== step.snapshotAfter.result) {
- console.log(
- "Result: " + summarizeValue(step.snapshotBefore.result) + " -> " + summarizeValue(step.snapshotAfter.result)
- );
- const afterResult = step.snapshotAfter.result;
- if (afterResult !== null && afterResult !== void 0 && typeof afterResult === "object") {
- console.log(" result:", afterResult);
- }
- }
- if (step.mutations.length > 0) {
- console.log("--- DOM Mutations (" + step.mutations.length + ") ---");
- for (const m of step.mutations) {
- this._logMutation(m);
- }
- }
- console.groupEnd();
- return step;
- }
- /** Show local variables at a step */
- locals(n) {
- const step = this._resolveStep(n);
- if (!step) return void 0;
- const after = step.snapshotAfter.locals;
- const keys = Object.keys(after);
- if (keys.length === 0) {
- console.log("[ttd] No locals at step " + step.index);
- } else {
- console.group("[ttd] Locals at step " + step.index + ":");
- for (const key of keys) {
- console.log(" " + key + ":", after[key]);
- }
- console.groupEnd();
- }
- return after;
- }
- /** Show what changed at a step compared to the previous step */
- diff(n) {
- const step = this._resolveStep(n);
- if (!step) return void 0;
- const changes = [];
- const before = step.snapshotBefore.locals;
- const after = step.snapshotAfter.locals;
- const allKeys = /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)]);
- for (const key of allKeys) {
- if (before[key] !== after[key]) {
- changes.push({
- What: "local:" + key,
- Before: summarizeValue(before[key]),
- After: summarizeValue(after[key])
- });
- }
- }
- if (step.snapshotBefore.result !== step.snapshotAfter.result) {
- changes.push({
- What: "result",
- Before: summarizeValue(step.snapshotBefore.result),
- After: summarizeValue(step.snapshotAfter.result)
- });
- }
- if (step.snapshotBefore.me !== step.snapshotAfter.me) {
- changes.push({
- What: "me",
- Before: elementDescription(step.snapshotBefore.me),
- After: elementDescription(step.snapshotAfter.me)
- });
- }
- if (step.snapshotBefore.you !== step.snapshotAfter.you) {
- changes.push({
- What: "you",
- Before: elementDescription(step.snapshotBefore.you),
- After: elementDescription(step.snapshotAfter.you)
- });
- }
- for (const m of step.mutations) {
- changes.push({
- What: "DOM:" + m.type,
- Before: this._mutationBefore(m),
- After: this._mutationAfter(m)
- });
- }
- if (changes.length === 0) {
- console.log("[ttd] No changes at step " + step.index);
- } else {
- console.log("[ttd] Changes at step " + step.index + " (" + step.commandSource.trim() + "):");
- console.table(changes);
- }
- return changes;
- }
- /** Show DOM mutations at a step */
- dom(n) {
- const step = this._resolveStep(n);
- if (!step) return void 0;
- if (step.mutations.length === 0) {
- console.log("[ttd] No DOM mutations at step " + step.index);
- } else {
- console.log("[ttd] DOM mutations at step " + step.index + " (" + step.mutations.length + "):");
- for (const m of step.mutations) {
- this._logMutation(m);
- }
- }
- return step.mutations;
}
// ==================================================================
// Overview
// ==================================================================
- /** Print a summary table of all (or filtered) steps */
- steps(opts) {
- opts = opts || {};
- let items = this._timeline.toArray();
- if (opts.stream) {
- items = items.filter((s) => s.streamId === opts.stream);
- }
- if (opts.last) {
- items = items.slice(-opts.last);
- }
- const rows = items.map((s) => ({
- "#": s.index,
- Stream: s.streamId,
- Command: s.commandSource.trim().substring(0, 50),
- Feature: s.featureName || "-",
- Mutations: s.mutations.length,
- Async: s.isAsync ? "Y" : "",
- Error: s.error ? "Y" : ""
- }));
- console.table(rows);
- return items;
- }
- /** List all execution streams */
- get streams() {
- const rows = [];
- for (const [id, info] of this._recorder._streams) {
- rows.push({
- Stream: id,
- Feature: info.featureName || "-",
- Event: info.eventType || "-",
- Owner: elementDescription(info.ownerElement),
- Start: info.startStep
- });
- }
- console.table(rows);
- return Array.from(this._recorder._streams.values());
- }
- // ==================================================================
- // Search
- // ==================================================================
- /** Find steps where command source matches a pattern (string or regex) */
- find(pattern) {
- const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern, "i");
- const results = [];
- for (const step of this._timeline) {
- if (regex.test(step.commandSource)) {
- results.push(step);
- }
- }
- if (results.length === 0) {
- console.log("[ttd] No steps matching: " + pattern);
- } else {
- const rows = results.map((s) => ({
- "#": s.index,
- Stream: s.streamId,
- Command: s.commandSource.trim().substring(0, 50),
- Feature: s.featureName || "-"
- }));
- console.log("[ttd] Found " + results.length + " steps matching: " + pattern);
- console.table(rows);
- }
- return results;
- }
- /** Find steps where a specific variable changed */
- findVar(name) {
- const results = [];
- for (const step of this._timeline) {
- const before = step.snapshotBefore.locals[name];
- const after = step.snapshotAfter.locals[name];
- if (before !== after) {
- results.push({
- step,
- before,
- after
- });
- }
- }
- if (results.length === 0) {
- console.log('[ttd] Variable "' + name + '" never changed (or does not exist)');
- } else {
- const rows = results.map((r) => ({
- "#": r.step.index,
- Stream: r.step.streamId,
- Command: r.step.commandSource.trim().substring(0, 40),
- Before: summarizeValue(r.before),
- After: summarizeValue(r.after)
- }));
- console.log('[ttd] Variable "' + name + '" changed in ' + results.length + " steps:");
- console.table(rows);
- }
- return results;
- }
- /** Filter steps to a specific execution stream */
- stream(id) {
- const results = [];
- for (const step of this._timeline) {
- if (step.streamId === id) {
- results.push(step);
- }
- }
- if (results.length === 0) {
- console.log("[ttd] No steps for stream: " + id);
- } else {
- const rows = results.map((s) => ({
- "#": s.index,
- Command: s.commandSource.trim().substring(0, 50),
- Mutations: s.mutations.length,
- Async: s.isAsync ? "Y" : ""
- }));
- console.log('[ttd] Stream "' + id + '" (' + results.length + " steps):");
- console.table(rows);
- }
- return results;
- }
- // ==================================================================
- // Recording control
- // ==================================================================
- /** Pause recording (does not enter time travel mode) */
- pause() {
- this._recorder.active = false;
- console.log("[ttd] Recording paused.");
- return this;
+ /** All recorded steps as raw step objects. */
+ steps() {
+ return this._timeline.toArray();
}
- /** Clear all recorded history */
+ /** Clear all recorded history. No-op while time traveling. */
clear() {
- if (this._recorder.timeTraveling) {
- console.warn("[ttd] Cannot clear while time traveling. Call ttd.resume() first.");
- return this;
- }
+ if (this._recorder.timeTraveling) return this;
this._timeline.clear();
- this._recorder._streams.clear();
this._recorder._stepCounter = 0;
this._position = -1;
- console.log("[ttd] Timeline cleared.");
return this;
}
- /** Start recording (if paused, but not time traveling) */
- record() {
- if (this._recorder.timeTraveling) {
- console.warn("[ttd] Cannot start recording while time traveling. Call ttd.resume() first.");
- return this;
- }
- this._recorder.active = true;
- console.log("[ttd] Recording started.");
- return this;
- }
- // ==================================================================
- // Help
- // ==================================================================
- help() {
- console.log([
- "",
- "=== _hyperscript Time Travel Debugger (TTD) ===",
- "",
- "Navigation:",
- " ttd.back(n) Step backward n steps (default 1), restoring DOM",
- " ttd.forward(n) Step forward n steps (default 1), re-applying DOM",
- " ttd.goto(n) Jump to step n with DOM restoration",
- " ttd.resume() Exit time travel, return to live execution",
- "",
- "Inspection:",
- " ttd.inspect(n) Detailed view of step n (default: current)",
- " ttd.locals(n) Local variables at step n",
- " ttd.diff(n) What changed at step n",
- " ttd.dom(n) DOM mutations at step n",
- "",
- "Overview:",
- " ttd.steps() Table of all steps. Options: {stream, last}",
- " ttd.streams List all execution streams",
- " ttd.length Total recorded steps",
- " ttd.current Current step index",
- "",
- "Search:",
- " ttd.find(pat) Find steps by command source (string or regex)",
- " ttd.findVar(name) Find steps where variable changed",
- " ttd.stream(id) Filter steps to one stream",
- "",
- "Control:",
- " ttd.pause() Pause recording",
- " ttd.record() Resume recording",
- " ttd.clear() Clear timeline",
- " ttd.help() Show this help",
- "",
- "State:",
- " ttd.recording Is recording active?",
- " ttd.traveling Is in time travel mode?",
- " ttd.maxSteps Ring buffer capacity",
- ""
- ].join("\n"));
- return this;
- }
- // ==================================================================
- // Internal helpers
- // ==================================================================
- _resolveStep(n) {
- if (n === void 0 || n === null) {
- n = this.current;
- }
- const step = this._timeline.getStep(n);
- if (!step) {
- console.error("[ttd] Step " + n + " not found.");
- return null;
- }
- return step;
- }
- _logMutation(m) {
- const target = elementDescription(m.target);
- switch (m.type) {
- case "attributes":
- console.log(
- " ATTR " + target + " @" + m.attributeName + ": " + summarizeValue(m.oldValue, 30) + " -> " + summarizeValue(m.newValue, 30)
- );
- break;
- case "characterData":
- console.log(
- " TEXT " + target + ": " + summarizeValue(m.oldValue, 30) + " -> " + summarizeValue(m.newValue, 30)
- );
- break;
- case "childList": {
- const parts = [];
- if (m.addedNodes.length > 0) {
- parts.push("+" + m.addedNodes.length + " added");
- }
- if (m.removedNodes.length > 0) {
- parts.push("-" + m.removedNodes.length + " removed");
- }
- console.log(" NODES " + target + ": " + parts.join(", "));
- break;
- }
- }
- }
- _mutationBefore(m) {
- switch (m.type) {
- case "attributes":
- return "@" + m.attributeName + "=" + summarizeValue(m.oldValue, 20);
- case "characterData":
- return summarizeValue(m.oldValue, 30);
- case "childList":
- return m.removedNodes.length + " nodes";
- default:
- return "";
- }
- }
- _mutationAfter(m) {
- switch (m.type) {
- case "attributes":
- return "@" + m.attributeName + "=" + summarizeValue(m.newValue, 20);
- case "characterData":
- return summarizeValue(m.newValue, 30);
- case "childList":
- return m.addedNodes.length + " nodes";
- default:
- return "";
- }
- }
};
- var LOGO_DATA = "data:image/png;base64,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";
- function injectFont() {
- if (document.querySelector("style[data-hs-debugger-font]")) return;
- var style = document.createElement("style");
- style.setAttribute("data-hs-debugger-font", "");
- style.textContent = ".hs-dbg-bp-glyph{background:#c03030;border-radius:50%;width:10px!important;height:10px!important;margin-top:4px;margin-left:4px}.hs-dbg-bp-line{background:rgba(192,48,48,.1)}.hs-dbg-current-line{background:rgba(255,210,60,.6)!important}.hs-dbg-current-glyph{background:#ffc850;border-radius:2px;width:10px!important;height:10px!important;margin-top:4px;margin-left:4px}";
- document.head.appendChild(style);
- }
- function injectStyles() {
- if (document.getElementById("hs-debugger-styles")) return;
- var style = document.createElement("style");
- style.id = "hs-debugger-styles";
- style.textContent = '#hs-debugger{all:initial;display:block;position:fixed;z-index:2147483647;overflow:auto;overscroll-behavior:none;font-family:"IBM Plex Sans",-apple-system,"Segoe UI",system-ui,sans-serif;font-size:13px;color:#222;line-height:1.4}#hs-debugger.hs-bottom{left:0;right:0;bottom:0;height:320px}#hs-debugger.hs-right{top:0;right:0;bottom:0;width:420px}#hs-debugger.hs-hidden{display:none!important}#hs-debugger .d-root{display:flex;flex-direction:column;height:100%;background:#fff;border-top:2px solid #b0b0b0;box-shadow:0 -2px 8px rgba(0,0,0,.12)}#hs-debugger.hs-right .d-root{border-top:none;border-left:2px solid #b0b0b0;box-shadow:-2px 0 8px rgba(0,0,0,.12)}#hs-debugger .d-resize{position:absolute;z-index:1}#hs-debugger.hs-bottom .d-resize{top:-4px;left:0;right:0;height:8px;cursor:ns-resize}#hs-debugger.hs-right .d-resize{top:0;left:-4px;bottom:0;width:8px;cursor:ew-resize}#hs-debugger .d-resize:hover{background:#4a84c4;opacity:.3}#hs-debugger .d-toolbar{display:flex;align-items:center;gap:4px;padding:3px 10px;background:#ebebeb;border-bottom:1px solid #b0b0b0;user-select:none;flex-shrink:0}#hs-debugger .d-logo{height:32px;width:auto;margin-right:8px}#hs-debugger .d-title{font-family:system-ui,sans-serif;font-size:20px;font-weight:bold;margin-right:auto}#hs-debugger .d-title em{color:#4a84c4;font-style:normal}#hs-debugger .d-btn{background:none;border:1px solid #d4d4d4;color:#666;cursor:pointer;padding:2px 8px;border-radius:3px;font:inherit;font-size:12px}#hs-debugger .d-btn:hover{color:#222;background:#e0e8f4;border-color:#b0b0b0}#hs-debugger .d-btn.active{color:#4a84c4;background:#e8f0fb;border-color:#4a84c4}#hs-debugger .d-btn-close{font-size:16px;padding:0 4px;margin-left:4px;border:none}#hs-debugger .d-body{display:grid;grid-template-columns:1fr 6px 40%;flex:1;overflow:hidden;min-height:0}#hs-debugger.hs-right .d-body{grid-template-columns:1fr;grid-template-rows:1fr 6px 40%}#hs-debugger .d-elements{display:grid;grid-template-columns:auto 4px 1fr;min-width:0;min-height:0;overflow:hidden}#hs-debugger.hs-right .d-elements{grid-template-columns:1fr;grid-template-rows:auto 4px 1fr}#hs-debugger .d-el-list{width:200px;min-width:100px;border-right:1px solid #d4d4d4;display:flex;flex-direction:column;min-height:0}#hs-debugger.hs-right .d-el-list{width:auto;height:150px;border-right:none;border-bottom:1px solid #d4d4d4;max-height:none}#hs-debugger .d-el-search{display:block;box-sizing:border-box;padding:4px 8px;margin:6px;width:calc(100% - 12px);border:1px solid #8a8a8a;border-radius:3px;background:#fff;color:#222;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:11px;outline:none;flex-shrink:0;box-shadow:inset 0 2px 4px rgba(0,0,0,.28)}#hs-debugger .d-el-search::placeholder{color:#999}#hs-debugger .d-el-search:focus{border-color:#4a84c4;box-shadow:inset 0 2px 4px rgba(0,0,0,.28),0 0 0 2px rgba(74,132,196,.25)}#hs-debugger .d-el-items{flex:1;min-height:0;overflow-y:auto}#hs-debugger .d-el-split{cursor:col-resize;background:#d4d4d4}#hs-debugger.hs-right .d-el-split{cursor:row-resize}#hs-debugger .d-el-split:hover{background:#4a84c4}#hs-debugger .d-el-item{padding:4px 10px;cursor:pointer;border-bottom:1px solid #d4d4d4;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#hs-debugger .d-el-item:hover{background:#e0e8f4}#hs-debugger .d-el-item.selected{background:#4a84c4;color:#fff}#hs-debugger .d-el-item.selected .d-tag,#hs-debugger .d-el-item.selected .d-id,#hs-debugger .d-el-item.selected .d-cls{color:inherit}#hs-debugger .d-tag{color:#4a84c4}#hs-debugger .d-id{color:#2b6b1f}#hs-debugger .d-cls{color:#8a6d00}#hs-debugger .d-detail{overflow-y:auto;padding:10px;display:flex;flex-direction:column;min-width:0}#hs-debugger .d-dbg-toolbar{display:flex;align-items:center;gap:10px;min-height:26px;margin:12px 0 6px}#hs-debugger .d-dbg-toolbar .d-label{margin:0}#hs-debugger .d-dbg-btns{display:flex;gap:2px;visibility:hidden}#hs-debugger.hs-paused .d-dbg-btns{visibility:visible}#hs-debugger.hs-right .d-detail{min-width:auto}#hs-debugger .d-code{white-space:pre-wrap;word-break:break-word;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:12px;line-height:1.5;padding:8px;background:#f6f6f6;border-radius:4px;border:1px solid #d4d4d4}#hs-debugger .d-code-area{display:flex;flex:1;min-height:80px;gap:8px}#hs-debugger .d-editor{flex:1;border:1px solid #d4d4d4;border-radius:4px;overflow:hidden}@keyframes hs-dbg-flash{0%{box-shadow:0 0 0 0 rgba(255,200,80,0)}25%{box-shadow:0 0 0 4px rgba(255,200,80,.85)}100%{box-shadow:0 0 0 0 rgba(255,200,80,0)}}#hs-debugger .d-editor.hs-dbg-flash{animation:hs-dbg-flash .5s ease-out}#hs-debugger.hs-paused .d-editor{border-color:#4a84c4;box-shadow:0 0 0 2px rgba(74,132,196,.5)}#hs-debugger .d-label{font-family:system-ui,sans-serif;font-size:11px;color:#666;text-transform:uppercase;letter-spacing:.05em;margin:0 0 4px}#hs-debugger .d-label+.d-label,#hs-debugger .d-code+.d-label{margin-top:12px}#hs-debugger .d-console{display:flex;flex-direction:column;border-left:2px solid #b0b0b0;background:#1a0e00;min-width:0;min-height:0;overflow:hidden;cursor:text}#hs-debugger.hs-right .d-console{border-left:none;border-top:2px solid #b0b0b0}#hs-debugger .d-con-hdr{padding:4px 10px;font-family:system-ui,sans-serif;font-size:11px;color:#ffdd60;border-bottom:1px solid #3a2800;text-transform:uppercase;letter-spacing:.08em;user-select:none;flex-shrink:0}#hs-debugger .d-con-scroll{flex:1;min-height:0;overflow-y:auto}#hs-debugger .d-con-out{padding:6px 10px;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:13px;font-weight:700;color:#ffe060;background-image:repeating-linear-gradient(0deg,transparent,transparent 10px,rgba(255,160,30,.06) 10px,rgba(255,160,30,.06) 20px);background-attachment:local}#hs-debugger .d-con-entry{padding:3px 0}#hs-debugger .d-con-in{display:flex;align-items:center;padding:2px 10px 6px}#hs-debugger .d-prompt{padding:0 6px 0 0;color:#ffdd60;font-family:system-ui,sans-serif;user-select:none;font-size:13px;font-weight:700;line-height:1.5;white-space:nowrap}#hs-debugger .d-input{flex:1;background:transparent;border:none;color:#ffdd60;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:13px;font-weight:700;padding:0;outline:none;caret-color:#ffdd60}#hs-debugger .d-log-input{color:#ffdd60;font-weight:700}#hs-debugger .d-log-result{color:#ffdd60;font-weight:700}#hs-debugger .d-log-error{color:#ff6040;font-weight:700}#hs-debugger .d-log-coll{color:#ffdd60;font-weight:700}#hs-debugger .d-log-coll-item{padding:1px 0 1px 12px;cursor:pointer;color:#ffdd60;font-weight:700}#hs-debugger .d-log-coll-item:hover{text-decoration:underline}#hs-debugger .d-split{cursor:col-resize;background:#b0b0b0;position:relative}#hs-debugger .d-split:hover{background:#4a84c4}#hs-debugger.hs-right .d-split{cursor:row-resize}#hs-debugger .d-con-toggle{position:absolute;top:50%;transform:translateY(-50%);right:-1px;background:#b0b0b0;color:#fff;border:none;cursor:pointer;font-size:10px;padding:8px 2px;border-radius:0 3px 3px 0;line-height:1}#hs-debugger.hs-right .d-con-toggle{top:50%;left:50%;right:auto;transform:translate(-50%,-50%);padding:1px 8px;border-radius:3px}#hs-debugger .d-con-collapsed .d-con-hdr,#hs-debugger .d-con-collapsed .d-con-scroll{display:none}#hs-debugger .d-con-collapsed{min-width:0;min-height:0}#hs-debugger.hs-bottom .d-con-collapsed{width:24px}#hs-debugger.hs-right .d-con-collapsed{height:24px;width:auto}#hs-debugger .d-con-vlabel{display:none;writing-mode:vertical-rl;text-orientation:mixed;font-family:system-ui,sans-serif;font-size:11px;color:#ffb030;letter-spacing:.08em;text-transform:uppercase;padding:10px 4px;user-select:none;cursor:pointer}#hs-debugger.hs-right .d-con-vlabel{writing-mode:horizontal-tb;padding:4px 10px;text-align:center}#hs-debugger .d-con-collapsed .d-con-vlabel{display:block}#hs-debugger .d-empty{color:#666;text-align:center;padding:20px;font-family:system-ui,sans-serif;font-size:12px}#hs-debugger .d-dbg-btn{background:#fff;border:1px solid #c0c0c0;box-shadow:0 1px 2px rgba(0,0,0,.1);cursor:pointer;padding:3px 8px;border-radius:3px;font-size:13px;line-height:1;color:#888}#hs-debugger .d-dbg-btn:hover{background:#f4f4f4;box-shadow:0 1px 3px rgba(0,0,0,.15)}#hs-debugger .d-dbg-btn:active{box-shadow:inset 0 1px 2px rgba(0,0,0,.12)}#hs-debugger .d-step,#hs-debugger .d-continue,#hs-debugger .d-step-back,#hs-debugger .d-step-over{color:#2b8a3e}#hs-debugger .d-stop{color:#c03030}#hs-debugger .d-vars{display:none;width:180px;flex-shrink:0;overflow-y:auto;border:1px solid #d4d4d4;border-radius:4px;padding:6px 8px;background:#f8f8f8}#hs-debugger.hs-paused .d-vars{display:block}#hs-debugger .d-vars table{width:100%;border-collapse:collapse}#hs-debugger .d-vars td{padding:2px 4px;border-bottom:1px solid #eee;font-family:"IBM Plex Mono","SF Mono","Consolas",monospace;font-size:11px}#hs-debugger .d-vars td:first-child{color:#c05020;white-space:nowrap}#hs-debugger .d-var-scope{color:#888!important;font-family:system-ui,sans-serif;font-size:10px;text-transform:uppercase;letter-spacing:.05em;padding-top:6px!important;border-bottom:none!important}';
- document.head.appendChild(style);
- }
+ var LOGO_DATA = "data:image/png;base64," + debugger_logo_default;
function createPanel(_hyperscript2, ttd, timeline, domRestorer, recorder) {
- injectFont();
- injectStyles();
var selectedElement = null;
var position = "bottom";
var consoleHistory = [];
@@ -11563,7 +11748,7 @@
}
var root = document.createElement("div");
root.id = "hs-debugger";
- root.innerHTML = '
Select an element to inspect
';
+ root.innerHTML = 'Select an element to inspect
';
document.body.appendChild(root);
var $ = function(s) {
return root.querySelector(s);
@@ -11574,27 +11759,47 @@
var conOut = $(".d-con-out");
var conIn = $(".d-input");
var conScroll = $(".d-con-scroll");
+ var body = $(".d-body");
+ var DEFAULT_SIZES = {
+ bottom: { list: 200, timeline: 260, console: 300 },
+ right: { list: 140, timeline: 180, console: 200 }
+ };
+ var MIN_SIZE = 60;
+ var paneSizes = {
+ bottom: Object.assign({}, DEFAULT_SIZES.bottom),
+ right: Object.assign({}, DEFAULT_SIZES.right)
+ };
+ function buildGridTracks() {
+ var s = paneSizes[position];
+ return s.list + "px 6px 1fr 6px " + s.timeline + "px 6px " + s.console + "px";
+ }
+ function applyGridTracks() {
+ var tracks = buildGridTracks();
+ if (position === "right") {
+ body.style.gridTemplateColumns = "1fr";
+ body.style.gridTemplateRows = tracks;
+ } else {
+ body.style.gridTemplateColumns = tracks;
+ body.style.gridTemplateRows = "";
+ }
+ }
+ function applyPageOffset() {
+ if (!document.body) return;
+ if (position === "bottom" && !root.classList.contains("hs-hidden")) {
+ document.body.style.paddingBottom = root.getBoundingClientRect().height + "px";
+ } else {
+ document.body.style.paddingBottom = "";
+ }
+ }
function setDock(pos) {
position = pos;
root.className = "hs-" + pos;
root.style.width = "";
root.style.height = "";
- var list = $(".d-el-list");
- if (list) {
- list.style.width = "";
- list.style.height = "";
- }
- var bodyEl = $(".d-body");
- if (bodyEl) {
- bodyEl.style.gridTemplateColumns = "";
- bodyEl.style.gridTemplateRows = "";
- }
- customConSize = null;
- var con = $(".d-console");
- if (con) con.classList.remove("d-con-collapsed");
- var toggle = $(".d-con-toggle");
- if (toggle) toggle.textContent = pos === "right" ? "\u25BC" : "\u25B6";
+ applyGridTracks();
for (var b2 of $$(".d-dock")) b2.classList.toggle("active", b2.dataset.dock === pos);
+ if (typeof renderTimeline === "function") renderTimeline();
+ applyPageOffset();
saveState();
}
for (var b of $$(".d-dock")) b.addEventListener("click", function() {
@@ -11603,6 +11808,7 @@
$(".d-btn-close").addEventListener("click", function() {
root.classList.add("hs-hidden");
hideHL();
+ applyPageOffset();
});
$(".d-resize").addEventListener("mousedown", function(e) {
e.preventDefault();
@@ -11614,110 +11820,41 @@
function up() {
document.removeEventListener("mousemove", mv);
document.removeEventListener("mouseup", up);
+ applyPageOffset();
}
document.addEventListener("mousemove", mv);
document.addEventListener("mouseup", up);
});
- $(".d-el-split").addEventListener("mousedown", function(e) {
- e.preventDefault();
- var list = $(".d-el-list");
- var startX = e.clientX, startW = list.offsetWidth;
- var startY = e.clientY, startH = list.offsetHeight;
- function mv(e2) {
- if (position === "right") {
- list.style.height = Math.max(60, startH + e2.clientY - startY) + "px";
- } else {
- list.style.width = Math.max(80, startW + e2.clientX - startX) + "px";
- }
- }
- function up() {
- document.removeEventListener("mousemove", mv);
- document.removeEventListener("mouseup", up);
- saveState();
- }
- document.addEventListener("mousemove", mv);
- document.addEventListener("mouseup", up);
- });
- var customConSize = null;
- var body = $(".d-body");
- var COLLAPSE_W = 100;
- var COLLAPSE_H = 50;
- $(".d-split").addEventListener("mousedown", function(e) {
- if (e.target.tagName === "BUTTON") return;
- e.preventDefault();
- var con = $(".d-console");
- var toggle = $(".d-con-toggle");
- if (con.classList.contains("d-con-collapsed")) {
- con.classList.remove("d-con-collapsed");
- if (position === "bottom") {
- body.style.gridTemplateColumns = "1fr 6px " + (customConSize || "300px");
- toggle.textContent = "\u25B6";
- } else {
- body.style.gridTemplateRows = "1fr 6px " + (customConSize || "200px");
- toggle.textContent = "\u25BC";
- }
- }
- var startX = e.clientX, startW = con.offsetWidth;
- var startY = e.clientY, startH = con.offsetHeight;
- function mv(e2) {
- if (position === "bottom") {
- var w = startW + startX - e2.clientX;
- if (w < COLLAPSE_W) {
- con.classList.add("d-con-collapsed");
- body.style.gridTemplateColumns = "1fr 6px 24px";
- toggle.textContent = "\u25C0";
- } else {
- con.classList.remove("d-con-collapsed");
- body.style.gridTemplateColumns = "1fr 6px " + w + "px";
- customConSize = w + "px";
- toggle.textContent = "\u25B6";
- }
- } else {
- var h = startH + startY - e2.clientY;
- if (h < COLLAPSE_H) {
- con.classList.add("d-con-collapsed");
- body.style.gridTemplateRows = "1fr 6px 24px";
- toggle.textContent = "\u25B2";
- } else {
- con.classList.remove("d-con-collapsed");
- body.style.gridTemplateRows = "1fr 6px " + h + "px";
- customConSize = h + "px";
- toggle.textContent = "\u25BC";
- }
- }
- }
- function up() {
- document.removeEventListener("mousemove", mv);
- document.removeEventListener("mouseup", up);
- saveState();
- }
- document.addEventListener("mousemove", mv);
- document.addEventListener("mouseup", up);
- });
- function toggleConsole() {
- var con = $(".d-console");
- con.classList.toggle("d-con-collapsed");
- var collapsed = con.classList.contains("d-con-collapsed");
- if (position === "bottom") {
- body.style.gridTemplateColumns = collapsed ? "1fr 6px 24px" : customConSize ? "1fr 6px " + customConSize : "";
- $(".d-con-toggle").textContent = collapsed ? "\u25C0" : "\u25B6";
- } else {
- body.style.gridTemplateRows = collapsed ? "1fr 6px 24px" : customConSize ? "1fr 6px " + customConSize : "";
- $(".d-con-toggle").textContent = collapsed ? "\u25B2" : "\u25BC";
- }
- saveState();
+ for (var sp of $$(".d-split")) {
+ sp.addEventListener("mousedown", function(e) {
+ e.preventDefault();
+ var paneName = this.dataset.pane;
+ var horizontal = position !== "right";
+ var dock = position;
+ var startCoord = horizontal ? e.clientX : e.clientY;
+ var startSize = paneSizes[dock][paneName];
+ var sign = paneName === "list" ? 1 : -1;
+ function mv(e2) {
+ var coord = horizontal ? e2.clientX : e2.clientY;
+ var delta = (coord - startCoord) * sign;
+ paneSizes[dock][paneName] = Math.max(MIN_SIZE, startSize + delta);
+ applyGridTracks();
+ }
+ function up() {
+ document.removeEventListener("mousemove", mv);
+ document.removeEventListener("mouseup", up);
+ saveState();
+ }
+ document.addEventListener("mousemove", mv);
+ document.addEventListener("mouseup", up);
+ });
}
- $(".d-con-toggle").addEventListener("click", function(e) {
- e.stopPropagation();
- toggleConsole();
- });
- $(".d-con-vlabel").addEventListener("click", toggleConsole);
$(".d-console").addEventListener("click", function(e) {
var sel = window.getSelection && window.getSelection();
if (sel && sel.toString().length > 0) return;
var t = e.target;
if (t.tagName === "INPUT" || t.tagName === "A" || t.tagName === "BUTTON") return;
- if (t.classList && (t.classList.contains("d-log-coll-item") || t.classList.contains("d-con-toggle") || t.classList.contains("d-con-vlabel"))) return;
+ if (t.classList && t.classList.contains("d-log-coll-item")) return;
conIn.focus();
});
function refreshElements() {
@@ -11784,12 +11921,9 @@
}
bpDecorations = [];
debugDecorations = [];
- var detail = $(".d-detail");
- var btns = $(".d-dbg-btns");
- detail.innerHTML = "";
- if (btns) detail.appendChild(btns);
- detail.insertAdjacentHTML("beforeend", 'Select an element to inspect
');
+ $(".d-detail-content").innerHTML = 'Select an element to inspect
';
hideHL();
+ updateToolbarState();
saveState();
}
if (typeof MutationObserver !== "undefined") {
@@ -12125,7 +12259,7 @@
}]);
monacoEditor.revealLineInCenter(line);
}
- showVariables(ctx);
+ updateToolbarState();
flashEditor();
return true;
}
@@ -12141,7 +12275,6 @@
if (monacoEditor) {
debugDecorations = monacoEditor.deltaDecorations(debugDecorations, []);
}
- $(".d-vars").innerHTML = "";
var cmd = pausedCommand;
var ctx = pausedCtx;
pausedCommand = null;
@@ -12151,40 +12284,7 @@
skipNextBreak = true;
_hyperscript2.internals.runtime.unifiedExec(cmd, ctx);
}
- }
- function fmtVar(val) {
- return val === void 0 ? "undefined" : val === null ? "null" : typeof val === "string" ? '"' + val.substring(0, 50) + '"' : val instanceof Element ? elementDescription(val) : String(val).substring(0, 50);
- }
- function showVariables(ctx) {
- var vars = $(".d-vars");
- var rows = "";
- var hasLocals = false;
- for (var key in ctx.locals) {
- if (key === "cookies" || key === "clipboard") continue;
- var val = ctx.locals[key];
- if (key === "selection" && !val) continue;
- if (!hasLocals) {
- rows += '| Locals |
';
- hasLocals = true;
- }
- rows += "| " + esc(key) + " | " + esc(fmtVar(val)) + " |
";
- }
- if (ctx.result !== void 0) {
- rows += "| result | " + esc(fmtVar(ctx.result)) + " |
";
- }
- var owner = ctx.meta && ctx.meta.owner;
- if (owner && owner._hyperscript && owner._hyperscript.elementScope) {
- var scope = owner._hyperscript.elementScope;
- var hasScope = false;
- for (var key in scope) {
- if (!hasScope) {
- rows += '| Element |
';
- hasScope = true;
- }
- rows += "| " + esc(key) + " | " + esc(fmtVar(scope[key])) + " |
";
- }
- }
- vars.innerHTML = rows ? "" : "";
+ updateToolbarState();
}
document.addEventListener("hyperscript:beforeEval", function(evt) {
var command = evt.detail.command;
@@ -12195,6 +12295,11 @@
}
}
});
+ document.addEventListener("hyperscript:breakpoint", function(evt) {
+ if (root.classList.contains("hs-hidden")) return;
+ breakOnNext = true;
+ evt.preventDefault();
+ });
function renderTimelineStep(step) {
if (!step) return;
root.classList.add("hs-paused");
@@ -12213,8 +12318,8 @@
} else {
applyStepDecoration(step);
}
- if (step.snapshotAfter) showSnapshotVars(step.snapshotAfter);
- else if (step.snapshotBefore) showSnapshotVars(step.snapshotBefore);
+ if (typeof syncTimelineToStep === "function") syncTimelineToStep(step.index);
+ updateToolbarState();
}
function applyStepDecoration(step) {
if (!monacoEditor || !step || !step.line) return;
@@ -12224,34 +12329,10 @@
}]);
monacoEditor.revealLineInCenter(step.line);
}
- function currentStreamId() {
- if (pausedCtx && pausedCtx.meta && pausedCtx.meta.ttd_streamId) {
- return pausedCtx.meta.ttd_streamId;
- }
- var step = timeline.getStep(ttd.current);
- return step ? step.streamId : null;
- }
- function findPrevInStream(pos, streamId) {
- for (var i = pos - 1; i >= timeline.firstIndex; i--) {
- var step = timeline.getStep(i);
- if (!step) continue;
- if (!streamId || step.streamId === streamId) return i;
- }
- return null;
- }
- function findNextInStream(pos, streamId) {
- for (var i = pos + 1; i <= timeline.lastIndex; i++) {
- var step = timeline.getStep(i);
- if (!step) continue;
- if (!streamId || step.streamId === streamId) return i;
- }
- return null;
- }
function stepForward() {
if (recorder.timeTraveling) {
- var streamId = currentStreamId();
- var target = findNextInStream(ttd.current, streamId);
- if (target !== null) {
+ var target = ttd.current + 1;
+ if (target <= timeline.lastIndex) {
ttd.goto(target);
renderTimelineStep(timeline.getStep(target));
return;
@@ -12262,8 +12343,8 @@
} else {
root.classList.remove("hs-paused");
if (monacoEditor) debugDecorations = monacoEditor.deltaDecorations(debugDecorations, []);
- $(".d-vars").innerHTML = "";
}
+ updateToolbarState();
return;
}
if (!pausedCommand) return;
@@ -12288,7 +12369,6 @@
} else {
applyLineDecoration(command.startToken && command.startToken.line);
}
- showVariables(ctx);
}
function applyLineDecoration(line) {
if (!monacoEditor || !line) return;
@@ -12319,7 +12399,7 @@
}
root.classList.remove("hs-paused");
if (monacoEditor) debugDecorations = monacoEditor.deltaDecorations(debugDecorations, []);
- $(".d-vars").innerHTML = "";
+ updateToolbarState();
}
function stopExec() {
if (recorder.timeTraveling) ttd.resume();
@@ -12331,58 +12411,157 @@
stepStreamId = null;
root.classList.remove("hs-paused");
if (monacoEditor) debugDecorations = monacoEditor.deltaDecorations(debugDecorations, []);
- $(".d-vars").innerHTML = "";
+ updateToolbarState();
}
function stepBack() {
if (timeline.length === 0) return;
- var streamId = currentStreamId();
var scanFrom = recorder.timeTraveling ? ttd.current : timeline.lastIndex + 1;
- var target = findPrevInStream(scanFrom, streamId);
- if (target === null) return;
+ var target = scanFrom - 1;
+ if (target < timeline.firstIndex) return;
root.classList.add("hs-paused");
ttd.goto(target);
renderTimelineStep(timeline.getStep(target));
}
- function showSnapshotVars(snapshot) {
- var vars = $(".d-vars");
- var rows = "";
- var hasLocals = false;
- for (var key in snapshot.locals) {
- if (key === "cookies" || key === "clipboard") continue;
- var val = snapshot.locals[key];
- if (key === "selection" && !val) continue;
- if (!hasLocals) {
- rows += '| Locals |
';
- hasLocals = true;
- }
- rows += "| " + esc(key) + " | " + esc(fmtVar(val)) + " |
";
- }
- if (snapshot.result !== void 0) {
- rows += "| result | " + esc(fmtVar(snapshot.result)) + " |
";
- }
- vars.innerHTML = rows ? "" : "";
- }
- $(".d-step-back").addEventListener("click", stepBack);
- $(".d-step").addEventListener("click", stepForward);
- $(".d-step-over").addEventListener("click", stepOver);
- $(".d-continue").addEventListener("click", continueExec);
- $(".d-stop").addEventListener("click", stopExec);
+ function canStepBack() {
+ if (timeline.length === 0) return false;
+ return !recorder.timeTraveling || ttd.current > timeline.firstIndex;
+ }
+ function canStepFwd() {
+ if (recorder.timeTraveling) {
+ return ttd.current < timeline.lastIndex || !!pausedCommand;
+ }
+ return !!pausedCommand;
+ }
+ function canContinue() {
+ return !!pausedCommand || recorder.timeTraveling;
+ }
+ function canStop() {
+ return !!pausedCommand || recorder.timeTraveling;
+ }
+ function updateToolbarState() {
+ var back = $(".d-step-back"), step = $(".d-step"), over = $(".d-step-over"), cont = $(".d-continue"), stop = $(".d-stop");
+ if (!back) return;
+ back.disabled = !canStepBack();
+ step.disabled = !canStepFwd();
+ over.disabled = !canStepFwd();
+ cont.disabled = !canContinue();
+ stop.disabled = !canStop();
+ }
+ $(".d-step-back").addEventListener("click", function() {
+ if (!this.disabled) stepBack();
+ });
+ $(".d-step").addEventListener("click", function() {
+ if (!this.disabled) stepForward();
+ });
+ $(".d-step-over").addEventListener("click", function() {
+ if (!this.disabled) stepOver();
+ });
+ $(".d-continue").addEventListener("click", function() {
+ if (!this.disabled) continueExec();
+ });
+ $(".d-stop").addEventListener("click", function() {
+ if (!this.disabled) stopExec();
+ });
document.addEventListener("keydown", function(e) {
- if (!root.classList.contains("hs-paused")) return;
+ if (root.classList.contains("hs-hidden")) return;
if (e.key === "F9") {
- e.preventDefault();
- stepBack();
+ if (canStepBack()) {
+ e.preventDefault();
+ stepBack();
+ }
} else if (e.key === "F10") {
- e.preventDefault();
- stepForward();
+ if (canStepFwd()) {
+ e.preventDefault();
+ stepForward();
+ }
} else if (e.key === "F11") {
- e.preventDefault();
- stepOver();
+ if (canStepFwd()) {
+ e.preventDefault();
+ stepOver();
+ }
} else if (e.key === "F8") {
- e.preventDefault();
+ if (canContinue()) {
+ e.preventDefault();
+ continueExec();
+ }
+ }
+ });
+ var tlSelectedIndex = null;
+ var tlRenderScheduled = false;
+ var tlTrackEl = $(".d-tl-track");
+ $(".d-tl-live").addEventListener("click", function() {
+ if (recorder.timeTraveling) {
continueExec();
}
+ tlSelectedIndex = null;
+ renderTimeline();
+ updateToolbarState();
});
+ $(".d-tl-clear").addEventListener("click", function() {
+ if (recorder.timeTraveling) continueExec();
+ ttd.clear();
+ tlSelectedIndex = null;
+ renderTimeline();
+ updateToolbarState();
+ });
+ recorder.onStep = function() {
+ updateToolbarState();
+ if (root.classList.contains("hs-hidden")) return;
+ if (recorder.timeTraveling) return;
+ scheduleTimelineRender();
+ };
+ function scheduleTimelineRender() {
+ if (tlRenderScheduled) return;
+ tlRenderScheduled = true;
+ requestAnimationFrame(function() {
+ tlRenderScheduled = false;
+ renderTimeline();
+ });
+ }
+ function renderTimeline() {
+ renderTimelineTrack();
+ }
+ function renderTimelineTrack() {
+ var steps = ttd.steps();
+ if (!steps.length) {
+ tlTrackEl.innerHTML = 'No steps recorded yet
';
+ return;
+ }
+ tlTrackEl.innerHTML = "";
+ var current = ttd.current;
+ for (var step of steps) {
+ var tick = document.createElement("button");
+ tick.className = "d-tl-tick";
+ if (step.error) tick.classList.add("err");
+ if (step.isAsync) tick.classList.add("async");
+ if (step.index === current && recorder.timeTraveling) tick.classList.add("current");
+ if (step.index === tlSelectedIndex) tick.classList.add("selected");
+ var src = step.commandSource.trim();
+ tick.innerHTML = '#' + step.index + '' + esc(src) + "";
+ tick.title = "#" + step.index + " " + src;
+ tick._idx = step.index;
+ tick._owner = step.ownerElement;
+ tick.addEventListener("click", function() {
+ tlGoto(this._idx);
+ });
+ tick.addEventListener("mouseenter", function() {
+ if (this._owner instanceof Element) showHL(this._owner);
+ });
+ tick.addEventListener("mouseleave", hideHL);
+ tlTrackEl.appendChild(tick);
+ }
+ var cur = tlTrackEl.querySelector(".current, .selected");
+ if (cur) cur.scrollIntoView({ block: "nearest", inline: "nearest" });
+ }
+ function tlGoto(index) {
+ if (ttd.goto(index)) {
+ renderTimelineStep(timeline.getStep(index));
+ }
+ }
+ function syncTimelineToStep(index) {
+ tlSelectedIndex = index;
+ renderTimeline();
+ }
var shiftHeld = false;
var shiftOverlays = [];
function hsAttrList() {
@@ -12533,19 +12712,14 @@
}
function selectElement(el) {
selectedElement = el;
- var detail = $(".d-detail");
+ var content = $(".d-detail-content");
var script = el.getAttribute("_") || el.getAttribute("script") || el.getAttribute("data-script") || "";
var t = el.tagName.toLowerCase();
var id = el.id ? "#" + el.id : "";
var c = el.className && typeof el.className === "string" ? "." + el.className.trim().split(/\s+/).join(".") : "";
- var btns = $(".d-dbg-btns");
- detail.innerHTML = "";
- detail.insertAdjacentHTML(
- "beforeend",
- 'Element
<' + t + id + c + '>
Hyperscript
'
- );
- $(".d-dbg-toolbar").appendChild(btns);
+ content.innerHTML = 'Element
<' + t + id + c + '>
Hyperscript
';
var editorReady = showInEditor($(".d-editor"), normalizeScript(script));
+ updateToolbarState();
saveState();
return editorReady;
}
@@ -12598,22 +12772,16 @@
if (result && result.then) {
result.then(function(v) {
showResult(v);
- refreshPausedVars();
}).catch(function(e) {
log(String(e), "error");
});
} else {
showResult(result);
- refreshPausedVars();
}
} catch (e) {
log(e.message || String(e), "error");
- refreshPausedVars();
}
}
- function refreshPausedVars() {
- if (pausedCtx) showVariables(pausedCtx);
- }
function isElColl(v) {
if (v instanceof NodeList || v instanceof HTMLCollection) return true;
if (Array.isArray(v) && v.length > 0 && v[0] instanceof Element) return true;
@@ -12625,7 +12793,7 @@
showCollection([value]);
} else if (isElColl(value)) {
showCollection(Array.from(value));
- } else if (value !== void 0) {
+ } else {
log(fmt(value), "result");
}
}
@@ -12671,6 +12839,7 @@
conScroll.scrollTop = conScroll.scrollHeight;
}
function fmt(v) {
+ if (v === void 0) return "undefined";
if (v === null) return "null";
if (typeof v === "string") return '"' + v + '"';
if (typeof v === "object") {
@@ -12759,7 +12928,6 @@
function saveState() {
if (!stateReady) return;
try {
- var list = $(".d-el-list");
var bpEntries = [];
for (var entry of breakpoints) {
var el = entry[0], lines = entry[1];
@@ -12770,11 +12938,12 @@
var state = {
open: !root.classList.contains("hs-hidden"),
dock: position,
- conCollapsed: $(".d-console").classList.contains("d-con-collapsed"),
- conSize: customConSize,
- listSize: position === "right" ? list.style.height || "" : list.style.width || "",
selectedIdentity: elementIdentity(selectedElement),
- breakpoints: bpEntries
+ breakpoints: bpEntries,
+ paneSizes: {
+ bottom: Object.assign({}, paneSizes.bottom),
+ right: Object.assign({}, paneSizes.right)
+ }
};
localStorage.setItem(STATE_KEY, JSON.stringify(state));
} catch (e) {
@@ -12806,32 +12975,23 @@
for (var i of $$(".d-el-item")) i.classList.toggle("selected", i._ref === sel);
}
}
+ renderTimeline();
}
}
function applyState() {
var state = loadState();
if (!state) return false;
- if (state.dock === "bottom" || state.dock === "right") setDock(state.dock);
- var list = $(".d-el-list");
- if (state.listSize && list) {
- if (state.dock === "right") list.style.height = state.listSize;
- else list.style.width = state.listSize;
- }
- if (state.conSize) {
- customConSize = state.conSize;
- if (state.dock === "right") body.style.gridTemplateRows = "1fr 6px " + state.conSize;
- else body.style.gridTemplateColumns = "1fr 6px " + state.conSize;
- }
- if (state.conCollapsed) {
- $(".d-console").classList.add("d-con-collapsed");
- if (state.dock === "right") {
- body.style.gridTemplateRows = "1fr 6px 24px";
- $(".d-con-toggle").textContent = "\u25B2";
- } else {
- body.style.gridTemplateColumns = "1fr 6px 24px";
- $(".d-con-toggle").textContent = "\u25C0";
+ if (state.paneSizes && typeof state.paneSizes === "object") {
+ for (var dockName of ["bottom", "right"]) {
+ var stored = state.paneSizes[dockName];
+ if (!stored || typeof stored !== "object") continue;
+ for (var key of Object.keys(paneSizes[dockName])) {
+ var v = Number(stored[key]);
+ if (!isNaN(v) && v >= MIN_SIZE) paneSizes[dockName][key] = v;
+ }
}
}
+ if (state.dock === "bottom" || state.dock === "right") setDock(state.dock);
if (state.open) root.classList.remove("hs-hidden");
else root.classList.add("hs-hidden");
whenDomReady(function() {
@@ -12843,25 +13003,31 @@
root.classList.add("hs-hidden");
applyState();
stateReady = true;
+ updateToolbarState();
return {
toggle: function() {
if (root.classList.contains("hs-hidden")) {
root.classList.remove("hs-hidden");
refreshElements();
+ renderTimeline();
} else {
root.classList.add("hs-hidden");
hideHL();
}
+ applyPageOffset();
saveState();
},
show: function() {
root.classList.remove("hs-hidden");
refreshElements();
+ renderTimeline();
+ applyPageOffset();
saveState();
},
hide: function() {
root.classList.add("hs-hidden");
hideHL();
+ applyPageOffset();
saveState();
},
refresh: refreshElements,
@@ -12869,19 +13035,17 @@
stepOver,
stepBack,
continue: continueExec,
- stop: stopExec,
- ttd
+ stop: stopExec
};
}
function debuggerPlugin(_hyperscript2) {
_hyperscript2.config.debugMode = true;
- var runtime2 = _hyperscript2.internals.runtime;
- var maxSteps = getMaxSteps();
- var timeline = new RingBuffer(maxSteps);
- var mutationBatcher = new MutationBatcher();
- var recorder = new Recorder(timeline, mutationBatcher);
- var domRestorer = new DomRestorer(mutationBatcher, runtime2);
- var ttd = new TTD(recorder, timeline, domRestorer);
+ const runtime2 = _hyperscript2.internals.runtime;
+ const timeline = new RingBuffer(MAX_STEPS);
+ const mutationBatcher = new MutationBatcher();
+ const recorder = new Recorder(timeline, mutationBatcher);
+ const domRestorer = new DomRestorer(mutationBatcher, runtime2);
+ const ttd = new TTD(recorder, timeline, domRestorer);
recorder.install();
if (typeof document !== "undefined") {
if (document.readyState === "loading") {
@@ -12892,9 +13056,8 @@
mutationBatcher.init();
}
}
- globalThis.ttd = ttd;
if (typeof document !== "undefined") {
- var panel = createPanel(_hyperscript2, ttd, timeline, domRestorer, recorder);
+ const panel = createPanel(_hyperscript2, ttd, timeline, domRestorer, recorder);
_hyperscript2.debugger = panel;
}
}
@@ -13326,7 +13489,7 @@
self2.importScripts.apply(self2, e.data.extraScripts);
const _hyperscript2 = self2["_hyperscript"];
var hyperscript = _hyperscript2.parse(e.data.src);
- hyperscript.apply(self2, self2);
+ hyperscript.apply(self2, self2, null, _hyperscript2.internals.runtime);
postMessage({ type: "didInit" });
break;
case "call":
@@ -13406,7 +13569,7 @@
var worker = new Worker(workerUri);
worker.postMessage({
type: "init",
- _hyperscript: document.currentScript?.src || "/dist/_hyperscript.js",
+ _hyperscript: document.currentScript?.src || new URL("/dist/_hyperscript.js", location.href).href,
extraScripts,
src: bodySrc
});
diff --git a/dist/_hyperscript-max.js.map b/dist/_hyperscript-max.js.map
index 64a25fcf0..d443138b2 100644
--- a/dist/_hyperscript-max.js.map
+++ b/dist/_hyperscript-max.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
- "sources": ["../src/core/tokenizer.js", "../src/parsetree/base.js", "../src/parsetree/internals.js", "../src/parsetree/expressions/literals.js", "../src/core/parser.js", "../src/core/kernel.js", "../src/core/config.js", "../src/core/runtime/conversions.js", "../src/core/runtime/cookies.js", "../src/core/runtime/collections.js", "../src/core/runtime/runtime.js", "../src/core/runtime/reactivity.js", "../src/core/runtime/morph.js", "../src/core/runtime/htmx-compat.js", "../src/parsetree/expressions/expressions.js", "../src/parsetree/expressions/webliterals.js", "../src/parsetree/expressions/postfix.js", "../src/parsetree/expressions/positional.js", "../src/parsetree/expressions/existentials.js", "../src/parsetree/expressions/targets.js", "../src/parsetree/commands/basic.js", "../src/parsetree/commands/setters.js", "../src/parsetree/commands/events.js", "../src/parsetree/commands/controlflow.js", "../src/parsetree/commands/execution.js", "../src/parsetree/commands/pseudoCommand.js", "../src/parsetree/commands/dom.js", "../src/parsetree/commands/animations.js", "../src/parsetree/commands/debug.js", "../src/parsetree/features/on.js", "../src/parsetree/features/def.js", "../src/parsetree/features/set.js", "../src/parsetree/features/init.js", "../src/parsetree/features/worker.js", "../src/parsetree/features/behavior.js", "../src/parsetree/features/install.js", "../src/parsetree/features/js.js", "../src/parsetree/features/when.js", "../src/parsetree/features/bind.js", "../src/parsetree/features/live.js", "../src/parsetree/commands/template.js", "../src/_hyperscript.js", "../src/ext/debugger.js", "../src/ext/component.js", "../src/ext/socket.js", "../src/ext/worker.js", "../src/ext/eventsource.js", "../src/ext/tailwind.js"],
- "sourcesContent": ["// Tokenizer - Lexical analysis for _hyperscript\n\n// ============================================================\n// Tokens - Token stream with matching/consuming API\n// ============================================================\n\nexport class Tokens {\n #tokens;\n #consumed = [];\n #lastConsumed = null;\n #follows = [];\n source;\n\n constructor(tokens, source) {\n this.#tokens = tokens;\n this.source = source;\n this.consumeWhitespace();\n }\n\n get list() {\n return this.#tokens;\n }\n\n get consumed() {\n return this.#consumed;\n }\n\n // ----- Debug -----\n\n toString() {\n var cur = this.currentToken();\n var lines = this.source.split(\"\\n\");\n var lineIdx = cur?.line ? cur.line - 1 : lines.length - 1;\n var col = cur?.line ? cur.column : 0;\n var contextLine = lines[lineIdx] || \"\";\n var tokenLen = Math.max(1, cur?.value?.length || 1);\n var gutter = String(lineIdx + 1).length;\n\n var out = \"Tokens(\";\n out += this.#consumed.filter(t => t.type !== \"WHITESPACE\").length + \" consumed, \";\n out += this.#tokens.filter(t => t.type !== \"WHITESPACE\").length + \" remaining\";\n out += \", line \" + (lineIdx + 1) + \")\\n\";\n out += \" \" + String(lineIdx + 1).padStart(gutter) + \" | \" + contextLine + \"\\n\";\n out += \" \".repeat(gutter + 5) + \" \".repeat(col) + \"^\".repeat(tokenLen);\n if (cur) out += \" \" + cur.type + \" '\" + cur.value + \"'\";\n return out;\n }\n\n // ----- Token access -----\n\n currentToken() {\n return this.token(0);\n }\n\n token(n, includeWhitespace) {\n var token;\n var i = 0;\n do {\n if (!includeWhitespace) {\n while (this.#tokens[i] && this.#tokens[i].type === \"WHITESPACE\") {\n i++;\n }\n }\n token = this.#tokens[i];\n n--;\n i++;\n } while (n > -1);\n return token || { type: \"EOF\", value: \"<<>>\" };\n }\n\n hasMore() {\n return this.#tokens.length > 0;\n }\n\n lastMatch() {\n return this.#lastConsumed;\n }\n\n // ----- Token matching -----\n\n matchToken(value, type) {\n if (this.#follows.includes(value)) return;\n type = type || \"IDENTIFIER\";\n if (this.currentToken() && this.currentToken().value === value && this.currentToken().type === type) {\n return this.consumeToken();\n }\n }\n\n matchOpToken(value) {\n if (this.currentToken() && this.currentToken().op && this.currentToken().value === value) {\n return this.consumeToken();\n }\n }\n\n matchTokenType(...types) {\n if (this.currentToken() && this.currentToken().type && types.includes(this.currentToken().type)) {\n return this.consumeToken();\n }\n }\n\n matchAnyToken(...tokens) {\n for (var i = 0; i < tokens.length; i++) {\n var match = this.matchToken(tokens[i]);\n if (match) return match;\n }\n }\n\n matchAnyOpToken(...ops) {\n for (var i = 0; i < ops.length; i++) {\n var match = this.matchOpToken(ops[i]);\n if (match) return match;\n }\n }\n\n // ----- Token consuming -----\n\n consumeToken() {\n var match = this.#tokens.shift();\n this.#consumed.push(match);\n this.#lastConsumed = match;\n this.consumeWhitespace();\n return match;\n }\n\n consumeWhitespace() {\n while (this.token(0, true).type === \"WHITESPACE\") {\n this.#consumed.push(this.#tokens.shift());\n }\n }\n\n consumeUntil(value, type) {\n var tokenList = [];\n var currentToken = this.token(0, true);\n while (\n (type == null || currentToken.type !== type) &&\n (value == null || currentToken.value !== value) &&\n currentToken.type !== \"EOF\"\n ) {\n var match = this.#tokens.shift();\n this.#consumed.push(match);\n tokenList.push(currentToken);\n currentToken = this.token(0, true);\n }\n this.consumeWhitespace();\n return tokenList;\n }\n\n consumeUntilWhitespace() {\n return this.consumeUntil(null, \"WHITESPACE\");\n }\n\n // ----- Lookahead -----\n\n peekToken(value, peek, type) {\n peek = peek || 0;\n type = type || \"IDENTIFIER\";\n let peekNoWhitespace = 0;\n while (peek > 0) {\n peekNoWhitespace++;\n if (this.#tokens[peekNoWhitespace]?.type !== \"WHITESPACE\") {\n peek--;\n }\n }\n if (this.#tokens[peekNoWhitespace] &&\n this.#tokens[peekNoWhitespace].value === value &&\n this.#tokens[peekNoWhitespace].type === type) {\n return this.#tokens[peekNoWhitespace];\n }\n }\n\n // ----- Whitespace -----\n\n lastWhitespace() {\n var last = this.#consumed.at(-1);\n return (last && last.type === \"WHITESPACE\") ? last.value : \"\";\n }\n\n // ----- Follow set management -----\n\n pushFollow(str) {\n this.#follows.push(str);\n }\n\n popFollow() {\n this.#follows.pop();\n }\n\n pushFollows(...strs) {\n for (var i = 0; i < strs.length; i++) this.#follows.push(strs[i]);\n return strs.length;\n }\n\n popFollows(count) {\n for (var i = 0; i < count; i++) this.#follows.pop();\n }\n\n clearFollows() {\n var tmp = this.#follows;\n this.#follows = [];\n return tmp;\n }\n\n restoreFollows(f) {\n this.#follows = f;\n }\n\n}\n\n// ============================================================\n// Tokenizer - Lexical analysis engine\n// ============================================================\n\nconst OP_TABLE = {\n \"+\": \"PLUS\",\n \"-\": \"MINUS\",\n \"*\": \"MULTIPLY\",\n \"/\": \"DIVIDE\",\n \".\": \"PERIOD\",\n \"..\": \"ELLIPSIS\",\n \"\\\\\": \"BACKSLASH\",\n \":\": \"COLON\",\n \"%\": \"PERCENT\",\n \"|\": \"PIPE\",\n \"!\": \"EXCLAMATION\",\n \"?\": \"QUESTION\",\n \"#\": \"POUND\",\n \"&\": \"AMPERSAND\",\n \"$\": \"DOLLAR\",\n \";\": \"SEMI\",\n \",\": \"COMMA\",\n \"(\": \"L_PAREN\",\n \")\": \"R_PAREN\",\n \"<\": \"L_ANG\",\n \">\": \"R_ANG\",\n \"<=\": \"LTE_ANG\",\n \">=\": \"GTE_ANG\",\n \"==\": \"EQ\",\n \"===\": \"EQQ\",\n \"!=\": \"NEQ\",\n \"!==\": \"NEQQ\",\n \"{\": \"L_BRACE\",\n \"}\": \"R_BRACE\",\n \"[\": \"L_BRACKET\",\n \"]\": \"R_BRACKET\",\n \"=\": \"EQUALS\",\n \"~\": \"TILDE\",\n \"^\": \"CARET\",\n};\n\nexport class Tokenizer {\n\n // ----- Instance state -----\n #source = \"\";\n #position = 0;\n #column = 0;\n #line = 1;\n #lastToken = \"\";\n #templateBraceCount = 0;\n #tokens = [];\n #template = false;\n #templateMode;\n\n // ----- Character classification -----\n\n #isAlpha(c) {\n return (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\");\n }\n\n #isNumeric(c) {\n return c >= \"0\" && c <= \"9\";\n }\n\n #isWhitespace(c) {\n return c === \" \" || c === \"\\t\" || c === \"\\r\" || c === \"\\n\";\n }\n\n #isNewline(c) {\n return c === \"\\r\" || c === \"\\n\";\n }\n\n #isValidCSSChar(c) {\n return this.#isAlpha(c) || this.#isNumeric(c) || c === \"-\" || c === \"_\" || c === \":\";\n }\n\n #isIdentifierChar(c) {\n return c === \"_\" || c === \"$\";\n }\n\n #isReservedChar(c) {\n return c === \"`\";\n }\n\n static tokenize(string, template) {\n return new Tokenizer().tokenize(string, template);\n }\n\n tokenize(string, template) {\n this.#source = string;\n this.#position = 0;\n this.#column = 0;\n this.#line = 1;\n this.#lastToken = \"\";\n this.#templateBraceCount = 0;\n this.#tokens = [];\n this.#template = template || false;\n this.#templateMode = \"indeterminant\";\n return this.#tokenize();\n }\n\n // ----- Character access -----\n\n #currentChar() {\n return this.#source.charAt(this.#position);\n }\n\n #nextChar() {\n return this.#source.charAt(this.#position + 1);\n }\n\n #charAt(offset = 1) {\n return this.#source.charAt(this.#position + offset);\n }\n\n #consumeChar() {\n this.#lastToken = this.#currentChar();\n this.#position++;\n if (this.#lastToken === \"\\n\") {\n this.#line++;\n this.#column = 0;\n } else {\n this.#column++;\n }\n return this.#lastToken;\n }\n\n // ----- Context checks -----\n\n #inTemplate() {\n return this.#template && this.#templateBraceCount === 0;\n }\n\n #inCommandMode() {\n return !this.#inTemplate() || this.#templateMode === \"command\";\n }\n\n #possiblePrecedingSymbol() {\n return (\n this.#isAlpha(this.#lastToken) ||\n this.#isNumeric(this.#lastToken) ||\n this.#lastToken === \")\" ||\n this.#lastToken === \"\\\"\" ||\n this.#lastToken === \"'\" ||\n this.#lastToken === \"`\" ||\n this.#lastToken === \"}\" ||\n this.#lastToken === \"]\"\n );\n }\n\n #isValidSingleQuoteStringStart() {\n if (this.#tokens.length > 0) {\n var prev = this.#tokens.at(-1);\n if (prev.type === \"IDENTIFIER\" || prev.type === \"CLASS_REF\" || prev.type === \"ID_REF\") {\n return false;\n }\n if (prev.op && (prev.value === \">\" || prev.value === \")\")) {\n return false;\n }\n }\n return true;\n }\n\n // ----- Token constructors -----\n\n #makeToken(type, value) {\n return {\n type: type,\n value: value || \"\",\n start: this.#position,\n end: this.#position + 1,\n column: this.#column,\n line: this.#line,\n };\n }\n\n #makeOpToken(type, value) {\n var token = this.#makeToken(type, value);\n token.op = true;\n return token;\n }\n\n // ----- Consume methods -----\n\n #consumeComment() {\n while (this.#currentChar() && !this.#isNewline(this.#currentChar())) {\n this.#consumeChar();\n }\n this.#consumeChar();\n }\n\n #consumeWhitespace() {\n var ws = this.#makeToken(\"WHITESPACE\");\n var value = \"\";\n while (this.#currentChar() && this.#isWhitespace(this.#currentChar())) {\n if (this.#isNewline(this.#currentChar())) {\n this.#templateMode = \"indeterminant\";\n }\n value += this.#consumeChar();\n }\n ws.value = value;\n ws.end = this.#position;\n return ws;\n }\n\n #consumeClassReference() {\n var token = this.#makeToken(\"CLASS_REF\");\n var value = this.#consumeChar();\n if (this.#currentChar() === \"{\") {\n token.template = true;\n value += this.#consumeChar();\n while (this.#currentChar() && this.#currentChar() !== \"}\") {\n value += this.#consumeChar();\n }\n if (this.#currentChar() !== \"}\") {\n throw new Error(\"Unterminated class reference\");\n } else {\n value += this.#consumeChar();\n }\n } else {\n while (this.#isValidCSSChar(this.#currentChar()) || this.#currentChar() === \"\\\\\") {\n if (this.#currentChar() === \"\\\\\") this.#consumeChar();\n value += this.#consumeChar();\n }\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeIdReference() {\n var token = this.#makeToken(\"ID_REF\");\n var value = this.#consumeChar();\n if (this.#currentChar() === \"{\") {\n token.template = true;\n value += this.#consumeChar();\n while (this.#currentChar() && this.#currentChar() !== \"}\") {\n value += this.#consumeChar();\n }\n if (this.#currentChar() !== \"}\") {\n throw new Error(\"Unterminated id reference\");\n } else {\n this.#consumeChar();\n }\n } else {\n while (this.#isValidCSSChar(this.#currentChar())) {\n value += this.#consumeChar();\n }\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeAttributeReference() {\n var token = this.#makeToken(\"ATTRIBUTE_REF\");\n var value = this.#consumeChar();\n while (this.#position < this.#source.length && this.#currentChar() !== \"]\") {\n value += this.#consumeChar();\n }\n if (this.#currentChar() === \"]\") {\n value += this.#consumeChar();\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeShortAttributeReference() {\n var token = this.#makeToken(\"ATTRIBUTE_REF\");\n var value = this.#consumeChar();\n while (this.#isValidCSSChar(this.#currentChar())) {\n value += this.#consumeChar();\n }\n if (this.#currentChar() === '=') {\n value += this.#consumeChar();\n if (this.#currentChar() === '\"' || this.#currentChar() === \"'\") {\n value += this.#consumeString().value;\n } else if (this.#isAlpha(this.#currentChar()) || this.#isNumeric(this.#currentChar()) || this.#isIdentifierChar(this.#currentChar())) {\n value += this.#consumeIdentifier().value;\n }\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeStyleReference() {\n var token = this.#makeToken(\"STYLE_REF\");\n var value = this.#consumeChar();\n while (this.#isAlpha(this.#currentChar()) || this.#currentChar() === \"-\") {\n value += this.#consumeChar();\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeTemplateLogic() {\n var token = this.#makeToken(\"IDENTIFIER\");\n this.#consumeChar(); // Don't need the '#'\n var value = \"\"\n\n while(this.#isAlpha(this.#currentChar())) {\n value += this.#consumeChar();\n }\n\n token.value = value;\n token.end = this.#position;\n\n return token;\n }\n\n #consumeTemplateLine() {\n var token = this.#makeToken(\"TEMPLATE_LINE\");\n token.value = \"TEMPLATE_LINE\";\n var content = \"\";\n while (this.#currentChar() && !this.#isNewline(this.#currentChar())) {\n content += this.#consumeChar();\n }\n if (this.#currentChar() && this.#isNewline(this.#currentChar())) {\n this.#consumeChar();\n content += \"\\n\";\n this.#templateMode = \"indeterminant\";\n }\n token.content = content;\n token.end = this.#position;\n return token;\n }\n\n #consumeTemplateIdentifier() {\n var token = this.#makeToken(\"IDENTIFIER\");\n var value = this.#consumeChar();\n var escaped = value === \"\\\\\";\n if (escaped) value = \"\";\n while (this.#isAlpha(this.#currentChar()) ||\n this.#isNumeric(this.#currentChar()) ||\n this.#isIdentifierChar(this.#currentChar()) ||\n this.#currentChar() === \"\\\\\" ||\n this.#currentChar() === \"{\" ||\n this.#currentChar() === \"}\") {\n if (this.#currentChar() === \"$\" && !escaped) {\n break;\n } else if (this.#currentChar() === \"\\\\\") {\n escaped = true;\n this.#consumeChar();\n } else {\n escaped = false;\n value += this.#consumeChar();\n }\n }\n if (this.#currentChar() === \"!\" && value === \"beep\") {\n value += this.#consumeChar();\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeIdentifier() {\n var token = this.#makeToken(\"IDENTIFIER\");\n var value = this.#consumeChar();\n while (this.#isAlpha(this.#currentChar()) || this.#isNumeric(this.#currentChar()) || this.#isIdentifierChar(this.#currentChar())) {\n value += this.#consumeChar();\n }\n if (this.#currentChar() === \"!\" && value === \"beep\") {\n value += this.#consumeChar();\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeNumber() {\n var token = this.#makeToken(\"NUMBER\");\n var value = this.#consumeChar();\n\n // consume integer part: XXX\n while (this.#isNumeric(this.#currentChar())) {\n value += this.#consumeChar();\n }\n\n // consume decimal part: .YYY\n if (this.#currentChar() === \".\" && this.#isNumeric(this.#nextChar())) {\n value += this.#consumeChar();\n }\n while (this.#isNumeric(this.#currentChar())) {\n value += this.#consumeChar();\n }\n\n // consume exponent: (e|E)[-]ZZZ\n if (this.#currentChar() === \"e\" || this.#currentChar() === \"E\") {\n if (this.#isNumeric(this.#nextChar())) {\n value += this.#consumeChar();\n } else if (this.#nextChar() === \"-\") {\n value += this.#consumeChar();\n value += this.#consumeChar();\n }\n }\n while (this.#isNumeric(this.#currentChar())) {\n value += this.#consumeChar();\n }\n\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeOp() {\n var token = this.#makeOpToken();\n var value = this.#consumeChar();\n while (this.#currentChar() && OP_TABLE[value + this.#currentChar()]) {\n value += this.#consumeChar();\n }\n token.type = OP_TABLE[value];\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeString() {\n var token = this.#makeToken(\"STRING\");\n var startChar = this.#consumeChar();\n token.template = startChar === \"`\";\n var value = \"\";\n while (this.#currentChar() && this.#currentChar() !== startChar) {\n if (this.#currentChar() === \"\\\\\") {\n this.#consumeChar();\n let next = this.#consumeChar();\n if (next === \"b\") value += \"\\b\";\n else if (next === \"f\") value += \"\\f\";\n else if (next === \"n\") value += \"\\n\";\n else if (next === \"r\") value += \"\\r\";\n else if (next === \"t\") value += \"\\t\";\n else if (next === \"v\") value += \"\\v\";\n else if (token.template && next === \"$\") value += \"\\\\$\";\n else if (next === \"x\") {\n const hex = this.#consumeHexEscape();\n if (Number.isNaN(hex)) {\n throw new Error(\"Invalid hexadecimal escape at [Line: \" + token.line + \", Column: \" + token.column + \"]\");\n }\n value += String.fromCharCode(hex);\n }\n else value += next;\n } else {\n value += this.#consumeChar();\n }\n }\n if (this.#currentChar() !== startChar) {\n throw new Error(\"Unterminated string at [Line: \" + token.line + \", Column: \" + token.column + \"]\");\n } else {\n this.#consumeChar();\n }\n token.value = value;\n token.end = this.#position;\n return token;\n }\n\n #consumeHexEscape() {\n if (!this.#currentChar()) return NaN;\n let result = 16 * Number.parseInt(this.#consumeChar(), 16);\n if (!this.#currentChar()) return NaN;\n result += Number.parseInt(this.#consumeChar(), 16);\n return result;\n }\n\n // ----- Main tokenization loop -----\n\n #isLineComment() {\n var c = this.#currentChar(), n = this.#nextChar(), n2 = this.#charAt(2);\n return (c === \"-\" && n === \"-\" && (this.#isWhitespace(n2) || n2 === \"\" || n2 === \"-\"))\n || (c === \"/\" && n === \"/\" && (this.#isWhitespace(n2) || n2 === \"\" || n2 === \"/\"));\n }\n\n #tokenize() {\n while (this.#position < this.#source.length) {\n if (this.#isLineComment()) {\n this.#consumeComment();\n } else if (this.#isWhitespace(this.#currentChar())) {\n this.#tokens.push(this.#consumeWhitespace());\n } else if (\n !this.#possiblePrecedingSymbol() &&\n this.#currentChar() === \".\" &&\n (this.#isAlpha(this.#nextChar()) || this.#nextChar() === \"{\" || this.#nextChar() === \"-\")\n ) {\n this.#tokens.push(this.#consumeClassReference());\n } else if (\n !this.#possiblePrecedingSymbol() &&\n this.#currentChar() === \"#\" &&\n (this.#isAlpha(this.#nextChar()) || this.#nextChar() === \"{\")\n ) {\n if (this.#template === \"lines\" && this.#templateMode === \"indeterminant\") {\n this.#templateMode = \"command\";\n this.#tokens.push(this.#consumeTemplateLogic());\n } else {\n this.#tokens.push(this.#consumeIdReference());\n }\n } else if (this.#template === \"lines\" && this.#templateMode === \"indeterminant\" && this.#templateBraceCount === 0) {\n this.#templateMode = \"template\";\n this.#tokens.push(this.#consumeTemplateLine());\n } else if (this.#currentChar() === \"[\" && this.#nextChar() === \"@\") {\n this.#tokens.push(this.#consumeAttributeReference());\n } else if (this.#currentChar() === \"@\") {\n this.#tokens.push(this.#consumeShortAttributeReference());\n } else if (this.#currentChar() === \"*\" && this.#isAlpha(this.#nextChar())) {\n this.#tokens.push(this.#consumeStyleReference());\n } else if (this.#inTemplate() &&\n (this.#isAlpha(this.#currentChar()) || this.#currentChar() === \"\\\\\") &&\n this.#templateMode !== \"command\"\n ) {\n this.#tokens.push(this.#consumeTemplateIdentifier());\n } else if (this.#inCommandMode() && (this.#isAlpha(this.#currentChar()) || this.#isIdentifierChar(this.#currentChar()))) {\n this.#tokens.push(this.#consumeIdentifier());\n } else if (this.#isNumeric(this.#currentChar())) {\n this.#tokens.push(this.#consumeNumber());\n } else if (this.#inCommandMode() && (this.#currentChar() === '\"' || this.#currentChar() === \"`\")) {\n this.#tokens.push(this.#consumeString());\n } else if (this.#inCommandMode() && this.#currentChar() === \"'\") {\n if (this.#isValidSingleQuoteStringStart()) {\n this.#tokens.push(this.#consumeString());\n } else {\n this.#tokens.push(this.#consumeOp());\n }\n } else if (OP_TABLE[this.#currentChar()]) {\n if (this.#lastToken === \"$\" && this.#currentChar() === \"{\") {\n this.#templateBraceCount++;\n }\n if (this.#currentChar() === \"}\") {\n this.#templateBraceCount--;\n }\n this.#tokens.push(this.#consumeOp());\n } else if (this.#inTemplate() || this.#isReservedChar(this.#currentChar())) {\n this.#tokens.push(this.#makeToken(\"RESERVED\", this.#consumeChar()));\n } else {\n if (this.#position < this.#source.length) {\n throw new Error(\"Unknown token: \" + this.#currentChar() + \" \");\n }\n }\n }\n\n return new Tokens(this.#tokens, this.#source);\n }\n}\n", "/**\n * Base classes for parse tree elements\n */\n\n/**\n * ParseElement - Root base class for all parse tree elements\n *\n * Provides common functionality for all parse tree nodes including\n * expressions, commands, and features.\n */\nexport class ParseElement {\n errors = [];\n\n collectErrors(visited) {\n if (!visited) visited = new Set();\n if (visited.has(this)) return [];\n visited.add(this);\n var all = [...this.errors];\n for (var key of Object.keys(this)) {\n for (var item of [this[key]].flat()) {\n if (item instanceof ParseElement) {\n all.push(...item.collectErrors(visited));\n }\n }\n }\n return all;\n }\n\n sourceFor() {\n return this.programSource.substring(this.startToken.start, this.endToken.end);\n }\n\n lineFor() {\n return this.programSource.split(\"\\n\")[this.startToken.line - 1];\n }\n\n static parseEventArgs(parser) {\n var args = [];\n // handle argument list (look ahead 3)\n if (\n parser.token(0).value === \"(\" &&\n (parser.token(1).value === \")\" || parser.token(2).value === \",\" || parser.token(2).value === \")\")\n ) {\n parser.matchOpToken(\"(\");\n do {\n args.push(parser.requireTokenType(\"IDENTIFIER\"));\n } while (parser.matchOpToken(\",\"));\n parser.requireOpToken(\")\");\n }\n return args;\n }\n}\n\n/**\n * Expression - Base class for all expressions\n *\n * Delegates to Runtime.unifiedEval for evaluation.\n * Subclasses define resolve() and args for their logic.\n * Type is auto-derived from static grammarName.\n */\nexport class Expression extends ParseElement {\n constructor() {\n super();\n if (this.constructor.grammarName) {\n this.type = this.constructor.grammarName;\n }\n }\n\n evaluate(context) {\n return context.meta.runtime.unifiedEval(this, context);\n }\n\n evalStatically() {\n throw new Error(\"This expression cannot be evaluated statically: \" + this.type);\n }\n}\n\n/**\n * Command - Base class for all commands\n *\n * Delegates to Runtime.unifiedExec for execution.\n * Subclasses define resolve() and args for their logic.\n * Type is auto-derived from static keyword + \"Command\".\n */\nexport class Command extends ParseElement {\n constructor() {\n super();\n if (this.constructor.keyword) {\n this.type = this.constructor.keyword + \"Command\";\n }\n }\n\n execute(context) {\n context.meta.command = this;\n return context.meta.runtime.unifiedExec(this, context);\n }\n\n findNext(context) {\n return context.meta.runtime.findNext(this, context);\n }\n\n}\n\n/**\n * Feature - Base class for all features\n *\n * Features define behavior that is installed on elements.\n * Subclasses implement install() method for their specific logic.\n * Type is auto-derived from static keyword + \"Feature\".\n */\nexport class Feature extends ParseElement {\n isFeature = true;\n\n constructor() {\n super();\n if (this.constructor.keyword) {\n this.type = this.constructor.keyword + \"Feature\";\n }\n }\n\n install(target, source, args, runtime) {\n // Subclasses override this method\n }\n\n /**\n * Parse optional catch/finally blocks after a command list.\n * Returns { errorHandler, errorSymbol, finallyHandler }\n */\n static parseErrorAndFinally(parser) {\n var errorSymbol, errorHandler, finallyHandler;\n if (parser.matchToken(\"catch\")) {\n errorSymbol = parser.requireTokenType(\"IDENTIFIER\").value;\n errorHandler = parser.requireElement(\"commandList\");\n parser.ensureTerminated(errorHandler);\n }\n if (parser.matchToken(\"finally\")) {\n finallyHandler = parser.requireElement(\"commandList\");\n parser.ensureTerminated(finallyHandler);\n }\n return { errorHandler, errorSymbol, finallyHandler };\n }\n}\n", "/**\n * Internal parse elements used by the kernel grammar\n */\n\nimport { ParseElement, Command, Feature } from './base.js';\n\n/**\n * EmptyCommandListCommand - Placeholder for empty command lists\n */\nexport class EmptyCommandListCommand extends Command {\n constructor() {\n super();\n this.type = \"emptyCommandListCommand\";\n }\n\n resolve(context) {\n return this.findNext(context);\n }\n}\n\n/**\n * UnlessStatementModifier - Wraps a command with an \"unless\" conditional\n */\nexport class UnlessStatementModifier extends Command {\n constructor(root, conditional) {\n super();\n this.type = \"unlessStatementModifier\";\n this.root = root;\n this.args = { conditional };\n }\n\n resolve(context, { conditional }) {\n if (conditional) {\n return this.next;\n } else {\n return this.root;\n }\n }\n}\n\n/**\n * HyperscriptProgram - Root node for a parsed hyperscript document\n */\nexport class HyperscriptProgram extends ParseElement {\n constructor(features) {\n super();\n this.type = \"hyperscript\";\n this.features = features;\n }\n\n apply(target, source, args, runtime) {\n for (const feature of this.features) {\n feature.install(target, source, args, runtime);\n }\n }\n}\n\n/**\n * FailedFeature - Placeholder for a feature that failed to parse.\n * Allows the parser to continue and collect more errors.\n * Never executed - element won't apply() if errors exist.\n */\nexport class FailedFeature extends Feature {\n constructor(error, keyword) {\n super();\n this.type = \"failedFeature\";\n this.keyword = keyword;\n this.errors.push(error);\n }\n\n install() {}\n}\n\n/**\n * FailedCommand - Placeholder for a command that failed to parse.\n * Allows the parser to continue and collect more errors.\n * Never executed - element won't apply() if errors exist.\n */\nexport class FailedCommand extends Command {\n constructor(error, keyword) {\n super();\n this.type = \"failedCommand\";\n this.keyword = keyword;\n this.errors.push(error);\n }\n\n resolve() {}\n}\n\n/**\n * ImplicitReturn - Terminates command lists without explicit returns\n */\nexport class ImplicitReturn extends Command {\n constructor() {\n super();\n this.type = \"implicitReturn\";\n }\n\n resolve(context) {\n context.meta.returned = true;\n if (context.meta.resolve) {\n context.meta.resolve();\n }\n return context.meta.runtime.HALT;\n }\n}\n", "/**\n * Literal parse tree elements\n * Simple value literals with no dependencies\n */\n\nimport { Expression } from '../base.js';\nimport { Tokenizer } from '../../core/tokenizer.js';\n\n/**\n * NakedString - Represents unquoted strings (consumed until whitespace)\n *\n * Parses: bareword text\n * Returns: string value\n */\nexport class NakedString extends Expression {\n static grammarName = \"nakedString\";\n\n constructor(tokens) {\n super();\n this.tokens = tokens;\n }\n\n static parse(parser) {\n if (parser.hasMore()) {\n var tokenArr = parser.consumeUntilWhitespace();\n parser.matchTokenType(\"WHITESPACE\");\n return new NakedString(tokenArr);\n }\n }\n\n evalStatically() {\n return this.resolve();\n }\n\n resolve(context) {\n return this.tokens\n .map(function (t) {\n return t.value;\n })\n .join(\"\");\n }\n}\n\n/**\n * BooleanLiteral - Represents true/false keywords\n *\n * Parses: true | false\n * Returns: boolean value\n */\nexport class BooleanLiteral extends Expression {\n static grammarName = \"boolean\";\n static expressionType = \"leaf\";\n\n constructor(value) {\n super();\n this.value = value;\n }\n\n static parse(parser) {\n var booleanLiteral = parser.matchToken(\"true\") || parser.matchToken(\"false\");\n if (!booleanLiteral) return;\n const value = booleanLiteral.value === \"true\";\n return new BooleanLiteral(value);\n }\n\n evalStatically() {\n return this.value;\n }\n\n resolve(context) {\n return this.value;\n }\n}\n\n/**\n * NullLiteral - Represents the null keyword\n *\n * Parses: null\n * Returns: null value\n */\nexport class NullLiteral extends Expression {\n static grammarName = \"null\";\n static expressionType = \"leaf\";\n\n constructor() {\n super();\n }\n\n static parse(parser) {\n if (parser.matchToken(\"null\")) {\n return new NullLiteral();\n }\n }\n\n evalStatically() {\n return null;\n }\n\n resolve(context) {\n return null;\n }\n}\n\n/**\n * NumberLiteral - Represents numeric values\n *\n * Parses: 42 | 3.14 | 1e10\n * Returns: number value\n */\nexport class NumberLiteral extends Expression {\n static grammarName = \"number\";\n static expressionType = \"leaf\";\n\n constructor(value, numberToken) {\n super();\n this.value = value;\n this.numberToken = numberToken;\n }\n\n static parse(parser) {\n var number = parser.matchTokenType(\"NUMBER\");\n if (!number) return;\n var numberToken = number;\n var value = parseFloat(/** @type {string} */ (number.value));\n return new NumberLiteral(value, numberToken);\n }\n\n evalStatically() {\n return this.value;\n }\n\n resolve(context) {\n return this.value;\n }\n}\n\n/**\n * StringLiteral - Represents string values (with optional template interpolation)\n *\n * Parses: \"hello\" | \"hello ${name}\"\n * Returns: string value\n */\nexport class StringLiteral extends Expression {\n static grammarName = \"string\";\n static expressionType = \"leaf\";\n\n constructor(stringToken, rawValue, args) {\n super();\n this.token = stringToken;\n this.rawValue = rawValue;\n this.args = args.length > 0 ? { parts: args } : null;\n }\n\n static parse(parser) {\n var stringToken = parser.matchTokenType(\"STRING\");\n if (!stringToken) return;\n var rawValue = /** @type {string} */ (stringToken.value);\n /** @type {any[]} */\n var args;\n if (stringToken.template) {\n var innerTokens = Tokenizer.tokenize(rawValue, true);\n var innerParser = parser.createChildParser(innerTokens);\n args = innerParser.parseStringTemplate();\n } else {\n args = [];\n }\n return new StringLiteral(stringToken, rawValue, args);\n }\n\n evalStatically() {\n if (this.args === null) return this.rawValue;\n return super.evalStatically();\n }\n\n resolve(context, { parts } = {}) {\n if (!parts || parts.length === 0) {\n return this.rawValue;\n }\n var returnStr = \"\";\n for (var i = 0; i < parts.length; i++) {\n var val = parts[i];\n if (val !== undefined) {\n returnStr += val;\n }\n }\n return returnStr;\n }\n}\n\n/**\n * ArrayLiteral - Represents array literals\n *\n * Parses: [1, 2, 3] | []\n * Returns: array value\n */\nexport class ArrayLiteral extends Expression {\n static grammarName = \"arrayLiteral\";\n static expressionType = \"leaf\";\n\n constructor(values) {\n super();\n this.values = values;\n this.args = { values };\n }\n\n static parse(parser) {\n if (!parser.matchOpToken(\"[\")) return;\n var values = [];\n if (!parser.matchOpToken(\"]\")) {\n do {\n var expr = parser.requireElement(\"expression\");\n values.push(expr);\n } while (parser.matchOpToken(\",\"));\n parser.requireOpToken(\"]\");\n }\n return new ArrayLiteral(values);\n }\n\n resolve(context, { values }) {\n return values;\n }\n}\n\n/**\n * ObjectKey - Represents an object key (string, identifier, or computed expression)\n *\n * Parses: \"key\" | key | [expression]\n * Returns: string key value\n */\nexport class ObjectKey extends Expression {\n static grammarName = \"objectKey\";\n\n constructor(key, expr, args) {\n super();\n this.key = key;\n this.expr = expr;\n this.args = args;\n }\n\n static parse(parser) {\n var token;\n if ((token = parser.matchTokenType(\"STRING\"))) {\n return new ObjectKey(token.value, null, null);\n } else if (parser.matchOpToken(\"[\")) {\n var expr = parser.parseElement(\"expression\");\n parser.requireOpToken(\"]\");\n return new ObjectKey(null, expr, { value: expr });\n } else {\n var key = \"\";\n do {\n token = parser.matchTokenType(\"IDENTIFIER\") || parser.matchOpToken(\"-\");\n if (token) key += token.value;\n } while (token);\n return new ObjectKey(key, null, null);\n }\n }\n\n evalStatically() {\n if (!this.expr) return this.key;\n return super.evalStatically();\n }\n\n resolve(ctx, { value } = {}) {\n if (this.expr) {\n return value;\n }\n return this.key;\n }\n}\n\n/**\n * ObjectLiteral - Represents object literals\n *\n * Parses: {foo: bar, baz: qux} | {}\n * Returns: object value\n */\nexport class ObjectLiteral extends Expression {\n static grammarName = \"objectLiteral\";\n static expressionType = \"leaf\";\n\n constructor(keyExpressions, valueExpressions) {\n super();\n this.keyExpressions = keyExpressions;\n this.valueExpressions = valueExpressions;\n this.args = { keys: keyExpressions, values: valueExpressions };\n }\n\n static parse(parser) {\n if (!parser.matchOpToken(\"{\")) return;\n var keyExpressions = [];\n var valueExpressions = [];\n if (!parser.matchOpToken(\"}\")) {\n do {\n var name = parser.requireElement(\"objectKey\");\n parser.requireOpToken(\":\");\n var value = parser.requireElement(\"expression\");\n valueExpressions.push(value);\n keyExpressions.push(name);\n } while (parser.matchOpToken(\",\") && !parser.peekToken(\"}\", 0, 'R_BRACE'));\n parser.requireOpToken(\"}\");\n }\n return new ObjectLiteral(keyExpressions, valueExpressions);\n }\n\n resolve(context, { keys, values }) {\n var returnVal = {};\n for (var i = 0; i < keys.length; i++) {\n returnVal[keys[i]] = values[i];\n }\n return returnVal;\n }\n}\n\n/**\n * NamedArgumentList - Represents named argument lists (with or without parentheses)\n *\n * Parses: foo: 1, bar: 2 or (foo: 1, bar: 2)\n * Returns: object with named arguments\n */\nexport class NamedArgumentList extends Expression {\n static grammarName = \"namedArgumentList\";\n\n constructor(fields, valueExpressions) {\n super();\n this.fields = fields;\n this.args = { values: valueExpressions };\n }\n\n static parseNaked(parser) {\n var fields = [];\n var valueExpressions = [];\n if (parser.currentToken().type === \"IDENTIFIER\") {\n do {\n var name = parser.requireTokenType(\"IDENTIFIER\");\n parser.requireOpToken(\":\");\n var value = parser.requireElement(\"expression\");\n valueExpressions.push(value);\n fields.push({ name: name, value: value });\n } while (parser.matchOpToken(\",\"));\n }\n return new NamedArgumentList(fields, valueExpressions);\n }\n\n static parse(parser) {\n if (!parser.matchOpToken(\"(\")) return;\n var elt = NamedArgumentList.parseNaked(parser);\n parser.requireOpToken(\")\");\n return elt;\n }\n\n resolve(context, { values }) {\n var returnVal = { _namedArgList_: true };\n for (var i = 0; i < values.length; i++) {\n var field = this.fields[i];\n returnVal[field.name.value] = values[i];\n }\n return returnVal;\n }\n}\n\n/**\n * NakedNamedArgumentList - Registration proxy for the naked (no parens) variant\n */\nexport class NakedNamedArgumentList extends Expression {\n static grammarName = \"nakedNamedArgumentList\";\n static parse = NamedArgumentList.parseNaked;\n}\n\n/**\n * StringLike - Matches either a quoted string or a naked string\n */\nexport class StringLike extends Expression {\n static grammarName = \"stringLike\";\n\n static parse(parser) {\n return parser.parseAnyOf([\"string\", \"nakedString\"]);\n }\n}", "// Parser - Unified API for parsing operations\n// Encapsulates both LanguageKernel and Tokens to provide a single parameter to grammar functions\n\nimport { ImplicitReturn } from '../parsetree/internals.js';\nimport { NakedString } from '../parsetree/expressions/literals.js';\n\n// ============================================================\n// Parse error types\n// ============================================================\n\nexport class ParseError {\n constructor(message, token, source, expected) {\n this.message = message;\n this.token = token;\n this.source = source;\n this.expected = expected || null;\n this.line = token?.line ?? null;\n this.column = token?.column ?? null;\n }\n}\n\nexport class ParseRecoverySentinel extends Error {\n constructor(parseError) {\n super(parseError.message);\n this.parseError = parseError;\n }\n}\n\nexport class Parser {\n #kernel;\n\n constructor(kernel, tokens) {\n this.#kernel = kernel;\n this.tokens = tokens;\n }\n\n toString() {\n this.tokens.matched\n }\n\n static formatErrors(errors) {\n if (!errors.length) return \"\";\n var source = errors[0].source;\n var lines = source.split(\"\\n\");\n\n var byLine = new Map();\n for (var e of errors) {\n var lineIdx = e.token?.line ? e.token.line - 1 : lines.length - 1;\n if (!byLine.has(lineIdx)) byLine.set(lineIdx, []);\n byLine.get(lineIdx).push(e);\n }\n\n var maxLine = Math.max(...byLine.keys()) + 1;\n var gutter = String(maxLine).length;\n var pad = \" \".repeat(gutter + 5);\n var sortedLines = [...byLine.entries()].sort((a, b) => a[0] - b[0]);\n var prevLineIdx = -1;\n var out = \"\";\n\n for (var [lineIdx, lineErrors] of sortedLines) {\n if (prevLineIdx !== -1 && lineIdx > prevLineIdx + 1) {\n out += \" \".repeat(gutter + 1) + \"...\\n\";\n } else if (prevLineIdx === -1 && lineIdx > 0) {\n out += \" \".repeat(gutter + 1) + \"...\\n\";\n }\n prevLineIdx = lineIdx;\n\n var lineNum = String(lineIdx + 1).padStart(gutter);\n var contextLine = lines[lineIdx] || \"\";\n out += \" \" + lineNum + \" | \" + contextLine + \"\\n\";\n\n lineErrors.sort((a, b) => (a.column || 0) - (b.column || 0));\n\n var underlineChars = Array(contextLine.length + 10).fill(\" \");\n for (var e of lineErrors) {\n var col = e.token?.line ? e.token.column : Math.max(0, contextLine.length - 1);\n var len = Math.max(1, e.token?.value?.length || 1);\n for (var i = 0; i < len; i++) underlineChars[col + i] = \"^\";\n }\n out += pad + underlineChars.join(\"\").trimEnd() + \"\\n\";\n\n for (var e of lineErrors) {\n var col = e.token?.line ? e.token.column : 0;\n out += pad + \" \".repeat(col) + e.message + \"\\n\";\n }\n }\n return out;\n }\n\n // ===========================\n // Token delegation methods\n // ===========================\n\n consumeWhitespace() {\n return this.tokens.consumeWhitespace();\n }\n\n requireOpToken(value) {\n var token = this.matchOpToken(value);\n if (token) return token;\n this.raiseExpected(value);\n }\n\n matchAnyOpToken(...ops) {\n return this.tokens.matchAnyOpToken(...ops);\n }\n\n matchAnyToken(...tokens) {\n return this.tokens.matchAnyToken(...tokens);\n }\n\n matchOpToken(value) {\n return this.tokens.matchOpToken(value);\n }\n\n requireTokenType(...types) {\n var token = this.matchTokenType(...types);\n if (token) return token;\n this.raiseExpected(...types);\n }\n\n matchTokenType(...types) {\n return this.tokens.matchTokenType(...types);\n }\n\n requireToken(value, type) {\n var token = this.matchToken(value, type);\n if (token) return token;\n this.raiseExpected(value);\n }\n\n peekToken(value, peek, type) {\n return this.tokens.peekToken(value, peek, type);\n }\n\n matchToken(value, type) {\n return this.tokens.matchToken(value, type);\n }\n\n consumeToken() {\n return this.tokens.consumeToken();\n }\n\n consumeUntil(value, type) {\n return this.tokens.consumeUntil(value, type);\n }\n\n lastWhitespace() {\n return this.tokens.lastWhitespace();\n }\n\n consumeUntilWhitespace() {\n return this.tokens.consumeUntilWhitespace();\n }\n\n hasMore() {\n return this.tokens.hasMore();\n }\n\n token(n, includeWhitespace) {\n return this.tokens.token(n, includeWhitespace);\n }\n\n currentToken() {\n return this.tokens.currentToken();\n }\n\n lastMatch() {\n return this.tokens.lastMatch();\n }\n\n pushFollow(str) {\n return this.tokens.pushFollow(str);\n }\n\n popFollow() {\n return this.tokens.popFollow();\n }\n\n pushFollows(...strs) {\n return this.tokens.pushFollows(...strs);\n }\n\n popFollows(count) {\n return this.tokens.popFollows(count);\n }\n\n clearFollows() {\n return this.tokens.clearFollows();\n }\n\n restoreFollows(f) {\n return this.tokens.restoreFollows(f);\n }\n\n get source() {\n return this.tokens.source;\n }\n\n get consumed() {\n return this.tokens.consumed;\n }\n\n get list() {\n return this.tokens.list;\n }\n\n createChildParser(tokens) {\n return new Parser(this.#kernel, tokens);\n }\n\n // ===========================\n // Kernel delegation methods\n // ===========================\n\n parseElement(type, root = null) {\n return this.#kernel.parseElement(type, this, root);\n }\n\n requireElement(type, message, root) {\n return this.#kernel.requireElement(type, this, message, root);\n }\n\n parseAnyOf(types) {\n return this.#kernel.parseAnyOf(types, this);\n }\n\n raiseError(message, expected) {\n message = message || \"Unexpected Token : \" + this.currentToken().value;\n var parseError = new ParseError(message, this.currentToken(), this.source, expected);\n throw new ParseRecoverySentinel(parseError);\n }\n\n raiseExpected(...expected) {\n var msg = expected.length === 1\n ? \"Expected '\" + expected[0] + \"' but found '\" + this.currentToken().value + \"'\"\n : \"Expected one of: \" + expected.map(e => \"'\" + e + \"'\").join(\", \");\n this.raiseError(msg, expected);\n }\n\n // ===========================\n // Parser-owned methods\n // ===========================\n\n parseStringTemplate() {\n var returnArr = [\"\"];\n do {\n returnArr.push(this.lastWhitespace());\n if (this.currentToken().value === \"$\") {\n this.consumeToken();\n var startingBrace = this.matchOpToken(\"{\");\n returnArr.push(this.requireElement(\"expression\"));\n if (startingBrace) {\n this.requireOpToken(\"}\");\n }\n returnArr.push(\"\");\n } else if (this.currentToken().value === \"\\\\\") {\n this.consumeToken(); // skip next\n this.consumeToken();\n } else {\n var token = this.consumeToken();\n returnArr[returnArr.length - 1] += token ? token.value : \"\";\n }\n } while (this.hasMore());\n returnArr.push(this.lastWhitespace());\n return returnArr;\n }\n\n commandBoundary(token) {\n if (\n token.value == \"end\" ||\n token.value == \"then\" ||\n token.value == \"else\" ||\n token.value == \"otherwise\" ||\n token.value == \")\" ||\n this.commandStart(token) ||\n this.featureStart(token) ||\n token.type == \"EOF\"\n ) {\n return true;\n }\n return false;\n }\n\n commandStart(token) {\n return this.#kernel.commandStart(token);\n }\n\n featureStart(token) {\n return this.#kernel.featureStart(token);\n }\n\n setParent(elt, parent) {\n if (typeof elt === 'object') {\n elt.parent = parent;\n if (typeof parent === 'object') {\n parent.children = (parent.children || new Set());\n parent.children.add(elt)\n }\n this.setParent(elt.next, parent);\n }\n }\n\n parseURLOrExpression() {\n var cur = this.currentToken();\n if (cur.value === \"/\" && cur.type === \"DIVIDE\") {\n // starts with / - naked URL\n var tokens = this.consumeUntilWhitespace();\n this.matchTokenType(\"WHITESPACE\");\n return new NakedString(tokens);\n }\n if (cur.type === \"IDENTIFIER\" && (cur.value === \"http\" || cur.value === \"https\" || cur.value === \"ws\" || cur.value === \"wss\")) {\n // starts with http/https - naked URL\n var tokens = this.consumeUntilWhitespace();\n this.matchTokenType(\"WHITESPACE\");\n return new NakedString(tokens);\n }\n return this.requireElement(\"expression\");\n }\n\n ensureTerminated(commandList) {\n var implicitReturn = new ImplicitReturn();\n var end = commandList;\n while (end.next) {\n end = end.next;\n }\n end.next = implicitReturn;\n }\n}\n", "// LanguageKernel - AST parsing for _hyperscript\nimport { Parser } from './parser.js';\nimport { EmptyCommandListCommand, UnlessStatementModifier, HyperscriptProgram, FailedFeature, FailedCommand } from '../parsetree/internals.js';\nimport { Command, Feature } from '../parsetree/base.js';\nimport { ParseRecoverySentinel } from './parser.js';\n\nexport class LanguageKernel {\n\n #grammar = {};\n #commands = {};\n #features = {};\n #leafExpressions = [];\n #indirectExpressions = [];\n #postfixExpressions = [];\n #unaryExpressions = [];\n #topExpressions = [];\n #assignableExpressions = [];\n\n constructor() {\n // Top-level program structure\n this.addGrammarElement(\"hyperscript\", this.parseHyperscriptProgram.bind(this));\n this.addGrammarElement(\"feature\", this.parseFeature.bind(this));\n\n // Command structure\n this.addGrammarElement(\"commandList\", this.parseCommandList.bind(this));\n this.addGrammarElement(\"command\", this.parseCommand.bind(this));\n this.addGrammarElement(\"indirectStatement\", this.parseIndirectStatement.bind(this));\n\n // Expression precedence chain (top to bottom)\n this.addGrammarElement(\"expression\", this.parseExpression.bind(this));\n this.addGrammarElement(\"assignableExpression\", this.parseAssignableExpression.bind(this));\n this.addGrammarElement(\"unaryExpression\", this.parseUnaryExpression.bind(this));\n this.addGrammarElement(\"postfixExpression\", this.parsePostfixExpression.bind(this));\n this.addGrammarElement(\"primaryExpression\", this.parsePrimaryExpression.bind(this));\n this.addGrammarElement(\"indirectExpression\", this.parseIndirectExpression.bind(this));\n this.addGrammarElement(\"leaf\", this.parseLeaf.bind(this));\n\n }\n\n parseFeature(parser) {\n if (parser.matchOpToken(\"(\")) {\n var featureElement = parser.requireElement(\"feature\");\n parser.requireOpToken(\")\");\n return featureElement;\n }\n var featureDefinition = this.#features[parser.currentToken().value || \"\"];\n if (featureDefinition) {\n return featureDefinition(parser);\n }\n }\n\n parseCommand(parser) {\n if (parser.matchOpToken(\"(\")) {\n const commandElement = parser.requireElement(\"command\");\n parser.requireOpToken(\")\");\n return commandElement;\n }\n var commandDefinition = this.#commands[parser.currentToken().value || \"\"];\n let commandElement;\n if (commandDefinition) {\n commandElement = commandDefinition(parser);\n } else if (parser.currentToken().type === \"IDENTIFIER\") {\n commandElement = parser.parseElement(\"pseudoCommand\");\n }\n if (commandElement) {\n return this.parseElement(\"indirectStatement\", parser, commandElement);\n }\n return commandElement;\n }\n\n parseCommandList(parser) {\n if (parser.hasMore()) {\n var keyword = parser.currentToken().value;\n var cmd;\n try {\n cmd = parser.parseElement(\"command\");\n } catch (e) {\n if (e instanceof ParseRecoverySentinel) {\n cmd = new FailedCommand(e.parseError, keyword);\n this.#syncToCommand(parser);\n } else {\n throw e;\n }\n }\n if (cmd) {\n parser.matchToken(\"then\");\n const next = parser.parseElement(\"commandList\");\n if (next) cmd.next = next;\n return cmd;\n }\n }\n return new EmptyCommandListCommand();\n }\n\n parseLeaf(parser) {\n var result = parser.parseAnyOf(this.#leafExpressions);\n // symbol is last so it doesn't consume any constants\n if (result == null) {\n return parser.parseElement(\"symbol\");\n }\n return result;\n }\n\n parseIndirectExpression(parser, root) {\n for (var i = 0; i < this.#indirectExpressions.length; i++) {\n var indirect = this.#indirectExpressions[i];\n root.endToken = parser.lastMatch();\n var result = this.parseElement(indirect, parser, root);\n if (result) {\n return result;\n }\n }\n return root;\n }\n\n parsePostfixExpression(parser) {\n var root = parser.parseElement(\"negativeNumber\");\n for (var i = 0; i < this.#postfixExpressions.length; i++) {\n var postfixType = this.#postfixExpressions[i];\n var result = this.parseElement(postfixType, parser, root);\n if (result) {\n return result;\n }\n }\n return root;\n }\n\n parseUnaryExpression(parser) {\n parser.matchToken(\"the\"); // optional \"the\"\n var result = parser.parseAnyOf(this.#unaryExpressions);\n if (result) return this.parseElement(\"indirectExpression\", parser, result);\n return parser.parseElement(\"postfixExpression\");\n }\n\n parseExpression(parser) {\n parser.matchToken(\"the\"); // optional \"the\"\n return parser.parseAnyOf(this.#topExpressions);\n }\n\n parseAssignableExpression(parser) {\n parser.matchToken(\"the\"); // optional \"the\"\n var expr = parser.parseElement(\"primaryExpression\");\n var checkExpr = expr;\n while (checkExpr && checkExpr.type === \"parenthesized\") {\n checkExpr = checkExpr.expr;\n }\n if (checkExpr && this.#assignableExpressions.includes(checkExpr.type)) {\n return expr;\n } else {\n parser.raiseError(\n \"A target expression must be writable. The expression type '\" + (checkExpr && checkExpr.type) + \"' is not.\"\n );\n }\n }\n\n parseIndirectStatement(parser, root) {\n if (parser.matchToken(\"unless\")) {\n root.endToken = parser.lastMatch();\n var conditional = parser.requireElement(\"expression\");\n var unless = new UnlessStatementModifier(root, conditional);\n root.parent = unless;\n return unless;\n }\n return root;\n }\n\n parsePrimaryExpression(parser) {\n var leaf = parser.parseElement(\"leaf\");\n if (leaf) {\n return this.parseElement(\"indirectExpression\", parser, leaf);\n }\n parser.raiseError(\"Unexpected value: \" + parser.currentToken().value);\n }\n\n parseHyperscriptProgram(parser) {\n var features = [];\n if (parser.hasMore()) {\n while (parser.currentToken().type !== \"EOF\") {\n var keyword = parser.currentToken().value;\n if (parser.featureStart(parser.currentToken()) || parser.currentToken().value === \"(\") {\n try {\n var feature = parser.requireElement(\"feature\");\n features.push(feature);\n parser.matchToken(\"end\"); // optional end\n } catch (e) {\n if (e instanceof ParseRecoverySentinel) {\n features.push(new FailedFeature(e.parseError, keyword));\n this.#syncToFeature(parser);\n } else {\n throw e;\n }\n }\n } else if (parser.currentToken().value === \"end\") {\n break; // scope terminator (e.g. behavior body) - leave for outer parser\n } else {\n // Unconsumed token between features - report and sync\n try {\n parser.raiseError();\n } catch (e) {\n if (e instanceof ParseRecoverySentinel) {\n features.push(new FailedFeature(e.parseError, keyword));\n this.#syncToFeature(parser);\n } else {\n throw e;\n }\n }\n }\n }\n }\n return new HyperscriptProgram(features);\n }\n\n use(plugin) {\n plugin(this)\n return this\n }\n\n initElt(parseElement, start, tokens) {\n parseElement.startToken = start;\n parseElement.programSource = tokens.source;\n }\n\n parseElement(type, parser, root = undefined) {\n var elementDefinition = this.#grammar[type];\n if (elementDefinition) {\n var tokens = parser.tokens;\n var start = tokens.currentToken();\n var parseElement = elementDefinition(parser, root);\n if (parseElement) {\n this.initElt(parseElement, start, tokens);\n parseElement.endToken = parseElement.endToken || tokens.lastMatch();\n var root = parseElement.root;\n while (root != null) {\n this.initElt(root, start, tokens);\n root = root.root;\n }\n }\n return parseElement;\n }\n }\n\n requireElement(type, parser, message, root) {\n var result = this.parseElement(type, parser, root);\n if (!result) parser.raiseError(message || \"Expected \" + type);\n return result;\n }\n\n parseAnyOf(types, parser) {\n for (var i = 0; i < types.length; i++) {\n var type = types[i];\n var expression = this.parseElement(type, parser);\n if (expression) {\n return expression;\n }\n }\n }\n\n addGrammarElement(name, definition) {\n if (this.#grammar[name]) {\n throw new Error(`Grammar element '${name}' already exists`);\n }\n this.#grammar[name] = definition;\n }\n\n addCommand(keyword, definition) {\n var commandGrammarType = keyword + \"Command\";\n this.#grammar[commandGrammarType] = definition;\n this.#commands[keyword] = definition;\n }\n\n addCommands(...commandClasses) {\n for (const CommandClass of commandClasses) {\n if (!CommandClass.keyword) {\n throw new Error(`Command class ${CommandClass.name} must have a static 'keyword' property`);\n }\n if (!CommandClass.parse) {\n throw new Error(`Command class ${CommandClass.name} must have a static 'parse' method`);\n }\n var keywords = Array.isArray(CommandClass.keyword) ? CommandClass.keyword : [CommandClass.keyword];\n for (var kw of keywords) this.addCommand(kw, CommandClass.parse);\n }\n }\n\n addFeatures(...featureClasses) {\n for (const FeatureClass of featureClasses) {\n if (!FeatureClass.keyword) {\n throw new Error(`Feature class ${FeatureClass.name} must have a static 'keyword' property`);\n }\n if (!FeatureClass.parse) {\n throw new Error(`Feature class ${FeatureClass.name} must have a static 'parse' method`);\n }\n this.addFeature(FeatureClass.keyword, FeatureClass.parse);\n }\n }\n\n addFeature(keyword, definition) {\n var featureGrammarType = keyword + \"Feature\";\n this.#grammar[featureGrammarType] = definition;\n this.#features[keyword] = definition;\n }\n\n /**\n * Register a parse element class based on its static metadata.\n * Commands need `static keyword`, expressions need `static grammarName`.\n */\n registerParseElement(ElementClass) {\n if (!ElementClass.parse) return;\n\n const parse = ElementClass.parse.bind(ElementClass);\n\n // Commands with keyword (supports string or array of strings)\n if (ElementClass.keyword && ElementClass.prototype instanceof Command) {\n var keywords = Array.isArray(ElementClass.keyword) ? ElementClass.keyword : [ElementClass.keyword];\n for (var kw of keywords) this.addCommand(kw, parse);\n return;\n }\n\n // Features with keyword (supports string or array of strings)\n if (ElementClass.keyword && ElementClass.prototype instanceof Feature) {\n var keywords = Array.isArray(ElementClass.keyword) ? ElementClass.keyword : [ElementClass.keyword];\n for (var kw of keywords) this.addFeature(kw, parse);\n return;\n }\n\n // Grammar elements with grammarName\n const name = ElementClass.grammarName;\n if (!name) return;\n\n switch (ElementClass.expressionType) {\n case 'leaf': this.addLeafExpression(name, parse); break;\n case 'indirect': this.addIndirectExpression(name, parse); break;\n case 'unary': this.addUnaryExpression(name, parse); break;\n case 'top': this.addTopExpression(name, parse); break;\n case 'postfix': this.addPostfixExpression(name, parse); break;\n default: this.addGrammarElement(name, parse); break;\n }\n\n if (ElementClass.assignable) {\n this.#assignableExpressions.push(name);\n }\n }\n\n /**\n * Register all exported parse element classes from a module.\n * Iterates over module exports and registers any class with\n * a static `parse` method and appropriate metadata.\n */\n registerModule(module) {\n for (const exported of Object.values(module)) {\n if (typeof exported === 'function' && exported.parse) {\n this.registerParseElement(exported);\n }\n }\n }\n\n addLeafExpression(name, definition) {\n this.#leafExpressions.push(name);\n this.addGrammarElement(name, definition);\n }\n\n addIndirectExpression(name, definition) {\n this.#indirectExpressions.push(name);\n this.addGrammarElement(name, definition);\n }\n\n addPostfixExpression(name, definition) {\n this.#postfixExpressions.push(name);\n this.addGrammarElement(name, definition);\n }\n\n addUnaryExpression(name, definition) {\n this.#unaryExpressions.push(name);\n this.addGrammarElement(name, definition);\n }\n\n addTopExpression(name, definition) {\n this.#topExpressions.push(name);\n this.addGrammarElement(name, definition);\n }\n\n commandStart(token) {\n return this.#commands[token.value || \"\"];\n }\n\n featureStart(token) {\n return this.#features[token.value || \"\"];\n }\n\n parseHyperScript(tokens) {\n var parser = new Parser(this, tokens);\n var result;\n var lastError = null;\n try {\n result = parser.parseElement(\"hyperscript\");\n if (tokens.hasMore()) parser.raiseError();\n } catch (e) {\n if (!(e instanceof ParseRecoverySentinel)) throw e;\n lastError = e.parseError;\n }\n if (!result) result = new HyperscriptProgram([]);\n result.errors = result.collectErrors();\n if (lastError) result.errors.push(lastError);\n return result;\n }\n\n #syncToFeature(parser) {\n parser.tokens.clearFollows();\n while (parser.hasMore() &&\n !parser.featureStart(parser.currentToken()) &&\n parser.currentToken().value !== \"end\" &&\n parser.currentToken().type !== \"EOF\") {\n parser.tokens.consumeToken();\n }\n }\n\n #syncToCommand(parser) {\n parser.tokens.clearFollows();\n while (parser.hasMore() &&\n !parser.commandBoundary(parser.currentToken())) {\n parser.tokens.consumeToken();\n }\n // consume 'then' if that's what we landed on\n if (parser.hasMore() && parser.currentToken().value === \"then\") {\n parser.tokens.consumeToken();\n }\n }\n\n parse(tokenizer, src) {\n var tokens = tokenizer.tokenize(src);\n var parser = new Parser(this, tokens);\n var result, lastError;\n try {\n if (parser.commandStart(tokens.currentToken())) {\n result = this.requireElement(\"commandList\", parser);\n if (tokens.hasMore()) parser.raiseError();\n parser.ensureTerminated(result);\n } else if (parser.featureStart(tokens.currentToken())) {\n result = this.requireElement(\"hyperscript\", parser);\n if (tokens.hasMore()) parser.raiseError();\n } else {\n result = this.requireElement(\"expression\", parser);\n if (tokens.hasMore()) parser.raiseError();\n }\n } catch (e) {\n if (!(e instanceof ParseRecoverySentinel)) throw e;\n lastError = e.parseError;\n }\n if (!result && lastError) {\n result = { type: \"empty\", errors: [lastError] };\n } else if (result) {\n result.errors = result.collectErrors();\n if (lastError) result.errors.push(lastError);\n }\n return result;\n }\n\n}\n", "// Configuration for _hyperscript\n\nexport const config = {\n attributes: \"_, script, data-script\",\n defaultTransition: \"all 500ms ease-in\",\n disableSelector: \"[disable-scripting], [data-disable-scripting]\",\n fetchThrowsOn: [/4.*/, /5.*/],\n hideShowStrategies: {},\n debugMode: false,\n logAll: false,\n mutatingMethods: {\n Array: [\"push\", \"pop\", \"shift\", \"unshift\", \"splice\", \"sort\", \"reverse\", \"fill\", \"copyWithin\"],\n Set: [\"add\", \"delete\", \"clear\"],\n Map: [\"set\", \"delete\", \"clear\"],\n },\n}\n", "// Type conversions for _hyperscript\n\nclass HyperscriptFormData {\n result = {};\n\n addElement(node) {\n if (node.name == undefined || node.value == undefined) return;\n if (node.type === \"radio\" && !node.checked) return;\n\n var name = node.name;\n var value;\n\n if (node.type === \"checkbox\") {\n value = node.checked ? [node.value] : undefined;\n } else if (node.type === \"select-multiple\") {\n value = Array.from(node.options).filter(o => o.selected).map(o => o.value);\n } else {\n value = node.value;\n }\n\n if (value == undefined) return;\n\n if (this.result[name] == undefined) {\n this.result[name] = value;\n } else {\n var existing = Array.isArray(this.result[name]) ? this.result[name] : [this.result[name]];\n this.result[name] = existing.concat(value);\n }\n }\n\n addContainer(node) {\n if (node.name != undefined && node.value != undefined) {\n this.addElement(node);\n return;\n }\n if (node.querySelectorAll) {\n node.querySelectorAll(\"input,select,textarea\").forEach(child => this.addElement(child));\n }\n }\n}\n\nfunction _toHTML(value) {\n if (value instanceof Array) {\n return value.map(item => _toHTML(item)).join(\"\");\n }\n if (value instanceof HTMLElement) {\n return value.outerHTML;\n }\n if (value instanceof NodeList) {\n var result = \"\";\n for (var i = 0; i < value.length; i++) {\n if (value[i] instanceof HTMLElement) {\n result += value[i].outerHTML;\n }\n }\n return result;\n }\n if (value.toString) {\n return value.toString();\n }\n return \"\";\n}\n\nexport const conversions = {\n dynamicResolvers: [\n // Fixed-point number conversion\n function(str, value) {\n if (str === \"Fixed\") {\n return Number(value).toFixed();\n } else if (str.startsWith(\"Fixed:\")) {\n let num = str.split(\":\")[1];\n return Number(value).toFixed(parseInt(num));\n }\n },\n // Values conversion - extracts form values from DOM nodes\n function(str, node, runtime) {\n if (str !== \"Values\") return;\n var formData = new HyperscriptFormData();\n runtime.implicitLoop(node, (node) => formData.addContainer(node));\n return formData.result;\n },\n ],\n String: function (val) {\n if (val.toString) {\n return val.toString();\n } else {\n return \"\" + val;\n }\n },\n Int: function (val) {\n return parseInt(val);\n },\n Float: function (val) {\n return parseFloat(val);\n },\n Number: function (val) {\n return Number(val);\n },\n Boolean: function (val) {\n return !!val;\n },\n Date: function (val) {\n return new Date(val);\n },\n Array: function (val) {\n return Array.from(val);\n },\n JSON: function (val) {\n if (typeof Response !== \"undefined\" && val instanceof Response) return val.json();\n return JSON.parse(val);\n },\n JSONString: function (val) {\n return JSON.stringify(val);\n },\n Object: function (val) {\n if (val instanceof String) {\n val = val.toString();\n }\n if (typeof val === \"string\") {\n return JSON.parse(val);\n } else {\n return Object.assign({}, val);\n }\n },\n FormEncoded: function (val) {\n return new URLSearchParams(val).toString();\n },\n Set: function (val) {\n return new Set(val);\n },\n Map: function (val) {\n return new Map(Object.entries(val));\n },\n Keys: function (val) {\n if (val instanceof Map) return Array.from(val.keys());\n return Object.keys(val);\n },\n Entries: function (val) {\n if (val instanceof Map) return Array.from(val.entries());\n return Object.entries(val);\n },\n Reversed: function (val) {\n return Array.from(val).reverse();\n },\n Unique: function (val) {\n return [...new Set(val)];\n },\n Flat: function (val) {\n return Array.from(val).flat();\n },\n HTML: _toHTML,\n Stream: function () {\n throw new Error(\"The Stream conversion requires the SSE extension. \" +\n \"Include dist/ext/sse.js or dist/ext/sse.esm.js after hyperscript.\");\n },\n Fragment: function (val, runtime) {\n var frag = document.createDocumentFragment();\n runtime.implicitLoop(val, (val) => {\n if (val instanceof Node) frag.append(val);\n else {\n var temp = document.createElement(\"template\");\n temp.innerHTML = val;\n frag.append(temp.content);\n }\n });\n return frag;\n },\n}\n", "// Cookie management for _hyperscript\n\nexport class CookieJar {\n #parseCookies() {\n if (!document.cookie) return [];\n return document.cookie.split(\"; \").map(entry => {\n var eq = entry.indexOf(\"=\");\n return { name: entry.slice(0, eq), value: decodeURIComponent(entry.slice(eq + 1)) };\n });\n }\n\n get(target, prop) {\n if (prop === 'then') {\n return null; // prevent Promise detection\n } else if (prop === 'length') {\n return this.#parseCookies().length;\n } else if (prop === 'clear') {\n return (name) => {\n document.cookie = name + \"=;expires=Thu, 01 Jan 1970 00:00:00 GMT\";\n };\n } else if (prop === 'clearAll') {\n return () => {\n for (const cookie of this.#parseCookies()) {\n document.cookie = cookie.name + \"=;expires=Thu, 01 Jan 1970 00:00:00 GMT\";\n }\n };\n } else if (prop === Symbol.iterator) {\n var cookies = this.#parseCookies();\n return cookies[Symbol.iterator].bind(cookies);\n } else if (typeof prop === \"string\") {\n if (!isNaN(prop)) {\n return this.#parseCookies()[parseInt(prop)];\n }\n var match = this.#parseCookies().find(c => c.name === prop);\n return match ? match.value : undefined;\n }\n }\n\n set(target, prop, value) {\n var parts = [];\n if (typeof value === 'string') {\n parts.push(encodeURIComponent(value));\n parts.push(\"samesite=lax\");\n } else {\n parts.push(encodeURIComponent(value.value));\n if (value.expires) parts.push(\"expires=\" + value.expires);\n if (value.maxAge) parts.push(\"max-age=\" + value.maxAge);\n if (value.partitioned) parts.push(\"partitioned=\" + value.partitioned);\n if (value.path) parts.push(\"path=\" + value.path);\n if (value.samesite) parts.push(\"samesite=\" + value.samesite);\n if (value.secure) parts.push(\"secure\");\n }\n document.cookie = String(prop) + \"=\" + parts.join(\";\");\n return true;\n }\n\n proxy() {\n return new Proxy({}, this)\n }\n}\n\n", "// Collection utilities for _hyperscript\n\nexport const SHOULD_AUTO_ITERATE_SYM = Symbol()\n\nexport class ElementCollection {\n constructor(css, relativeToElement, escape, runtime) {\n this._css = css;\n this.relativeToElement = relativeToElement;\n this.escape = escape;\n this._runtime = runtime;\n this[SHOULD_AUTO_ITERATE_SYM] = true;\n }\n\n get css() {\n if (this.escape) {\n return this._runtime.escapeSelector(this._css);\n } else {\n return this._css;\n }\n }\n\n get className() {\n return this._css.slice(1);\n }\n\n get id() {\n return this.className;\n }\n\n contains(elt) {\n for (let element of this) {\n if (element.contains(elt)) {\n return true;\n }\n }\n return false;\n }\n\n get length() {\n return this.selectMatches().length;\n }\n\n [Symbol.iterator]() {\n let query = this.selectMatches();\n return query [Symbol.iterator]();\n }\n\n /** @returns {NodeList} all elements matching this.css under the root node */\n selectMatches() {\n var root = this._runtime.getRootNode(this.relativeToElement);\n return this._runtime.resolveQuery(root, this.css);\n }\n}\n\nexport class TemplatedQueryElementCollection extends ElementCollection {\n constructor(css, relativeToElement, templateParts, runtime) {\n super(css, relativeToElement, false, runtime);\n this.templateParts = templateParts;\n this.elements = templateParts.filter(elt => elt instanceof Element);\n }\n\n get css() {\n let rv = \"\", i = 0\n for (const val of this.templateParts) {\n if (val instanceof Element) {\n rv += \"[data-hs-query-id='\" + i++ + \"']\";\n } else rv += val;\n }\n return rv;\n }\n\n [Symbol.iterator]() {\n this.elements.forEach((el, i) => el.dataset.hsQueryId = i);\n const rv = super[Symbol.iterator]();\n this.elements.forEach(el => el.removeAttribute('data-hs-query-id'));\n return rv;\n }\n}\n\nexport class RegExpIterator {\n constructor(re, str) {\n this.re = re;\n this.str = str;\n }\n\n next() {\n const match = this.re.exec(this.str);\n if (match === null) return { done: true };\n if (match[0].length === 0) this.re.lastIndex++;\n return { value: match };\n }\n}\n\nexport class RegExpIterable {\n constructor(re, flags, str) {\n this.re = re;\n this.flags = flags;\n this.str = str;\n }\n\n [Symbol.iterator]() {\n return new RegExpIterator(new RegExp(this.re, this.flags), this.str);\n }\n}\n\nexport class HyperscriptModule extends EventTarget {\n constructor(mod) {\n super();\n this.module = mod;\n }\n\n toString() {\n return this.module.id;\n }\n}\n", "// Runtime - Execution engine for _hyperscript\nimport { config } from '../config.js';\nimport { conversions } from './conversions.js';\nimport { CookieJar } from './cookies.js';\nimport { ElementCollection, SHOULD_AUTO_ITERATE_SYM } from './collections.js';\nimport { Parser } from '../parser.js';\n\n// cookie jar proxy for runtime\nlet cookies = new CookieJar().proxy();\n\nexport class Context {\n constructor(owner, feature, hyperscriptTarget, event, runtime, globalScope, kernel, tokenizer) {\n this.meta = {\n parser: kernel,\n tokenizer: tokenizer,\n runtime,\n owner: owner,\n feature: feature,\n iterators: {},\n ctx: this\n }\n this.locals = {\n cookies: cookies\n };\n if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n Object.defineProperty(this.locals, 'clipboard', {\n get() { return navigator.clipboard.readText(); },\n set(v) { navigator.clipboard.writeText(String(v)); },\n enumerable: false,\n configurable: true\n });\n }\n if (typeof window !== \"undefined\" && window.getSelection) {\n Object.defineProperty(this.locals, 'selection', {\n get() { return window.getSelection().toString(); },\n enumerable: true,\n configurable: true\n });\n }\n this.me = hyperscriptTarget;\n this.you = undefined\n this.result = undefined\n this.beingTested = null\n this.event = event;\n this.target = event?.target ?? null;\n this.detail = event?.detail ?? null;\n this.sender = event?.detail?.sender ?? null;\n this.body = \"document\" in globalScope ? document.body : null;\n runtime.addFeatures(owner, this);\n }\n}\n\n\nexport class Runtime {\n\n static HALT = {};\n HALT = Runtime.HALT;\n\n #kernel;\n #tokenizer;\n #globalScope;\n #reactivity;\n #morphEngine;\n #scriptAttrs = null;\n\n constructor(globalScope, kernel, tokenizer, reactivity, morphEngine) {\n this.#globalScope = globalScope;\n this.#kernel = kernel;\n this.#tokenizer = tokenizer;\n this.#reactivity = reactivity;\n this.#morphEngine = morphEngine;\n }\n\n get globalScope() {\n return this.#globalScope;\n }\n\n get reactivity() {\n return this.#reactivity;\n }\n\n // =================================================================\n // Core execution engine\n // =================================================================\n\n unifiedExec(command, ctx) {\n while (true) {\n if (config.debugMode) {\n var target = ctx.meta.owner || ctx.me;\n var eventResult = this.triggerEvent(\n target,\n \"hyperscript:beforeEval\",\n { command: command, ctx: ctx },\n );\n if (!eventResult) {\n if (ctx.meta.onHalt) ctx.meta.onHalt();\n return;\n }\n }\n var afterFired = false;\n\n try {\n var next = this.unifiedEval(command, ctx);\n } catch (e) {\n if (config.debugMode) {\n this.triggerEvent(target, \"hyperscript:afterEval\", {\n command: command,\n ctx: ctx,\n error: e,\n });\n afterFired = true;\n }\n\n if (ctx.meta.handlingFinally) {\n console.error(\" Exception in finally block: \", e);\n next = Runtime.HALT;\n } else {\n this.registerHyperTrace(ctx, e);\n if (ctx.meta.errorHandler && !ctx.meta.handlingError) {\n ctx.meta.handlingError = true;\n ctx.locals[ctx.meta.errorSymbol] = e;\n command = ctx.meta.errorHandler;\n continue;\n } else {\n ctx.meta.currentException = e;\n next = Runtime.HALT;\n }\n }\n }\n\n if (config.debugMode && !afterFired) {\n this.triggerEvent(target, \"hyperscript:afterEval\", {\n command: command,\n ctx: ctx,\n next: next,\n });\n }\n\n if (next == null) {\n throw new Error(\"Command \" + (command.type || \"unknown\") + \" did not return a next element to execute\");\n } else if (next.then) {\n next.then(resolvedNext => {\n this.unifiedExec(resolvedNext, ctx);\n }).catch(reason => {\n this.unifiedExec({\n resolve: function(){\n throw reason;\n }\n }, ctx);\n });\n return;\n } else if (next === Runtime.HALT) {\n if (ctx.meta.finallyHandler && !ctx.meta.handlingFinally) {\n ctx.meta.handlingFinally = true;\n command = ctx.meta.finallyHandler;\n } else {\n if (ctx.meta.onHalt) {\n ctx.meta.onHalt();\n }\n if (ctx.meta.currentException) {\n if (ctx.meta.reject) {\n ctx.meta.reject(ctx.meta.currentException);\n return;\n } else {\n throw ctx.meta.currentException;\n }\n } else {\n return;\n }\n }\n } else {\n command = next;\n }\n }\n }\n\n unifiedEval(parseElement, ctx) {\n var async = false;\n var evaluatedArgs = {};\n\n if (parseElement.args) {\n for (var [name, argument] of Object.entries(parseElement.args)) {\n if (argument == null) {\n evaluatedArgs[name] = null;\n } else if (Array.isArray(argument)) {\n var arr = [];\n for (var j = 0; j < argument.length; j++) {\n var element = argument[j];\n if (element == null) {\n arr.push(null);\n } else if (element.evaluate) {\n var value = element.evaluate(ctx);\n if (value && value.then) {\n async = true;\n }\n arr.push(value);\n } else {\n arr.push(element);\n }\n }\n evaluatedArgs[name] = arr;\n } else if (argument.evaluate) {\n var value = argument.evaluate(ctx);\n if (value && value.then) {\n async = true;\n }\n evaluatedArgs[name] = value;\n } else {\n evaluatedArgs[name] = argument;\n }\n }\n }\n if (async) {\n return new Promise((resolve, reject) => {\n var keys = Object.keys(evaluatedArgs);\n var values = Object.values(evaluatedArgs).map(v =>\n Array.isArray(v) ? Promise.all(v) : v\n );\n Promise.all(values)\n .then(function (resolved) {\n try {\n var finalArgs = {};\n keys.forEach((k, i) => finalArgs[k] = resolved[i]);\n resolve(parseElement.resolve(ctx, finalArgs));\n } catch (e) {\n reject(e);\n }\n })\n .catch(function (reason) {\n reject(reason);\n });\n });\n } else {\n return parseElement.resolve(ctx, evaluatedArgs);\n }\n }\n\n findNext(command, context) {\n if (command) {\n if (command.resolveNext) {\n return command.resolveNext(context);\n } else if (command.next) {\n return command.next;\n } else {\n return this.findNext(command.parent, context);\n }\n }\n }\n\n\n // =================================================================\n // Context and scope\n // =================================================================\n\n makeContext(owner, feature, hyperscriptTarget, event) {\n return new Context(owner, feature, hyperscriptTarget, event, this, this.#globalScope, this.#kernel, this.#tokenizer)\n }\n\n getHyperscriptFeatures(elt) {\n var data = this.getInternalData(elt);\n if (!data.features) {\n data.features = {};\n }\n return data.features;\n }\n\n addFeatures(owner, ctx) {\n if (owner) {\n Object.assign(ctx.locals, this.getHyperscriptFeatures(owner));\n this.addFeatures(owner.parentElement, ctx);\n }\n }\n\n // =================================================================\n // Symbol and property resolution\n // =================================================================\n\n #isReservedWord(str) {\n return [\"meta\", \"it\", \"result\", \"locals\", \"event\", \"target\", \"detail\", \"sender\", \"body\"].includes(str)\n }\n\n #isHyperscriptContext(context) {\n return context instanceof Context;\n }\n\n resolveSymbol(str, context, type, targetElement) {\n if (str === \"me\" || str === \"my\" || str === \"I\") return context.me;\n if (str === \"it\" || str === \"its\") return context.beingTested ?? context.result;\n if (str === \"result\") return context.result;\n if (str === \"you\" || str === \"your\" || str === \"yourself\") return context.you;\n\n if (type === \"global\") {\n if (this.reactivity.isTracking) this.reactivity.trackGlobalSymbol(str);\n var val = this.#globalScope[str];\n this.#trackMutation(val);\n return val;\n }\n if (type === \"element\") {\n if (this.reactivity.isTracking) this.reactivity.trackElementSymbol(str, context.meta.owner);\n var val = this.#getElementScope(context)[str];\n this.#trackMutation(val);\n return val;\n }\n if (type === \"inherited\") {\n var inherited = this.#resolveInherited(str, context, targetElement);\n if (this.reactivity.isTracking) {\n var trackElement = inherited.element || targetElement || context.meta?.owner;\n if (trackElement) {\n this.reactivity.trackElementSymbol(str, trackElement);\n }\n }\n this.#trackMutation(inherited.value);\n return inherited.value;\n }\n // local scope resolution: meta.context (set only inside `on click[...]`\n // filter expressions to the current event) \u2192 locals \u2192 element \u2192 global.\n // Event destructuring in handler bodies is explicit: `on click(x, y)`\n // copies event/detail props into ctx.locals at handler entry, so in body\n // code `x` is a real local, not a fallback lookup.\n if (context.meta?.context) {\n var fromMetaContext = context.meta.context[str];\n if (typeof fromMetaContext !== \"undefined\") return fromMetaContext;\n if (context.meta.context.detail) {\n fromMetaContext = context.meta.context.detail[str];\n if (typeof fromMetaContext !== \"undefined\") return fromMetaContext;\n }\n }\n var fromContext = this.#isHyperscriptContext(context) && !this.#isReservedWord(str)\n ? context.locals[str] : context[str];\n if (typeof fromContext !== \"undefined\") return fromContext;\n\n // element scope\n var elementScope = this.#getElementScope(context);\n fromContext = elementScope[str];\n if (typeof fromContext !== \"undefined\") {\n if (this.reactivity.isTracking) this.reactivity.trackElementSymbol(str, context.meta.owner);\n this.#trackMutation(fromContext);\n return fromContext;\n }\n // global scope (or not found - track as global so we catch the first write)\n if (this.reactivity.isTracking) this.reactivity.trackGlobalSymbol(str);\n var val = this.#globalScope[str];\n this.#trackMutation(val);\n return val;\n }\n\n setSymbol(str, context, type, value, targetElement) {\n if (type === \"global\") {\n this.#globalScope[str] = value;\n this.reactivity.notifyGlobalSymbol(str);\n return;\n }\n if (type === \"element\") {\n this.#getElementScope(context)[str] = value;\n this.reactivity.notifyElementSymbol(str, context.meta.owner);\n return;\n }\n if (type === \"inherited\") {\n var inherited = this.#resolveInherited(str, context, targetElement);\n if (inherited.element) {\n this.getInternalData(inherited.element).elementScope[str] = value;\n this.reactivity.notifyElementSymbol(str, inherited.element);\n } else {\n var owner = targetElement || context.meta?.owner;\n if (owner) {\n var internalData = this.getInternalData(owner);\n if (!internalData.elementScope) internalData.elementScope = {};\n internalData.elementScope[str] = value;\n this.reactivity.notifyElementSymbol(str, owner);\n }\n }\n return;\n }\n // local scope resolution (tries locals \u2192 element \u2192 global chain)\n if (this.#isHyperscriptContext(context) && !this.#isReservedWord(str) && typeof context.locals[str] !== \"undefined\") {\n context.locals[str] = value;\n return;\n }\n var elementScope = this.#getElementScope(context);\n if (typeof elementScope[str] !== \"undefined\") {\n elementScope[str] = value;\n this.reactivity.notifyElementSymbol(str, context.meta.owner);\n } else if (this.#isHyperscriptContext(context) && !this.#isReservedWord(str)) {\n context.locals[str] = value;\n } else {\n context[str] = value;\n }\n }\n\n getInternalData(elt) {\n if (!elt._hyperscript) {\n elt._hyperscript = {};\n }\n return elt._hyperscript;\n }\n\n #resolveInherited(str, context, startElement) {\n var elt = startElement || (context.meta && context.meta.owner);\n while (elt) {\n var internalData = elt._hyperscript;\n if (internalData && internalData.elementScope && str in internalData.elementScope) {\n return { value: internalData.elementScope[str], element: elt };\n }\n // Check dom-scope attribute for scope control\n var domScope = elt.getAttribute && elt.getAttribute('dom-scope');\n if (domScope) {\n if (domScope === 'isolated') {\n return { value: undefined, element: null };\n }\n // \"closest \" - jump to matching ancestor\n var match = domScope.match(/^closest\\s+(.+)/);\n if (match) {\n elt = elt.parentElement && elt.parentElement.closest(match[1]);\n continue;\n }\n // \"parent of \" - jump to the parent of the nearest matching ancestor\n match = domScope.match(/^parent\\s+of\\s+(.+)/);\n if (match) {\n var target = elt.closest(match[1]);\n elt = target && target.parentElement;\n continue;\n }\n }\n elt = elt.parentElement;\n }\n return { value: undefined, element: null };\n }\n\n #getElementScope(context) {\n var elt = context.meta && context.meta.owner;\n if (elt) {\n var internalData = this.getInternalData(elt);\n var scopeName = \"elementScope\";\n if (context.meta.feature && context.meta.feature.behavior) {\n scopeName = context.meta.feature.behavior + \"Scope\";\n }\n var elementScope = internalData[scopeName];\n if (!elementScope) {\n elementScope = {};\n internalData[scopeName] = elementScope;\n }\n return elementScope;\n } else {\n return {};\n }\n }\n\n #flatGet(root, property, getter) {\n if (root != null) {\n var val = getter(root, property);\n if (typeof val !== \"undefined\") {\n return val;\n }\n if (this.shouldAutoIterate(root)) {\n var result = [];\n for (var component of root) {\n var componentValue = getter(component, property);\n result.push(componentValue);\n }\n return result;\n }\n }\n }\n\n resolveProperty(root, property) {\n if (this.reactivity.isTracking) this.reactivity.trackProperty(root, property);\n return this.#flatGet(root, property, (root, property) => root[property])\n }\n\n /**\n * Set a property on an object and notify the reactivity system.\n * @param {Object} obj - DOM element or plain JS object\n * @param {string} property\n * @param {any} value\n */\n setProperty(obj, property, value) {\n obj[property] = value;\n this.reactivity.notifyProperty(obj);\n }\n\n /**\n * Notify the reactivity system that an object was mutated in-place.\n * Call this after operations like push, splice, append, etc.\n * @param {Object} obj - The mutated object\n */\n notifyMutation(obj) {\n this.reactivity.notifyProperty(obj);\n }\n\n morph(elt, content) {\n this.#morphEngine.morph(elt, content, {\n beforeNodeRemoved: (node) => {\n if (node.nodeType === 1) this.cleanup(node);\n },\n afterNodeAdded: (node) => {\n if (node.nodeType === 1) this.processNode(node);\n },\n afterNodeMorphed: (node) => {\n if (node.nodeType === 1) this.processNode(node);\n }\n });\n }\n\n replaceInDom(target, value) {\n this.implicitLoop(target, (elt) => {\n var parent = elt.parentElement;\n if (value instanceof Node) {\n elt.replaceWith(value.cloneNode(true));\n } else {\n elt.replaceWith(this.convertValue(value, \"Fragment\"));\n }\n if (parent) this.processNode(parent);\n });\n }\n\n /**\n * Check if a method call is known to mutate its receiver, and notify if so.\n * @param {Object} target - The object the method was called on\n * @param {string} methodName - The method name\n */\n maybeNotify(target, methodName) {\n if (target == null || typeof target !== \"object\") return;\n var typeName = target.constructor && target.constructor.name;\n var methods = typeName && config.mutatingMethods[typeName];\n if (methods && methods.includes(methodName)) {\n this.notifyMutation(target);\n }\n }\n\n #trackMutation(val) {\n if (this.reactivity.isTracking && val != null && typeof val === \"object\") {\n this.reactivity.trackProperty(val, \"__mutation__\");\n }\n }\n\n resolveQuery(root, css) {\n if (this.reactivity.isTracking) this.reactivity.trackQuery(root);\n return root.querySelectorAll(css);\n }\n\n resolveAttribute(root, property) {\n if (this.reactivity.isTracking) this.reactivity.trackAttribute(root, property);\n return this.#flatGet(root, property, (root, property) => root.getAttribute && root.getAttribute(property))\n }\n\n resolveStyle(root, property) {\n return this.#flatGet(root, property, (root, property) => root.style && root.style[property])\n }\n\n resolveComputedStyle(root, property) {\n return this.#flatGet(root, property, (root, property) => getComputedStyle(root).getPropertyValue(property))\n }\n\n assignToNamespace(elt, nameSpace, name, value) {\n let root\n if (elt == null || (typeof document !== \"undefined\" && elt === document.body)) {\n root = this.#globalScope;\n } else {\n root = this.getHyperscriptFeatures(elt);\n }\n var propertyName;\n while ((propertyName = nameSpace.shift()) !== undefined) {\n var newRoot = root[propertyName];\n if (newRoot == null) {\n newRoot = {};\n root[propertyName] = newRoot;\n }\n root = newRoot;\n }\n root[name] = value;\n }\n\n // =================================================================\n // Collection and iteration utilities\n // =================================================================\n\n #isArrayLike(value) {\n return Array.isArray(value) ||\n (typeof NodeList !== 'undefined' && (value instanceof NodeList || value instanceof HTMLCollection || value instanceof FileList));\n }\n\n #isIterable(value) {\n return typeof value === 'object'\n && Symbol.iterator in value\n && typeof value[Symbol.iterator] === 'function';\n }\n\n shouldAutoIterate(value) {\n return (value != null && value[SHOULD_AUTO_ITERATE_SYM]) || this.#isArrayLike(value);\n }\n\n forEach(value, func) {\n if (value == null) {\n // do nothing\n } else if (this.#isIterable(value)) {\n for (const nth of value) {\n func(nth);\n }\n } else if (this.#isArrayLike(value)) {\n for (var i = 0; i < value.length; i++) {\n func(value[i]);\n }\n } else {\n func(value);\n }\n }\n\n implicitLoop(value, func) {\n if (this.shouldAutoIterate(value)) {\n for (const x of value) func(x);\n } else {\n func(value);\n }\n }\n\n /**\n * Iterate over targets with a when condition, applying forward or reverse per element.\n * Supports async conditions transparently -- returns a Promise if any condition is async.\n */\n implicitLoopWhen(targets, whenExpr, context, forwardFn, reverseFn) {\n var elements = [];\n this.implicitLoop(targets, function (elt) { elements.push(elt); });\n\n var conditions = elements.map(function (elt) {\n context.beingTested = elt;\n return whenExpr.evaluate(context);\n });\n context.beingTested = null;\n\n var hasPromise = conditions.some(function (c) { return c && typeof c.then === \"function\"; });\n if (hasPromise) {\n return Promise.all(conditions).then((results) => {\n context.result = this.#applyWhenResults(elements, results, forwardFn, reverseFn);\n });\n } else {\n context.result = this.#applyWhenResults(elements, conditions, forwardFn, reverseFn);\n }\n }\n\n #applyWhenResults(elements, results, forwardFn, reverseFn) {\n var matched = [];\n for (var i = 0; i < elements.length; i++) {\n if (results[i]) { forwardFn(elements[i]); matched.push(elements[i]); }\n else reverseFn(elements[i]);\n }\n return matched;\n }\n\n // =================================================================\n // Type system\n // =================================================================\n\n convertValue(value, type) {\n var dynamicResolvers = conversions.dynamicResolvers;\n for (var i = 0; i < dynamicResolvers.length; i++) {\n var dynamicResolver = dynamicResolvers[i];\n var converted = dynamicResolver(type, value, this);\n if (converted !== undefined) {\n return converted;\n }\n }\n if (value == null) {\n return null;\n }\n var converter = conversions[type];\n if (converter) {\n return converter(value, this);\n }\n throw new Error(\"Unknown conversion : \" + type);\n }\n\n evaluateNoPromise(elt, ctx) {\n let result = elt.evaluate(ctx);\n if (result && typeof result.then === \"function\") {\n throw new Error(elt.sourceFor() + \" returned a Promise in a context that they are not allowed.\");\n }\n return result;\n }\n\n typeCheck(value, typeString, nullOk) {\n if (value == null && nullOk) {\n return true;\n }\n var typeName = Object.prototype.toString.call(value).slice(8, -1);\n if (typeName === typeString) return true;\n // instanceof fallback for base classes\n var ctor = typeof globalThis !== \"undefined\" && globalThis[typeString];\n return typeof ctor === \"function\" && value instanceof ctor;\n }\n\n nullCheck(value, elt) {\n if (value == null) {\n throw new Error(\"'\" + elt.sourceFor() + \"' is null\");\n }\n }\n\n isEmpty(value) {\n return value == undefined || value.length === 0;\n }\n\n doesExist(value) {\n if(value == null){\n return false;\n }\n if (this.shouldAutoIterate(value)) {\n for (const elt of value) {\n return true;\n }\n return false;\n }\n return true;\n }\n\n // =================================================================\n // DOM operations\n // =================================================================\n\n matchesSelector(elt, selector) {\n return elt.matches && elt.matches(selector);\n }\n\n makeEvent(eventName, detail) {\n var evt = new Event(eventName, { bubbles: true, cancelable: true, composed: true });\n evt['detail'] = detail;\n return evt;\n }\n\n triggerEvent(elt, eventName, detail, sender) {\n detail = detail || {};\n detail[\"sender\"] = sender;\n var event = this.makeEvent(eventName, detail);\n if (config.logAll) {\n console.log(eventName, detail, elt);\n }\n var eventResult = elt.dispatchEvent(event);\n return eventResult;\n }\n\n getRootNode(node) {\n if (node && node instanceof Node) {\n var rv = node.getRootNode();\n if (rv instanceof Document || rv instanceof ShadowRoot) return rv;\n }\n return document;\n }\n\n escapeSelector(str) {\n return str.replace(/[:&()\\[\\]\\/]/g, function (str) {\n return \"\\\\\" + str;\n });\n }\n\n getEventQueueFor(elt, onFeature) {\n let internalData = this.getInternalData(elt);\n var eventQueuesForElt = internalData.eventQueues;\n if (eventQueuesForElt == null) {\n eventQueuesForElt = new Map();\n internalData.eventQueues = eventQueuesForElt;\n }\n var eventQueueForFeature = eventQueuesForElt.get(onFeature);\n if (eventQueueForFeature == null) {\n eventQueueForFeature = {queue:[], executing:false};\n eventQueuesForElt.set(onFeature, eventQueueForFeature);\n }\n return eventQueueForFeature;\n }\n\n // =================================================================\n // DOM initialization\n // =================================================================\n\n #getScriptAttributes() {\n if (this.#scriptAttrs == null) {\n this.#scriptAttrs = config.attributes.replaceAll(\" \", \"\").split(\",\");\n }\n return this.#scriptAttrs;\n }\n\n #getScript(elt) {\n var attrs = this.#getScriptAttributes();\n for (var i = 0; i < attrs.length; i++) {\n var scriptAttribute = attrs[i];\n if (elt.hasAttribute && elt.hasAttribute(scriptAttribute)) {\n return elt.getAttribute(scriptAttribute);\n }\n }\n if (elt instanceof HTMLScriptElement && elt.type === \"text/hyperscript\") {\n return elt.innerText;\n }\n return null;\n }\n\n #scriptSelector;\n #getScriptSelector() {\n if (!this.#scriptSelector) {\n this.#scriptSelector = this.#getScriptAttributes().map(a => \"[\" + a + \"]\").join(\", \");\n }\n return this.#scriptSelector;\n }\n\n #hashScript(str) {\n var hash = 5381;\n for (var i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) + str.charCodeAt(i);\n }\n return hash;\n }\n\n cleanup(elt) {\n if (!elt._hyperscript) return;\n\n this.triggerEvent(elt, \"hyperscript:before:cleanup\");\n\n var data = elt._hyperscript;\n\n // Remove registered event listeners\n if (data.listeners) {\n for (var info of data.listeners) {\n info.target.removeEventListener(info.event, info.handler);\n }\n }\n\n // Disconnect observers\n if (data.observers) {\n for (var observer of data.observers) {\n observer.disconnect();\n }\n }\n\n // Clear debounce/throttle timers\n if (data.eventState) {\n for (var state of data.eventState.values()) {\n if (state.debounced) clearTimeout(state.debounced);\n }\n }\n\n // Stop reactive effects\n this.reactivity.stopElementEffects(elt);\n\n // Recursively clean children\n if (elt.querySelectorAll) {\n for (var child of elt.querySelectorAll('[data-hyperscript-powered]')) {\n this.cleanup(child);\n }\n }\n\n this.triggerEvent(elt, \"hyperscript:after:cleanup\");\n\n elt.removeAttribute('data-hyperscript-powered');\n delete elt._hyperscript;\n }\n\n #initElement(elt, target) {\n if (elt.closest && elt.closest(config.disableSelector)) {\n return;\n }\n var internalData = this.getInternalData(elt);\n var src = this.#getScript(elt);\n if (!src) return;\n var hash = this.#hashScript(src);\n if (internalData.initialized) {\n if (internalData.scriptHash === hash) {\n this.#resolveTemplateScopes(elt);\n return;\n }\n // Script changed (e.g. morph swap) - clean up and reinitialize\n this.cleanup(elt);\n internalData = this.getInternalData(elt);\n }\n\n if (!this.triggerEvent(elt, \"hyperscript:before:init\")) return;\n\n internalData.initialized = true;\n internalData.scriptHash = hash;\n try {\n var tokens = this.#tokenizer.tokenize(src);\n var hyperScript = this.#kernel.parseHyperScript(tokens);\n if (!hyperScript) return;\n\n if (hyperScript.errors?.length) {\n this.triggerEvent(elt, \"hyperscript:parse-error\", {\n errors: hyperScript.errors,\n });\n console.error(\n \"hyperscript: \" + hyperScript.errors.length + \" parse error(s) on:\",\n elt,\n \"\\n\\n\" + Parser.formatErrors(hyperScript.errors)\n );\n return;\n }\n\n this.#resolveTemplateScopes(elt);\n hyperScript.apply(target || elt, elt, null, this);\n elt.setAttribute('data-hyperscript-powered', 'true');\n this.triggerEvent(elt, \"hyperscript:after:init\");\n setTimeout(() => {\n this.triggerEvent(target || elt, \"load\", {\n hyperscript: true,\n });\n }, 1);\n } catch (e) {\n this.triggerEvent(elt, \"exception\", {\n error: e,\n });\n console.error(\n \"hyperscript errors were found on the following element:\",\n elt,\n \"\\n\\n\",\n e.message,\n e.stack\n );\n }\n }\n\n #resolveTemplateScopes(elt) {\n var root = elt.closest('[data-live-template], [dom-scope=\"isolated\"]');\n if (!root || !root.__hs_scopes) return;\n\n var matches = [];\n var node = elt;\n while (node && node !== root) {\n var prev = node.previousSibling;\n while (prev) {\n if (prev.nodeType === 8) {\n var text = prev.data;\n if (text.startsWith('hs-scope:')) {\n matches.push(text);\n break;\n }\n }\n prev = prev.previousSibling;\n }\n node = node.parentElement;\n }\n if (!matches.length) return;\n\n var internalData = this.getInternalData(elt);\n if (!internalData.elementScope) internalData.elementScope = {};\n\n for (var i = 0; i < matches.length; i++) {\n var parts = matches[i].split(':');\n var loopId = parts[1];\n var iter = parseInt(parts[2]);\n var scope = root.__hs_scopes[loopId];\n if (!scope) continue;\n internalData.elementScope[scope.identifier] = scope.source[iter];\n if (scope.indexIdentifier) {\n internalData.elementScope[scope.indexIdentifier] = iter;\n }\n }\n }\n\n #beforeProcessHooks = [];\n #afterProcessHooks = [];\n\n addBeforeProcessHook(fn) { this.#beforeProcessHooks.push(fn); }\n addAfterProcessHook(fn) { this.#afterProcessHooks.push(fn); }\n\n processNode(elt) {\n for (var fn of this.#beforeProcessHooks) fn(elt);\n\n var selector = this.#getScriptSelector();\n if (this.matchesSelector(elt, selector)) {\n this.#initElement(elt, elt);\n }\n if (elt instanceof HTMLScriptElement && elt.type === \"text/hyperscript\") {\n this.#initElement(elt, document.body);\n }\n if (elt.querySelectorAll) {\n this.forEach(elt.querySelectorAll(selector + \", [type='text/hyperscript']\"), elt => {\n this.#initElement(elt, elt instanceof HTMLScriptElement && elt.type === \"text/hyperscript\" ? document.body : elt);\n });\n }\n\n for (var fn of this.#afterProcessHooks) fn(elt);\n }\n\n // =================================================================\n // Debug and tracing\n // =================================================================\n\n getHyperTrace(ctx, thrown) {\n var trace = [];\n var root = ctx;\n while (root.meta.caller) {\n root = root.meta.caller;\n }\n if (root.meta.traceMap) {\n return root.meta.traceMap.get(thrown, trace);\n }\n }\n\n registerHyperTrace(ctx, thrown) {\n var trace = [];\n var root = null;\n while (ctx != null) {\n trace.push(ctx);\n root = ctx;\n ctx = ctx.meta.caller;\n }\n if (root.meta.traceMap == null) {\n root.meta.traceMap = new Map();\n }\n if (!root.meta.traceMap.get(thrown)) {\n var traceEntry = {\n trace: trace,\n print: function (logger) {\n logger = logger || console.error;\n logger(\"hypertrace /// \");\n var maxLen = 0;\n for (var i = 0; i < trace.length; i++) {\n maxLen = Math.max(maxLen, trace[i].meta.feature.displayName.length);\n }\n for (var i = 0; i < trace.length; i++) {\n var traceElt = trace[i];\n logger(\n \" ->\",\n traceElt.meta.feature.displayName.padEnd(maxLen + 2),\n \"-\",\n traceElt.meta.owner\n );\n }\n },\n };\n root.meta.traceMap.set(thrown, traceEntry);\n }\n }\n\n beepValueToConsole(element, expression, value) {\n if (this.triggerEvent(element, \"hyperscript:beep\", {element, expression, value})) {\n var typeName = !value ? \"object (null)\"\n : value instanceof ElementCollection ? \"ElementCollection\"\n : value.constructor?.name || \"unknown\";\n var logValue = typeName === \"String\" ? '\"' + value + '\"'\n : value instanceof ElementCollection ? Array.from(value)\n : value;\n console.log(\"///_ BEEP! The expression (\" + expression.sourceFor().replace(\"beep! \", \"\") + \") evaluates to:\", logValue, \"of type \" + typeName);\n }\n }\n\n}\n", "// Reactivity - Automatic dependency tracking for _hyperscript\n//\n// When an effect is active, reads via resolveSymbol, resolveProperty,\n// and resolveAttribute record dependencies. Writes via setSymbol\n// notify subscribers. Property and attribute changes are detected\n// via DOM events and MutationObserver.\n\n/**\n * A single tracked read, recording what was accessed during expression().\n *\n * @typedef {Object} Dependency\n * @property {string} type - \"symbol\" | \"property\" | \"attribute\" | \"query\"\n * @property {string} name - e.g. \"$price\", \"value\", \"data-title\"\n * @property {string} [scope] - \"global\" or \"element\" (symbol deps only)\n * @property {Element} [element] - Target element (element-scoped/property/attribute deps)\n */\n\n/** Object.is semantics: treats NaN===NaN and distinguishes +0/-0 */\nfunction _sameValue(a, b) {\n // eslint-disable-next-line no-self-compare\n return a === b ? (a !== 0 || 1 / a === 1 / b) : (a !== a && b !== b);\n}\n\n/**\n * A reactive effect. Re-runs when its dependencies change.\n * Owns its full lifecycle: initialize, run, stop.\n */\nclass Effect {\n /**\n * @param {() => any} expression - The watched expression\n * @param {(v: any) => void} handler - Called when value changes\n * @param {Element|null} element - Owner element; auto-stops when disconnected\n * @param {Reactivity} reactivity - The owning reactivity system\n */\n constructor(expression, handler, element, reactivity) {\n // What this effect does\n this.expression = expression; // () => value - the watched expression, re-evaluated on dep change\n this.handler = handler; // (value) => void - called when expression result changes\n\n // Where it lives\n this.element = element;\n this._reactivity = reactivity;\n\n // Tracked state\n this.dependencies = new Map();\n this._lastValue = undefined;\n this._isStopped = false;\n this._consecutiveTriggers = 0;\n }\n\n /**\n * First evaluation: track deps, subscribe, call handler if non-null.\n * Both undefined and null are treated as \"no value yet\" to support\n * left-side-wins initialization in bind.\n */\n initialize() {\n var reactivity = this._reactivity;\n\n // Evaluate expression with tracking enabled - any symbol, property,\n // or attribute reads during this call are recorded as dependencies.\n var prev = reactivity._currentEffect;\n reactivity._currentEffect = this;\n try {\n this._lastValue = this.expression();\n } catch (e) {\n console.error(\"Error in reactive expression:\", e);\n }\n reactivity._currentEffect = prev;\n\n // Wire up subscriptions so we're notified when dependencies change\n reactivity._subscribeEffect(this);\n\n // If we got a value, push it to the handler immediately.\n // null/undefined means \"no value yet\" - skip to let the other\n // side of a bind initialize first (left-side-wins semantics).\n if (this._lastValue != null) {\n try {\n this.handler(this._lastValue);\n } catch (e) {\n console.error(\"Error in reactive handler:\", e);\n }\n }\n }\n\n /**\n * Re-evaluate expression with dependency tracking, compare with last\n * value, and call handler if changed. Returns false if circular\n * guard tripped (caller should skip this effect).\n * @returns {boolean} Whether the effect ran successfully\n */\n run() {\n this._consecutiveTriggers++;\n if (this._consecutiveTriggers > 100) {\n console.error(\n \"Reactivity loop detected: an effect triggered 100 consecutive \" +\n \"times without settling. This usually means an effect is modifying \" +\n \"a variable it also depends on.\",\n this.element || this\n );\n return false;\n }\n\n var reactivity = this._reactivity;\n\n // Unsubscribe from current deps\n reactivity._unsubscribeEffect(this);\n\n // Re-run expression with tracking\n var oldDeps = this.dependencies;\n this.dependencies = new Map();\n\n var prev = reactivity._currentEffect;\n reactivity._currentEffect = this;\n var newValue;\n try {\n newValue = this.expression();\n } catch (e) {\n console.error(\"Error in reactive expression:\", e);\n // Restore old dependencies on error\n this.dependencies = oldDeps;\n reactivity._currentEffect = prev;\n reactivity._subscribeEffect(this);\n return true;\n }\n reactivity._currentEffect = prev;\n\n // Subscribe to new deps\n reactivity._subscribeEffect(this);\n\n // Clean up empty subscription entries for deps that were dropped\n reactivity._cleanupOrphanedDeps(oldDeps);\n\n // Compare and fire (Object.is semantics: NaN === NaN, +0 !== -0)\n if (!_sameValue(newValue, this._lastValue)) {\n this._lastValue = newValue;\n try {\n this.handler(newValue);\n } catch (e) {\n console.error(\"Error in reactive handler:\", e);\n }\n }\n return true;\n }\n\n /** Reset circular guard after cascade settles. */\n resetTriggerCount() {\n this._consecutiveTriggers = 0;\n }\n\n /** Stop this effect and clean up all subscriptions. */\n stop() {\n if (this._isStopped) return;\n this._isStopped = true;\n this._reactivity._unsubscribeEffect(this);\n this._reactivity._cleanupOrphanedDeps(this.dependencies);\n this._reactivity._pendingEffects.delete(this);\n }\n}\n\nexport class Reactivity {\n constructor() {\n /** Per-object reactive state, keyed by any object (DOM element or plain JS object) */\n this._objectState = new WeakMap();\n\n // Symbol subscriptions \u2014 global $variables (e.g. $count, $theme)\n // Element-scoped :variables are stored in _getObjectState(element).subscriptions\n this._globalSymbolSubscriptions = new Map(); // symbolName -> Set\n\n // Attribute subscriptions \u2014 DOM attributes (@data-theme, @aria-hidden)\n this._attributeSubscriptions = new Map(); // \"attrName:elementId\" -> Set\n\n // Property subscriptions \u2014 JS properties (element.value, element.checked)\n this._propertySubscriptions = new Map(); // elementId -> Set\n\n // Query subscriptions \u2014 CSS selector results (<:checked/> in #myTable)\n this._querySubscriptions = new Map(); // root -> Set\n\n /** Next ID to assign to an object for dependency dedup keys */\n this._nextId = 0;\n\n /** @type {Effect|null} The effect currently being evaluated */\n this._currentEffect = null;\n\n /** @type {Set} Effects waiting to run in the next microtask */\n this._pendingEffects = new Set();\n\n /** @type {boolean} Whether a microtask is scheduled to run pending effects */\n this._isRunScheduled = false;\n\n }\n\n /**\n * Get or create the reactive state object for any object.\n * Assigns a stable unique ID on first access.\n * @param {Object} obj - DOM element or plain JS object\n * @returns {{ id: string, subscriptions: Map|null }}\n */\n _getObjectState(obj) {\n var state = this._objectState.get(obj);\n if (!state) {\n this._objectState.set(obj, state = {\n id: String(++this._nextId),\n subscriptions: null,\n });\n }\n return state;\n }\n\n /**\n * Whether an effect is currently evaluating its expression().\n * When true, reads (symbol/property/attribute) are recorded as dependencies.\n * @returns {boolean}\n */\n get isTracking() {\n return this._currentEffect !== null;\n }\n\n /**\n * Track a global variable read as a dependency.\n * @param {string} name - Variable name\n */\n trackGlobalSymbol(name) {\n this._currentEffect.dependencies.set(\"symbol:global:\" + name,\n { type: \"symbol\", name: name, scope: \"global\" });\n }\n\n /**\n * Track an element-scoped variable read as a dependency.\n * @param {string} name - Variable name\n * @param {Element} element - Owning element\n */\n trackElementSymbol(name, element) {\n if (!element) return;\n var elementId = this._getObjectState(element).id;\n this._currentEffect.dependencies.set(\"symbol:element:\" + name + \":\" + elementId,\n { type: \"symbol\", name: name, scope: \"element\", element: element });\n }\n\n /**\n * Track a property read as a dependency.\n * Subscription is coarse-grained (one handler per object, not per property),\n * so the dep key uses \"*\" rather than the property name.\n * @param {Object} obj - DOM element or plain JS object\n * @param {string} name - Property name\n */\n trackProperty(obj, name) {\n if (obj == null || typeof obj !== \"object\" || obj._hsSkipTracking) return;\n this._currentEffect.dependencies.set(\"property:\" + this._getObjectState(obj).id,\n { type: \"property\", object: obj, name: name });\n }\n\n /**\n * Track a DOM attribute read as a dependency.\n * @param {Element} element\n * @param {string} name - Attribute name\n */\n trackAttribute(element, name) {\n if (!(element instanceof Element)) return;\n this._currentEffect.dependencies.set(\"attribute:\" + name + \":\" + this._getObjectState(element).id,\n { type: \"attribute\", element: element, name: name });\n }\n\n /**\n * Track a DOM query as a dependency. Re-evaluates when any DOM\n * change occurs within root or its descendants.\n * @param {Element|Document} root - the element querySelectorAll runs on (e.g. #myTable in `<:checked/> in #myTable`)\n */\n trackQuery(root) {\n if (!this._currentEffect) return;\n root = root || document;\n var key = \"query:\" + this._getObjectState(root).id;\n this._currentEffect.dependencies.set(key,\n { type: \"query\", root: root });\n }\n\n /**\n * Notify that a global variable was written.\n * @param {string} name - Variable name\n */\n notifyGlobalSymbol(name) {\n var subs = this._globalSymbolSubscriptions.get(name);\n if (subs) {\n for (var effect of subs) {\n this._scheduleEffect(effect);\n }\n }\n }\n\n /**\n * Notify that an element-scoped variable was written.\n * @param {string} name - Variable name\n * @param {Element} element - Owning element\n */\n notifyElementSymbol(name, element) {\n if (!element) return;\n var state = this._getObjectState(element);\n if (state.subscriptions) {\n var subs = state.subscriptions.get(name);\n if (subs) {\n for (var effect of subs) {\n this._scheduleEffect(effect);\n }\n }\n }\n }\n\n /**\n * Notify that a property was written programmatically.\n * Schedules all effects watching properties on this object.\n * @param {Object} obj - DOM element or plain JS object\n */\n notifyProperty(obj) {\n if (obj == null || typeof obj !== \"object\" || obj._hsSkipTracking) return;\n var state = this._objectState.get(obj);\n if (state) {\n var subs = this._propertySubscriptions.get(state.id);\n if (subs) {\n for (var effect of subs) {\n this._scheduleEffect(effect);\n }\n }\n }\n }\n\n /**\n * Add an effect to the pending set.\n * Schedules a microtask to run them if one isn't already scheduled.\n * @param {Effect} effect\n */\n _scheduleEffect(effect) {\n if (effect._isStopped) return;\n this._pendingEffects.add(effect);\n if (!this._isRunScheduled) {\n this._isRunScheduled = true;\n var self = this;\n queueMicrotask(function () { self._runPendingEffects(); });\n }\n }\n\n /**\n * Set up the single global MutationObserver and delegated input/change\n * listeners that power attribute, property, and query tracking.\n */\n _initGlobalObserver() {\n if (typeof document === \"undefined\") return;\n\n if (!this._observer) {\n var reactivity = this;\n this._observer = new MutationObserver(function (mutations) {\n reactivity._handleMutations(mutations);\n });\n this._inputHandler = function (e) { reactivity._handleDOMEvent(e); };\n this._changeHandler = function (e) { reactivity._handleDOMEvent(e); };\n }\n\n // observe() replaces any prior observation on this target\n this._observer.observe(document, {\n attributes: true,\n childList: true,\n subtree: true\n });\n\n // addEventListener is idempotent for the same listener+capture combo\n document.addEventListener(\"input\", this._inputHandler, true);\n document.addEventListener(\"change\", this._changeHandler, true);\n }\n\n /**\n * Handle MutationObserver callbacks. Dispatches to attribute and query\n * subscriptions based on mutation type.\n * @param {MutationRecord[]} mutations\n */\n _handleMutations(mutations) {\n var hasQueries = this._querySubscriptions.size > 0;\n var queryTargets = hasQueries ? new Set() : null;\n for (var i = 0; i < mutations.length; i++) {\n var mutation = mutations[i];\n if (mutation.type === \"attributes\") {\n this._scheduleAttributeEffects(mutation.target, mutation.attributeName);\n }\n if (queryTargets) queryTargets.add(mutation.target);\n }\n if (queryTargets) this._scheduleQueryEffects(queryTargets);\n }\n\n /**\n * Handle delegated input/change events. Dispatches to property and\n * query subscriptions.\n * @param {Event} event\n */\n _handleDOMEvent(event) {\n var el = event.target;\n if (!(el instanceof Element)) return;\n var state = this._objectState.get(el);\n if (state) {\n var subs = this._propertySubscriptions.get(state.id);\n if (subs) {\n for (var effect of subs) {\n this._scheduleEffect(effect);\n }\n }\n }\n this._scheduleQueryEffects(el);\n }\n\n /**\n * Schedule effects watching a specific attribute on a specific element.\n * @param {Element} element\n * @param {string} attrName\n */\n _scheduleAttributeEffects(element, attrName) {\n var state = this._objectState.get(element);\n if (!state) return;\n var key = attrName + \":\" + state.id;\n var subs = this._attributeSubscriptions.get(key);\n if (subs) {\n for (var effect of subs) {\n this._scheduleEffect(effect);\n }\n }\n }\n\n /**\n * Schedule effects with query deps whose root includes any of the mutated elements.\n * @param {Set|Element} mutated - Element(s) where DOM changes occurred\n */\n _scheduleQueryEffects(mutated) {\n if (this._querySubscriptions.size === 0) return;\n for (var [root, effects] of this._querySubscriptions) {\n if (this._containsTarget(root, mutated)) {\n for (var effect of effects) {\n this._scheduleEffect(effect);\n }\n }\n }\n }\n\n /** Check if any of the mutated elements are inside root. */\n _containsTarget(root, mutated) {\n if (mutated instanceof Set) {\n for (var el of mutated) {\n if (root.contains(el)) return true;\n }\n return false;\n }\n return root.contains(mutated);\n }\n\n /**\n * Run all pending effects. Called once per microtask batch.\n * Effects that re-trigger during this run are queued for the next batch.\n */\n _runPendingEffects() {\n this._isRunScheduled = false;\n // Copy because effects may re-schedule themselves during this run\n var effects = Array.from(this._pendingEffects);\n this._pendingEffects.clear();\n for (var i = 0; i < effects.length; i++) {\n var effect = effects[i];\n if (effect._isStopped) continue;\n // Auto-stop if owning element is disconnected\n if (effect.element && !effect.element.isConnected) {\n effect.stop();\n continue;\n }\n effect.run();\n }\n // Reset trigger counts when the cascade settles (no more pending\n // effects). Legitimate re-triggers on future user events start\n // fresh, while infinite cross-microtask loops accumulate to 100.\n if (this._pendingEffects.size === 0) {\n for (var i = 0; i < effects.length; i++) {\n if (!effects[i]._isStopped) effects[i].resetTriggerCount();\n }\n }\n }\n\n /**\n * Subscribe an effect to all its current deps.\n * Symbols go into per-element/global subscription maps.\n * Attributes, properties, and queries use flat lookup maps\n * dispatched by the global observer.\n * @param {Effect} effect\n */\n _subscribeEffect(effect) {\n var reactivity = this;\n var needsGlobalObserver = false;\n\n for (var [depKey, dep] of effect.dependencies) {\n if (dep.type === \"symbol\" && dep.scope === \"global\") {\n if (!reactivity._globalSymbolSubscriptions.has(dep.name)) {\n reactivity._globalSymbolSubscriptions.set(dep.name, new Set());\n }\n reactivity._globalSymbolSubscriptions.get(dep.name).add(effect);\n\n } else if (dep.type === \"symbol\" && dep.scope === \"element\") {\n var state = reactivity._getObjectState(dep.element);\n if (!state.subscriptions) {\n state.subscriptions = new Map();\n }\n if (!state.subscriptions.has(dep.name)) {\n state.subscriptions.set(dep.name, new Set());\n }\n state.subscriptions.get(dep.name).add(effect);\n\n } else if (dep.type === \"attribute\") {\n var attrState = reactivity._getObjectState(dep.element);\n var attrKey = dep.name + \":\" + attrState.id;\n if (!reactivity._attributeSubscriptions.has(attrKey)) {\n reactivity._attributeSubscriptions.set(attrKey, new Set());\n }\n reactivity._attributeSubscriptions.get(attrKey).add(effect);\n needsGlobalObserver = true;\n\n } else if (dep.type === \"property\") {\n var propState = reactivity._getObjectState(dep.object);\n if (!reactivity._propertySubscriptions.has(propState.id)) {\n reactivity._propertySubscriptions.set(propState.id, new Set());\n }\n reactivity._propertySubscriptions.get(propState.id).add(effect);\n needsGlobalObserver = true;\n\n } else if (dep.type === \"query\") {\n if (!reactivity._querySubscriptions.has(dep.root)) {\n reactivity._querySubscriptions.set(dep.root, new Set());\n }\n reactivity._querySubscriptions.get(dep.root).add(effect);\n needsGlobalObserver = true;\n }\n }\n\n // Lazily initialize the global observer only when an effect\n // actually depends on DOM state (attributes, properties, or queries).\n // Symbol-only effects (e.g. `when $count changes`) skip this entirely.\n if (needsGlobalObserver) {\n reactivity._initGlobalObserver();\n }\n }\n\n /** @param {Effect} effect */\n _unsubscribeEffect(effect) {\n var reactivity = this;\n for (var [depKey, dep] of effect.dependencies) {\n if (dep.type === \"symbol\" && dep.scope === \"global\") {\n var subs = reactivity._globalSymbolSubscriptions.get(dep.name);\n if (subs) {\n subs.delete(effect);\n if (subs.size === 0) {\n reactivity._globalSymbolSubscriptions.delete(dep.name);\n }\n }\n } else if (dep.type === \"symbol\" && dep.scope === \"element\") {\n var state = reactivity._getObjectState(dep.element);\n if (state.subscriptions) {\n var subs = state.subscriptions.get(dep.name);\n if (subs) {\n subs.delete(effect);\n if (subs.size === 0) {\n state.subscriptions.delete(dep.name);\n }\n }\n }\n } else if (dep.type === \"attribute\" && dep.element) {\n var attrState = reactivity._getObjectState(dep.element);\n var attrKey = dep.name + \":\" + attrState.id;\n var subs = reactivity._attributeSubscriptions.get(attrKey);\n if (subs) {\n subs.delete(effect);\n if (subs.size === 0) {\n reactivity._attributeSubscriptions.delete(attrKey);\n }\n }\n } else if (dep.type === \"property\" && dep.object) {\n var propState = reactivity._getObjectState(dep.object);\n var subs = reactivity._propertySubscriptions.get(propState.id);\n if (subs) {\n subs.delete(effect);\n if (subs.size === 0) {\n reactivity._propertySubscriptions.delete(propState.id);\n }\n }\n } else if (dep.type === \"query\") {\n var subs = reactivity._querySubscriptions.get(dep.root);\n if (subs) {\n subs.delete(effect);\n if (subs.size === 0) {\n reactivity._querySubscriptions.delete(dep.root);\n }\n }\n }\n }\n reactivity._maybeStopGlobalObserver();\n }\n\n /**\n * Disconnect the global observer and delegated listeners when no\n * effects depend on DOM state (attributes, properties, or queries).\n */\n _maybeStopGlobalObserver() {\n if (!this._observer) return;\n if (this._attributeSubscriptions.size > 0) return;\n if (this._propertySubscriptions.size > 0) return;\n if (this._querySubscriptions.size > 0) return;\n this._observer.disconnect();\n document.removeEventListener(\"input\", this._inputHandler, true);\n document.removeEventListener(\"change\", this._changeHandler, true);\n }\n\n /**\n * Remove empty entries from subscription maps for deps that were dropped.\n * Query deps need no cleanup here \u2014 _unsubscribeEffect handles them directly.\n * @param {Map} deps\n */\n _cleanupOrphanedDeps(deps) {\n var reactivity = this;\n for (var [depKey, dep] of deps) {\n if (dep.type === \"attribute\" && dep.element) {\n var attrState = reactivity._objectState.get(dep.element);\n if (attrState) {\n var attrKey = dep.name + \":\" + attrState.id;\n var subs = reactivity._attributeSubscriptions.get(attrKey);\n if (subs && subs.size === 0) {\n reactivity._attributeSubscriptions.delete(attrKey);\n }\n }\n } else if (dep.type === \"property\" && dep.object) {\n var propState = reactivity._objectState.get(dep.object);\n if (propState) {\n var subs = reactivity._propertySubscriptions.get(propState.id);\n if (subs && subs.size === 0) {\n reactivity._propertySubscriptions.delete(propState.id);\n }\n }\n }\n }\n }\n\n /**\n * Create a reactive effect with automatic dependency tracking.\n * @param {() => any} expression - The watched expression\n * @param {(value: any) => void} handler - Called when the value changes\n * @param {Object} [options]\n * @param {Element} [options.element] - Auto-stop when element disconnects\n * @returns {() => void} Stop function\n */\n createEffect(expression, handler, options) {\n var effect = new Effect(\n expression,\n handler,\n (options && options.element) || null,\n this\n );\n\n effect.initialize();\n\n // Track effect by element for cleanup\n if (effect.element) {\n var data = effect.element._hyperscript ??= {};\n data.effects ??= new Set();\n data.effects.add(effect);\n }\n\n return function () {\n effect.stop();\n };\n }\n\n /** Stop all reactive effects owned by an element. */\n stopElementEffects(element) {\n var data = element._hyperscript;\n if (!data || !data.effects) return;\n for (var effect of data.effects) {\n effect.stop();\n }\n delete data.effects;\n }\n}\n\n// Reactivity instance is created by Runtime, not here.\n// See runtime.js constructor.\n", "// Morph - DOM morphing algorithm for _hyperscript\n//\n// Based on the htmx4 morph algorithm by Michael West.\n// Efficiently updates an existing DOM tree to match new content,\n// preserving node identity, focus, scroll position, and event listeners\n// where possible.\n\n/**\n * @typedef {Object} MorphCallbacks\n * @property {function(Node): void} [beforeNodeRemoved] - Called before a node is removed\n * @property {function(Node): void} [afterNodeAdded] - Called after a new node is inserted\n * @property {function(Node): void} [afterNodeMorphed] - Called after an existing node is morphed\n */\n\nexport class Morph {\n\n /**\n * Morph oldNode to match content.\n * @param {Element} oldNode - The existing DOM element to morph\n * @param {string|Element|DocumentFragment} content - The new content\n * @param {MorphCallbacks} [callbacks] - Optional lifecycle callbacks\n */\n morph(oldNode, content, callbacks = {}) {\n var fragment;\n if (typeof content === \"string\") {\n var temp = document.createElement(\"template\");\n temp.innerHTML = content;\n fragment = temp.content;\n } else if (content instanceof DocumentFragment) {\n fragment = content;\n } else if (content instanceof Element) {\n fragment = document.createDocumentFragment();\n fragment.append(content.cloneNode(true));\n } else {\n throw new Error(\"morph requires an HTML string, element, or document fragment\");\n }\n\n // If the fragment has a single root element matching the target tag,\n // treat as outer morph: sync attributes, then morph children\n var newRoot = fragment.firstElementChild;\n if (newRoot && !newRoot.nextElementSibling && newRoot.tagName === oldNode.tagName) {\n _copyAttributes(oldNode, newRoot);\n fragment = newRoot;\n }\n\n var { persistentIds, idMap } = _createIdMaps(oldNode, fragment);\n var pantry = document.createElement(\"div\");\n pantry.hidden = true;\n (document.body || oldNode.parentElement).after(pantry);\n var ctx = { target: oldNode, idMap, persistentIds, pantry, futureMatches: new WeakSet(), callbacks };\n\n _morphChildren(ctx, oldNode, fragment);\n\n // clean up orphaned nodes in pantry\n callbacks.beforeNodeRemoved?.(pantry);\n pantry.remove();\n }\n}\n\nfunction _morphChildren(ctx, oldParent, newParent, insertionPoint = null, endPoint = null) {\n if (oldParent instanceof HTMLTemplateElement && newParent instanceof HTMLTemplateElement) {\n oldParent = oldParent.content;\n newParent = newParent.content;\n }\n insertionPoint ||= oldParent.firstChild;\n\n let newChild = newParent.firstChild;\n while (newChild) {\n let matchedNode;\n if (insertionPoint && insertionPoint !== endPoint) {\n matchedNode = _findBestMatch(ctx, newChild, insertionPoint, endPoint);\n if (matchedNode && matchedNode !== insertionPoint) {\n let cursor = insertionPoint;\n while (cursor && cursor !== matchedNode) {\n let tempNode = cursor;\n cursor = cursor.nextSibling;\n if (tempNode instanceof Element && (ctx.idMap.has(tempNode) || _matchesUpcomingSibling(ctx, tempNode, newChild))) {\n _moveBefore(oldParent, tempNode, endPoint);\n } else {\n _removeNode(ctx, tempNode);\n }\n }\n }\n }\n\n if (!matchedNode && newChild instanceof Element && ctx.persistentIds.has(newChild.id)) {\n let escapedId = CSS.escape(newChild.id);\n matchedNode = (ctx.target.id === newChild.id && ctx.target) ||\n ctx.target.querySelector('[id=\"' + escapedId + '\"]') ||\n ctx.pantry.querySelector('[id=\"' + escapedId + '\"]');\n let element = matchedNode;\n while ((element = element.parentNode)) {\n let idSet = ctx.idMap.get(element);\n if (idSet) {\n idSet.delete(matchedNode.id);\n if (!idSet.size) ctx.idMap.delete(element);\n }\n }\n _moveBefore(oldParent, matchedNode, insertionPoint);\n }\n\n if (matchedNode) {\n _morphNode(matchedNode, newChild, ctx);\n insertionPoint = matchedNode.nextSibling;\n newChild = newChild.nextSibling;\n continue;\n }\n\n let nextNewChild = newChild.nextSibling;\n if (ctx.idMap.has(newChild)) {\n let placeholder = document.createElement(newChild.tagName);\n oldParent.insertBefore(placeholder, insertionPoint);\n _morphNode(placeholder, newChild, ctx);\n insertionPoint = placeholder.nextSibling;\n } else {\n oldParent.insertBefore(newChild, insertionPoint);\n ctx.callbacks.afterNodeAdded?.(newChild);\n insertionPoint = newChild.nextSibling;\n }\n newChild = nextNewChild;\n }\n\n while (insertionPoint && insertionPoint !== endPoint) {\n let tempNode = insertionPoint;\n insertionPoint = insertionPoint.nextSibling;\n _removeNode(ctx, tempNode);\n }\n}\n\nfunction _morphNode(oldNode, newNode, ctx) {\n if (!(oldNode instanceof Element)) return;\n _copyAttributes(oldNode, newNode);\n if (oldNode instanceof HTMLTextAreaElement && oldNode.defaultValue !== newNode.defaultValue) {\n oldNode.value = newNode.value;\n }\n if (!oldNode.isEqualNode(newNode) || newNode.tagName === \"TEMPLATE\" || newNode.querySelector?.(\"template\")) {\n _morphChildren(ctx, oldNode, newNode);\n }\n ctx.callbacks.afterNodeMorphed?.(oldNode);\n}\n\nfunction _findBestMatch(ctx, node, startPoint, endPoint) {\n if (!(node instanceof Element)) return null;\n var softMatch = null, displaceMatchCount = 0, scanLimit = 10;\n var newSet = ctx.idMap.get(node), nodeMatchCount = newSet?.size || 0;\n if (node.id && !newSet) return null;\n var cursor = startPoint;\n while (cursor && cursor !== endPoint) {\n var oldSet = ctx.idMap.get(cursor);\n if (_isSoftMatch(cursor, node)) {\n if (oldSet && newSet && [...oldSet].some(id => newSet.has(id))) return cursor;\n if (!oldSet) {\n if (scanLimit > 0 && cursor.isEqualNode(node)) return cursor;\n if (!softMatch) softMatch = cursor;\n }\n }\n displaceMatchCount += oldSet?.size || 0;\n if (displaceMatchCount > nodeMatchCount) break;\n if (cursor.contains(document.activeElement)) break;\n if (--scanLimit < 1 && nodeMatchCount === 0) break;\n cursor = cursor.nextSibling;\n }\n if (softMatch && _matchesUpcomingSibling(ctx, softMatch, node)) return null;\n return softMatch;\n}\n\nfunction _matchesUpcomingSibling(ctx, oldElt, startNode) {\n if (ctx.futureMatches.has(oldElt)) return true;\n for (var sibling = startNode.nextSibling, i = 0; sibling && i < 10; sibling = sibling.nextSibling, i++) {\n if (sibling instanceof Element && oldElt.isEqualNode(sibling)) {\n ctx.futureMatches.add(oldElt);\n return true;\n }\n }\n return false;\n}\n\nfunction _removeNode(ctx, node) {\n if (ctx.idMap.has(node)) {\n _moveBefore(ctx.pantry, node, null);\n } else {\n ctx.callbacks.beforeNodeRemoved?.(node);\n node.remove();\n }\n}\n\nfunction _moveBefore(parentNode, element, after) {\n if (parentNode.moveBefore) {\n try { parentNode.moveBefore(element, after); return; } catch (e) {}\n }\n parentNode.insertBefore(element, after);\n}\n\nfunction _copyAttributes(destination, source) {\n for (var attr of source.attributes) {\n if (destination.getAttribute(attr.name) !== attr.value) {\n destination.setAttribute(attr.name, attr.value);\n if (attr.name === \"value\" && destination instanceof HTMLInputElement && destination.type !== \"file\") {\n destination.value = attr.value;\n }\n }\n }\n for (var i = destination.attributes.length - 1; i >= 0; i--) {\n var attr = destination.attributes[i];\n if (attr && !source.hasAttribute(attr.name)) {\n destination.removeAttribute(attr.name);\n }\n }\n}\n\nfunction _isSoftMatch(oldNode, newNode) {\n if (!(oldNode instanceof Element) || oldNode.tagName !== newNode.tagName) return false;\n if (oldNode.tagName === \"SCRIPT\" && !oldNode.isEqualNode(newNode)) return false;\n return !oldNode.id || oldNode.id === newNode.id;\n}\n\nfunction _createIdMaps(oldNode, newContent) {\n var oldIdElements = _queryEltAndDescendants(oldNode, \"[id]\");\n var newIdElements = newContent.querySelectorAll(\"[id]\");\n var persistentIds = _createPersistentIds(oldIdElements, newIdElements);\n var idMap = new Map();\n _populateIdMapWithTree(idMap, persistentIds, oldNode.parentElement, oldIdElements);\n _populateIdMapWithTree(idMap, persistentIds, newContent, newIdElements);\n return { persistentIds, idMap };\n}\n\nfunction _createPersistentIds(oldIdElements, newIdElements) {\n var duplicateIds = new Set(), oldIdTagNameMap = new Map();\n for (var { id, tagName } of oldIdElements) {\n if (oldIdTagNameMap.has(id)) duplicateIds.add(id);\n else if (id) oldIdTagNameMap.set(id, tagName);\n }\n var persistentIds = new Set();\n for (var { id, tagName } of newIdElements) {\n if (persistentIds.has(id)) duplicateIds.add(id);\n else if (oldIdTagNameMap.get(id) === tagName) persistentIds.add(id);\n }\n for (var id of duplicateIds) persistentIds.delete(id);\n return persistentIds;\n}\n\nfunction _populateIdMapWithTree(idMap, persistentIds, root, elements) {\n for (var elt of elements) {\n if (persistentIds.has(elt.id)) {\n var current = elt;\n while (current && current !== root) {\n var idSet = idMap.get(current);\n if (idSet == null) { idSet = new Set(); idMap.set(current, idSet); }\n idSet.add(elt.id);\n current = current.parentElement;\n }\n }\n }\n}\n\nfunction _queryEltAndDescendants(elt, selector) {\n var results = [...(elt.querySelectorAll?.(selector) ?? [])];\n if (elt.matches?.(selector)) results.unshift(elt);\n return results;\n}\n", "/**\n * HtmxCompat - hyperscript/htmx integration layer\n *\n * Handles bidirectional processing (htmx content \u2192 hyperscript, hyperscript content \u2192 htmx)\n * and the hs-include extension for bridging element variables into htmx requests.\n */\nexport class HtmxCompat {\n\n #processingFromHtmx = false;\n\n constructor(globalScope, hyperscript) {\n this.globalScope = globalScope;\n this.hyperscript = hyperscript;\n }\n\n init() {\n var self = this;\n var globalScope = this.globalScope;\n var _hyperscript = this.hyperscript;\n\n // htmx -> hyperscript: process new htmx content\n globalScope.document.addEventListener(\"htmx:load\", function (evt) {\n self.#processingFromHtmx = true;\n _hyperscript.process(evt.detail.elt);\n self.#processingFromHtmx = false;\n });\n globalScope.document.addEventListener(\"htmx:after:process\", function (evt) {\n self.#processingFromHtmx = true;\n _hyperscript.process(evt.target);\n self.#processingFromHtmx = false;\n });\n\n // hyperscript -> htmx: notify htmx about hyperscript-inserted content\n if (typeof htmx !== 'undefined') {\n _hyperscript.addAfterProcessHook(function (elt) {\n if (!self.#processingFromHtmx) htmx.process(elt);\n });\n\n // hs-include: bridge hyperscript element variables into htmx requests (htmx 4+ only)\n if (htmx.version?.startsWith('4')) {\n htmx.registerExtension('hs-include', {\n htmx_config_request: function (elt, detail) {\n var ctx = detail?.ctx;\n if (!ctx) return;\n var sourceElt = ctx.sourceElement || elt;\n\n var found = HtmxCompat.#findHsInclude(sourceElt);\n if (!found) return;\n\n var vars = HtmxCompat.#resolveSpecifiers(found.value, found.scopeElt);\n var body = ctx.request?.body;\n if (body instanceof FormData) {\n for (var k in vars) body.set(k, vars[k]);\n }\n }\n });\n }\n }\n }\n\n // ----- hs-include helpers -----\n\n static #findHsInclude(sourceElt) {\n var attr = sourceElt.getAttribute('hs-include');\n if (attr !== null) return { value: attr, scopeElt: sourceElt };\n var elt = sourceElt.parentElement;\n while (elt) {\n attr = elt.getAttribute('hs-include:inherited');\n if (attr !== null) return { value: attr, scopeElt: elt };\n elt = elt.parentElement;\n }\n return null;\n }\n\n static #readScope(elt) {\n return elt?._hyperscript?.elementScope || {};\n }\n\n static #serialize(value) {\n if (value == null) return '';\n if (typeof value === 'object') {\n try { return JSON.stringify(value); }\n catch (_) { return ''; }\n }\n return String(value);\n }\n\n static #resolveInherited(scopeKey, startElt) {\n var elt = startElt;\n while (elt) {\n var scope = elt._hyperscript?.elementScope;\n if (scope && scopeKey in scope) return scope[scopeKey];\n elt = elt.parentElement;\n }\n }\n\n static #resolveSpecifiers(attrValue, scopeElt) {\n var result = {};\n var raw = attrValue.trim();\n\n if (raw === '*') {\n var scope = this.#readScope(scopeElt);\n for (var k in scope) {\n if (Object.prototype.hasOwnProperty.call(scope, k)) {\n result[k[0] === ':' ? k.slice(1) : k] = this.#serialize(scope[k]);\n }\n }\n return result;\n }\n\n var self = this;\n raw.split(',').forEach(function (part) {\n part = part.trim();\n if (!part) return;\n if (part[0] === ':') {\n var name = part.slice(1);\n var scope = self.#readScope(scopeElt);\n var scopeKey = ':' + name;\n if (scopeKey in scope) result[name] = self.#serialize(scope[scopeKey]);\n } else if (part[0] === '^') {\n var name = part.slice(1);\n var val = self.#resolveInherited(':' + name, scopeElt);\n if (val !== undefined) result[name] = self.#serialize(val);\n } else if (part[0] === '#') {\n var colonIdx = part.lastIndexOf(':');\n if (colonIdx > 0) {\n var selector = part.slice(0, colonIdx);\n var name = part.slice(colonIdx + 1);\n var targetElt = document.querySelector(selector);\n if (targetElt) {\n var scope = self.#readScope(targetElt);\n var scopeKey = ':' + name;\n if (scopeKey in scope) result[name] = self.#serialize(scope[scopeKey]);\n }\n }\n }\n });\n return result;\n }\n}\n", "/**\n * Basic expression parse tree elements\n */\n\nimport { Expression } from '../base.js';\n\n/**\n * ParenthesizedExpression - Wraps an expression in parentheses\n *\n * Parses: (expression)\n * Returns: the inner expression\n */\nexport class ParenthesizedExpression extends Expression {\n static grammarName = \"parenthesized\";\n static expressionType = \"leaf\";\n\n constructor(expr) {\n super();\n this.expr = expr;\n this.args = { value: expr };\n }\n\n static parse(parser) {\n if (parser.matchOpToken(\"(\")) {\n var follows = parser.clearFollows();\n try {\n var expr = parser.requireElement(\"expression\");\n } finally {\n parser.restoreFollows(follows);\n }\n parser.requireOpToken(\")\");\n return new ParenthesizedExpression(expr);\n }\n }\n\n resolve(context, { value }) {\n return value;\n }\n}\n\n/**\n * BlockLiteral - Represents lambda-style block expressions\n *\n * Parses: \\x -> expr or \\x, y -> expr\n * Returns: function that evaluates the expression with bound arguments\n */\nexport class BlockLiteral extends Expression {\n static grammarName = \"blockLiteral\";\n static expressionType = \"leaf\";\n\n constructor(params, expr) {\n super();\n this.params = params;\n this.expr = expr;\n }\n\n static parse(parser) {\n if (!parser.matchOpToken(\"\\\\\")) return;\n var params = [];\n var arg1 = parser.matchTokenType(\"IDENTIFIER\");\n if (arg1) {\n params.push(arg1);\n while (parser.matchOpToken(\",\")) {\n params.push(parser.requireTokenType(\"IDENTIFIER\"));\n }\n }\n // TODO compound op token\n parser.requireOpToken(\"-\");\n parser.requireOpToken(\">\");\n var expr = parser.requireElement(\"expression\");\n return new BlockLiteral(params, expr);\n }\n\n resolve(ctx) {\n var params = this.params;\n var expr = this.expr;\n return function () {\n //TODO - push scope\n for (var i = 0; i < params.length; i++) {\n ctx.locals[params[i].value] = arguments[i];\n }\n return expr.evaluate(ctx); //OK\n };\n }\n}\n\n/**\n * NegativeNumber - Represents unary minus operator\n *\n * Parses: -expression\n * Returns: negated numeric value\n */\nexport class NegativeNumber extends Expression {\n static grammarName = \"negativeNumber\";\n\n constructor(root) {\n super();\n this.root = root;\n this.args = { value: root };\n }\n\n static parse(parser) {\n if (parser.matchOpToken(\"-\")) {\n var root = parser.requireElement(\"negativeNumber\");\n return new NegativeNumber(root);\n } else {\n return parser.requireElement(\"primaryExpression\");\n }\n }\n\n resolve(context, { value }) {\n return -value;\n }\n}\n\n/**\n * LogicalNot - Represents logical NOT operator\n *\n * Parses: not expression\n * Returns: boolean negation\n */\nexport class LogicalNot extends Expression {\n static grammarName = \"logicalNot\";\n static expressionType = \"unary\";\n\n constructor(root) {\n super();\n this.root = root;\n this.args = { value: root };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"not\")) return;\n var root = parser.requireElement(\"unaryExpression\");\n return new LogicalNot(root);\n }\n\n resolve(context, { value: val }) {\n return !val;\n }\n}\n\n/**\n * SymbolRef - Represents variable/symbol references\n *\n * Parses: identifier | global identifier | local identifier | :identifier | $identifier\n * Returns: resolved symbol value\n */\nexport class SymbolRef extends Expression {\n static grammarName = \"symbol\";\n static assignable = true;\n\n constructor(token, scope, name, targetExpr) {\n super();\n this.token = token;\n this.scope = scope;\n this.name = name;\n this.targetExpr = targetExpr || null;\n }\n\n static parse(parser) {\n var scope = null;\n if (parser.matchToken(\"global\")) {\n scope = \"global\";\n } else if (parser.matchToken(\"element\")) {\n scope = \"element\";\n // optional possessive\n if (parser.matchOpToken(\"'\")) {\n parser.requireToken(\"s\");\n }\n } else if (parser.matchToken(\"dom\")) {\n scope = \"inherited\";\n } else if (parser.matchToken(\"local\")) {\n scope = \"local\";\n }\n\n // TODO better look ahead here\n let eltPrefix = parser.matchOpToken(\":\");\n let caretPrefix = !eltPrefix && parser.matchOpToken(\"^\");\n let identifier = parser.matchTokenType(\"IDENTIFIER\");\n if (identifier && identifier.value) {\n var name = identifier.value;\n if (eltPrefix) {\n name = \":\" + name;\n } else if (caretPrefix) {\n name = \"^\" + name;\n }\n // Resolve final scope: explicit keyword > name prefix > local default\n if (scope === null) {\n if (name.startsWith(\"$\")) {\n scope = \"global\";\n } else if (name.startsWith(\":\")) {\n scope = \"element\";\n } else if (name.startsWith(\"^\")) {\n scope = \"inherited\";\n } else {\n scope = \"local\";\n }\n }\n var targetExpr = null;\n if (scope === \"inherited\" && parser.matchToken(\"on\")) {\n var follows = parser.pushFollows(\"to\", \"into\", \"before\", \"after\", \"then\");\n try {\n targetExpr = parser.requireElement(\"expression\");\n } finally {\n parser.popFollows(follows);\n }\n }\n return new SymbolRef(identifier, scope, name, targetExpr);\n }\n }\n\n resolve(context) {\n return context.meta.runtime.resolveSymbol(this.name, context, this.scope,\n this.targetExpr ? this.targetExpr.evaluate(context) : null);\n }\n\n get lhs() { return {}; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.setSymbol(this.name, ctx, this.scope, value,\n this.targetExpr ? this.targetExpr.evaluate(ctx) : null);\n }\n}\n\n/**\n * BeepExpression - Debug operator that logs expression values\n *\n * Parses: beep! expression\n * Returns: expression value (after logging to console)\n */\nexport class BeepExpression extends Expression {\n static grammarName = \"beepExpression\";\n static expressionType = \"unary\";\n\n constructor(expression) {\n super();\n this.expression = expression;\n this.expression['booped'] = true;\n this.args = { value: expression };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"beep!\")) return;\n var expression = parser.parseElement(\"unaryExpression\");\n if (expression) {\n return new BeepExpression(expression);\n }\n }\n\n resolve(ctx, { value }) {\n ctx.meta.runtime.beepValueToConsole(ctx.me, this.expression, value);\n return value;\n }\n}\n\n/**\n * PropertyAccess - Represents dot notation property access\n *\n * Parses: expression.property\n * Returns: property value from the root expression\n */\nexport class PropertyAccess extends Expression {\n static grammarName = \"propertyAccess\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(root, prop) {\n super();\n this.root = root;\n this.prop = prop;\n this.args = { root };\n }\n\n static parse(parser, root) {\n if (!parser.matchOpToken(\".\")) return;\n var prop = parser.requireTokenType(\"IDENTIFIER\");\n var propertyAccess = new PropertyAccess(root, prop);\n return parser.parseElement(\"indirectExpression\", propertyAccess);\n }\n\n resolve(context, { root: rootVal }) {\n return context.meta.runtime.resolveProperty(rootVal, this.prop.value);\n }\n\n get lhs() { return { root: this.root }; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n var runtime = ctx.meta.runtime;\n runtime.implicitLoop(lhs.root, elt => {\n runtime.setProperty(elt, this.prop.value, value);\n });\n }\n\n delete(ctx, lhs) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n var runtime = ctx.meta.runtime;\n var prop = this.prop.value;\n runtime.implicitLoop(lhs.root, elt => {\n delete elt[prop];\n runtime.notifyMutation(elt);\n });\n }\n}\n\n/**\n * OfExpression - Represents reversed property access (property of object)\n *\n * Parses: property of expression\n * Returns: property value from the expression\n */\nexport class OfExpression extends Expression {\n static grammarName = \"ofExpression\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(prop, newRoot, attribute, expression, args, urRoot) {\n super();\n this.prop = prop; // token\n this.root = newRoot;\n this.attribute = attribute;\n this.expression = expression;\n this.args = args;\n this._urRoot = urRoot;\n this._prop = urRoot.name;\n this._isAttribute = urRoot.type === \"attributeRef\";\n this._isStyle = urRoot.type === \"styleRef\";\n this._isComputed = urRoot.type === \"computedStyleRef\";\n }\n\n static parse(parser, root) {\n if (!parser.matchToken(\"of\")) return;\n var newRoot = parser.requireElement(\"unaryExpression\");\n // find the urroot\n var childOfUrRoot = null;\n var urRoot = root;\n while (urRoot.root) {\n childOfUrRoot = urRoot;\n urRoot = urRoot.root;\n }\n var validOfRoots = [\"symbol\", \"attributeRef\", \"styleRef\", \"computedStyleRef\"];\n if (!validOfRoots.includes(urRoot.type)) {\n parser.raiseError(\"Cannot take a property of a non-symbol: \" + urRoot.type);\n }\n var attribute = urRoot.type === \"attributeRef\";\n var style = urRoot.type === \"styleRef\" || urRoot.type === \"computedStyleRef\";\n var attributeElt = (attribute || style) ? urRoot : null;\n var prop = urRoot.name;\n\n var propertyAccess = new OfExpression(\n urRoot.token, // can be undefined for attributeRef\n newRoot,\n attributeElt,\n root,\n { root: newRoot },\n urRoot\n );\n\n if (urRoot.type === \"attributeRef\") {\n propertyAccess.attribute = urRoot;\n }\n if (childOfUrRoot) {\n childOfUrRoot.root = propertyAccess;\n childOfUrRoot.args = { root: propertyAccess };\n } else {\n root = propertyAccess;\n }\n\n return parser.parseElement(\"indirectExpression\", root);\n }\n\n resolve(context, { root: rootVal }) {\n if (this._isAttribute) {\n return context.meta.runtime.resolveAttribute(rootVal, this._prop);\n } else if (this._isComputed) {\n return context.meta.runtime.resolveComputedStyle(rootVal, this._prop);\n } else if (this._isStyle) {\n return context.meta.runtime.resolveStyle(rootVal, this._prop);\n } else {\n return context.meta.runtime.resolveProperty(rootVal, this._prop);\n }\n }\n\n get lhs() { return { root: this.root }; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n if (this._isAttribute) {\n ctx.meta.runtime.implicitLoop(lhs.root, elt => {\n value == null ? elt.removeAttribute(this._prop) : elt.setAttribute(this._prop, value);\n });\n } else if (this._isStyle) {\n ctx.meta.runtime.implicitLoop(lhs.root, elt => { elt.style[this._prop] = value; });\n } else {\n var runtime = ctx.meta.runtime;\n runtime.implicitLoop(lhs.root, elt => {\n runtime.setProperty(elt, this._prop, value);\n });\n }\n }\n\n delete(ctx, lhs) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n var runtime = ctx.meta.runtime;\n var prop = this._prop;\n if (this._isAttribute) {\n runtime.implicitLoop(lhs.root, elt => elt.removeAttribute(prop));\n } else if (this._isStyle) {\n runtime.implicitLoop(lhs.root, elt => elt.style.removeProperty(prop));\n } else {\n runtime.implicitLoop(lhs.root, elt => {\n delete elt[prop];\n runtime.notifyMutation(elt);\n });\n }\n }\n}\n\n/**\n * PossessiveExpression - Represents possessive property access\n *\n * Parses: expression's property | my property | its property\n * Returns: property value\n */\nexport class PossessiveExpression extends Expression {\n static grammarName = \"possessive\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(root, attribute, prop) {\n super();\n this.root = root;\n this.attribute = attribute;\n this.prop = prop;\n this.args = { root };\n }\n\n static parse(parser, root) {\n var apostrophe = parser.matchOpToken(\"'\");\n if (\n apostrophe ||\n (root.type === \"symbol\" &&\n (root.name === \"my\" || root.name === \"its\" || root.name === \"your\") &&\n (parser.currentToken().type === \"IDENTIFIER\" || parser.currentToken().type === \"ATTRIBUTE_REF\" || parser.currentToken().type === \"STYLE_REF\"))\n ) {\n if (apostrophe) {\n parser.requireToken(\"s\");\n }\n\n var attribute, style, prop;\n attribute = parser.parseElement(\"attributeRef\");\n if (attribute == null) {\n style = parser.parseElement(\"styleRef\");\n if (style == null) {\n prop = parser.requireTokenType(\"IDENTIFIER\");\n }\n }\n var propertyAccess = new PossessiveExpression(root, attribute || style, prop);\n return parser.parseElement(\"indirectExpression\", propertyAccess);\n }\n }\n\n resolve(context, { root: rootVal }) {\n var value;\n if (this.attribute) {\n if (this.attribute.type === 'computedStyleRef') {\n value = context.meta.runtime.resolveComputedStyle(rootVal, this.attribute['name']);\n } else if (this.attribute.type === 'styleRef') {\n value = context.meta.runtime.resolveStyle(rootVal, this.attribute['name']);\n } else {\n value = context.meta.runtime.resolveAttribute(rootVal, this.attribute.name);\n }\n } else {\n value = context.meta.runtime.resolveProperty(rootVal, this.prop.value);\n }\n return value;\n }\n\n get lhs() { return { root: this.root }; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n if (this.attribute) {\n var name = this.attribute.name;\n if (this.attribute.type === 'styleRef') {\n ctx.meta.runtime.implicitLoop(lhs.root, elt => { elt.style[name] = value; });\n } else {\n ctx.meta.runtime.implicitLoop(lhs.root, elt => {\n value == null ? elt.removeAttribute(name) : elt.setAttribute(name, value);\n });\n }\n } else {\n var runtime = ctx.meta.runtime;\n var prop = this.prop.value;\n runtime.implicitLoop(lhs.root, elt => {\n runtime.setProperty(elt, prop, value);\n });\n }\n }\n}\n\n/**\n * InExpression - Represents containment check\n *\n * Parses: expression in target\n * Returns: filtered elements or boolean\n */\nexport class InExpression extends Expression {\n static grammarName = \"inExpression\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(root, target) {\n super();\n this.root = root;\n this.target = target;\n this.args = { root, target };\n }\n\n static parse(parser, root) {\n if (!parser.matchToken(\"in\")) return;\n var target = parser.requireElement(\"unaryExpression\");\n var result = new InExpression(root, target);\n if (parser.matchToken(\"where\")) {\n result = new WhereExpression(result, CollectionExpression.parseOperand(parser));\n }\n return parser.parseElement(\"indirectExpression\", result);\n }\n\n resolve(context, { root: rootVal, target }) {\n if (rootVal == null) return [];\n var returnArr = [];\n if (rootVal.css) {\n context.meta.runtime.implicitLoop(target, function (targetElt) {\n var results = context.meta.runtime.resolveQuery(targetElt, rootVal.css);\n for (var i = 0; i < results.length; i++) {\n returnArr.push(results[i]);\n }\n });\n } else if (rootVal instanceof Element) {\n var within = false;\n context.meta.runtime.implicitLoop(target, function (targetElt) {\n if (targetElt.contains(rootVal)) {\n within = true;\n }\n });\n if(within) {\n return rootVal;\n }\n } else {\n context.meta.runtime.implicitLoop(rootVal, function (rootElt) {\n context.meta.runtime.implicitLoop(target, function (targetElt) {\n if (rootElt === targetElt) {\n returnArr.push(rootElt);\n }\n });\n });\n }\n return returnArr;\n }\n\n get lhs() { return { root: this.root, target: this.target }; }\n set(ctx, lhs, value) {\n var targets = this.resolve(ctx, lhs);\n ctx.meta.runtime.replaceInDom(targets, value);\n }\n}\n\n/**\n * AsExpression - Type conversion expression\n *\n * Parses: expression as Type [| Type]*\n * Returns: converted value\n */\nexport class AsExpression extends Expression {\n static grammarName = \"asExpression\";\n static expressionType = \"indirect\";\n\n constructor(root, conversion) {\n super();\n this.root = root;\n this.conversion = conversion;\n this.args = { root };\n }\n\n static parse(parser, root) {\n if (!parser.matchToken(\"as\")) return;\n parser.matchToken(\"a\") || parser.matchToken(\"an\");\n var conversion = parser.requireElement(\"dotOrColonPath\").evalStatically();\n var asExpr = new AsExpression(root, conversion);\n while (parser.matchOpToken(\"|\")) {\n conversion = parser.requireElement(\"dotOrColonPath\").evalStatically();\n asExpr = new AsExpression(asExpr, conversion);\n }\n return parser.parseElement(\"indirectExpression\", asExpr);\n }\n\n resolve(context, { root: rootVal }) {\n return context.meta.runtime.convertValue(rootVal, this.conversion);\n }\n}\n\n/**\n * FunctionCall - Represents function call expressions\n *\n * Parses: function(args) or object.method(args)\n * Returns: function result\n */\nexport class FunctionCall extends Expression {\n static grammarName = \"functionCall\";\n static expressionType = \"indirect\";\n\n constructor(root, argExpressions, args, isMethodCall) {\n super();\n this.root = root;\n this.argExpressions = argExpressions;\n this.args = args;\n this._isMethodCall = isMethodCall;\n this._parseRoot = root; // Store original root from parse time (before mutations)\n }\n\n static parse(parser, root) {\n if (!parser.matchOpToken(\"(\")) return;\n var args = [];\n if (!parser.matchOpToken(\")\")) {\n do {\n args.push(parser.requireElement(\"expression\"));\n } while (parser.matchOpToken(\",\"));\n parser.requireOpToken(\")\");\n }\n\n var functionCall;\n if (root.root) {\n functionCall = new FunctionCall(root, args, { target: root.root, argVals: args }, true);\n } else {\n functionCall = new FunctionCall(root, args, { target: root, argVals: args }, false);\n }\n return parser.parseElement(\"indirectExpression\", functionCall);\n }\n\n resolve(context, { target, argVals }) {\n if (this._isMethodCall) {\n context.meta.runtime.nullCheck(target, this._parseRoot.root);\n var methodName = this._parseRoot.prop.value;\n var func = target[methodName];\n context.meta.runtime.nullCheck(func, this._parseRoot);\n if (func.hyperfunc) {\n argVals.push(context);\n }\n var result = func.apply(target, argVals);\n context.meta.runtime.maybeNotify(target, methodName);\n return result;\n } else {\n context.meta.runtime.nullCheck(target, this._parseRoot);\n if (target.hyperfunc) {\n argVals.push(context);\n }\n return target(...argVals);\n }\n }\n}\n\n/**\n * AttributeRefAccess - Attribute reference on an expression\n *\n * Parses: expression@attribute\n * Returns: attribute value\n */\nexport class AttributeRefAccess extends Expression {\n static grammarName = \"attributeRefAccess\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(root, attribute) {\n super();\n this.root = root;\n this.attribute = attribute;\n this.args = { root };\n }\n\n static parse(parser, root) {\n var attribute = parser.parseElement(\"attributeRef\");\n if (!attribute) return;\n return new AttributeRefAccess(root, attribute);\n }\n\n resolve(_ctx, { root: rootVal }) {\n return _ctx.meta.runtime.resolveAttribute(rootVal, this.attribute.name);\n }\n\n get lhs() { return { root: this.root }; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n ctx.meta.runtime.implicitLoop(lhs.root, elt => {\n value == null ? elt.removeAttribute(this.attribute.name) : elt.setAttribute(this.attribute.name, value);\n });\n }\n}\n\n/**\n * ArrayIndex - Array/object indexing and slicing\n *\n * Parses: array[index] | array[start..end] | array[..end] | array[start..]\n * Returns: indexed value or slice\n */\nexport class ArrayIndex extends Expression {\n static grammarName = \"arrayIndex\";\n static expressionType = \"indirect\";\n static assignable = true;\n\n constructor(root, firstIndex, secondIndex, andBefore, andAfter) {\n super();\n this.root = root;\n this.prop = firstIndex;\n this.firstIndex = firstIndex;\n this.secondIndex = secondIndex;\n this.andBefore = andBefore;\n this.andAfter = andAfter;\n this.args = { root, firstIndex, secondIndex };\n }\n\n static parse(parser, root) {\n if (!parser.matchOpToken(\"[\")) return;\n var andBefore = false;\n var andAfter = false;\n var firstIndex = null;\n var secondIndex = null;\n\n if (parser.matchOpToken(\"..\")) {\n andBefore = true;\n firstIndex = parser.requireElement(\"expression\");\n } else {\n firstIndex = parser.requireElement(\"expression\");\n\n if (parser.matchOpToken(\"..\")) {\n andAfter = true;\n var current = parser.currentToken();\n if (current.type !== \"R_BRACKET\") {\n secondIndex = parser.parseElement(\"expression\");\n }\n }\n }\n parser.requireOpToken(\"]\");\n\n var arrayIndex = new ArrayIndex(root, firstIndex, secondIndex, andBefore, andAfter);\n return parser.parseElement(\"indirectExpression\", arrayIndex);\n }\n\n resolve(_ctx, { root, firstIndex, secondIndex }) {\n if (root == null) {\n return null;\n }\n if (this.andBefore) {\n if (firstIndex < 0) {\n firstIndex = root.length + firstIndex;\n }\n return root.slice(0, firstIndex + 1); // returns all items from beginning to firstIndex (inclusive)\n } else if (this.andAfter) {\n if (secondIndex != null) {\n if (secondIndex < 0) {\n secondIndex = root.length + secondIndex;\n }\n return root.slice(firstIndex, secondIndex + 1); // returns all items from firstIndex to secondIndex (inclusive)\n } else {\n return root.slice(firstIndex); // returns from firstIndex to end of array\n }\n } else {\n return root[firstIndex];\n }\n }\n\n get lhs() { return { root: this.root, index: this.firstIndex }; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n lhs.root[lhs.index] = value;\n }\n\n delete(ctx, lhs) {\n if (this.andBefore || this.andAfter) {\n throw new Error(\"Cannot remove a slice - use a single index\");\n }\n ctx.meta.runtime.nullCheck(lhs.root, this.root);\n var runtime = ctx.meta.runtime;\n var root = lhs.root;\n var idx = lhs.index;\n if (Array.isArray(root)) {\n if (idx < 0) idx = root.length + idx;\n root.splice(idx, 1);\n } else {\n delete root[idx];\n }\n runtime.notifyMutation(root);\n }\n}\n\n/**\n * MathOperator - Binary math operations\n *\n * Parses: expr + expr | expr - expr | expr * expr | expr / expr | expr mod expr\n * Returns: computed result\n * Note: Enforces same operator throughout chain (must parenthesize mixed operators)\n */\nexport class MathOperator extends Expression {\n static grammarName = \"mathOperator\";\n\n constructor(lhs, operator, rhs) {\n super();\n this.lhs = lhs;\n this.rhs = rhs;\n this.operator = operator;\n this.args = { lhs, rhs };\n }\n\n static parse(parser) {\n var expr = parser.parseElement(\"collectionExpression\");\n var mathOp, initialMathOp = null;\n mathOp = parser.matchAnyOpToken(\"+\", \"-\", \"*\", \"/\") || parser.matchToken('mod');\n while (mathOp) {\n initialMathOp = initialMathOp || mathOp;\n var operator = mathOp.value;\n if (initialMathOp.value !== operator) {\n parser.raiseError(\"You must parenthesize math operations with different operators\");\n }\n var rhs = parser.parseElement(\"collectionExpression\");\n expr = new MathOperator(expr, operator, rhs);\n mathOp = parser.matchAnyOpToken(\"+\", \"-\", \"*\", \"/\") || parser.matchToken('mod');\n }\n return expr;\n }\n\n resolve(context, { lhs: lhsVal, rhs: rhsVal }) {\n if (this.operator === \"+\") {\n if (Array.isArray(lhsVal)) return lhsVal.concat(rhsVal);\n return lhsVal + rhsVal;\n } else if (this.operator === \"-\") {\n return lhsVal - rhsVal;\n } else if (this.operator === \"*\") {\n return lhsVal * rhsVal;\n } else if (this.operator === \"/\") {\n return lhsVal / rhsVal;\n } else if (this.operator === \"mod\") {\n return lhsVal % rhsVal;\n }\n }\n}\n\n/**\n * ComparisonOperator - Comparison operations\n *\n * Parses: expr == expr | expr < expr | expr is empty | expr matches pattern | etc.\n * Returns: boolean result\n * Supports: ==, !=, ===, !==, <, >, <=, >=, is, am, match, contain, include, start with, end with, between, precede, follow, exist, empty\n */\nexport class ComparisonOperator extends Expression {\n static grammarName = \"comparisonOperator\";\n\n constructor(lhs, operator, rhs, typeName, nullOk, ignoringCase, rhs2) {\n super();\n this.operator = operator;\n this.typeName = typeName;\n this.nullOk = nullOk;\n this.ignoringCase = ignoringCase;\n this.lhs = lhs;\n this.rhs = rhs;\n this.rhs2 = rhs2;\n this.args = { lhs, rhs, rhs2 };\n }\n\n sloppyContains(src, container, value) {\n if (container['contains']) {\n return container.contains(value);\n } else if (container['includes']) {\n return container.includes(value);\n } else {\n throw new Error(\"The value of \" + src.sourceFor() + \" does not have a contains or includes method on it\");\n }\n }\n\n sloppyMatches(src, target, toMatch) {\n if (target['match']) {\n return !!target.match(toMatch);\n } else if (target['matches']) {\n return target.matches(toMatch);\n } else {\n throw new Error(\"The value of \" + src.sourceFor() + \" does not have a match or matches method on it\");\n }\n }\n\n static parse(parser) {\n var expr = parser.parseElement(\"mathOperator\");\n var comparisonToken = parser.matchAnyOpToken(\"<\", \">\", \"<=\", \">=\", \"==\", \"===\", \"!=\", \"!==\");\n var operator = comparisonToken ? comparisonToken.value : null;\n var hasRightValue = true;\n var typeCheck = false;\n\n if (operator == null) {\n if (parser.matchToken(\"is\") || parser.matchToken(\"am\")) {\n if (parser.matchToken(\"not\")) {\n if (parser.matchToken(\"in\")) {\n operator = \"not in\";\n } else if (parser.matchToken(\"a\") || parser.matchToken(\"an\")) {\n operator = \"not a\";\n typeCheck = true;\n } else if (parser.matchToken(\"empty\")) {\n operator = \"not empty\";\n hasRightValue = false;\n } else if (parser.matchToken(\"between\")) {\n operator = \"not between\";\n } else if (parser.matchToken(\"really\")) {\n operator = \"!==\";\n if (parser.matchToken(\"equal\")) parser.matchToken(\"to\");\n } else if (parser.matchToken(\"equal\")) {\n parser.matchToken(\"to\");\n operator = \"!=\";\n } else {\n operator = \"is not\";\n }\n } else if (parser.matchToken(\"in\")) {\n operator = \"in\";\n } else if (parser.matchToken(\"a\") || parser.matchToken(\"an\")) {\n operator = \"a\";\n typeCheck = true;\n } else if (parser.matchToken(\"empty\")) {\n operator = \"empty\";\n hasRightValue = false;\n } else if (parser.matchToken(\"between\")) {\n operator = \"between\";\n } else if (parser.matchToken(\"less\")) {\n parser.requireToken(\"than\");\n if (parser.matchToken(\"or\")) {\n parser.requireToken(\"equal\");\n parser.requireToken(\"to\");\n operator = \"<=\";\n } else {\n operator = \"<\";\n }\n } else if (parser.matchToken(\"greater\")) {\n parser.requireToken(\"than\");\n if (parser.matchToken(\"or\")) {\n parser.requireToken(\"equal\");\n parser.requireToken(\"to\");\n operator = \">=\";\n } else {\n operator = \">\";\n }\n } else if (parser.matchToken(\"really\")) {\n operator = \"===\";\n if (parser.matchToken(\"equal\")) parser.matchToken(\"to\");\n } else if (parser.matchToken(\"equal\")) {\n parser.matchToken(\"to\");\n operator = \"==\";\n } else {\n operator = \"is\";\n }\n } else if (parser.matchToken(\"equals\")) {\n operator = \"==\";\n } else if (parser.matchToken(\"really\")) {\n parser.requireToken(\"equals\")\n operator = \"===\";\n } else if (parser.matchToken(\"exist\") || parser.matchToken(\"exists\")) {\n operator = \"exist\";\n hasRightValue = false;\n } else if (parser.matchToken(\"matches\") || parser.matchToken(\"match\")) {\n operator = \"match\";\n } else if (parser.matchToken(\"contains\") || parser.matchToken(\"contain\")) {\n operator = \"contain\";\n } else if (parser.matchToken(\"includes\") || parser.matchToken(\"include\")) {\n operator = \"include\";\n } else if (parser.matchToken(\"starts\")) {\n parser.requireToken(\"with\");\n operator = \"start with\";\n } else if (parser.matchToken(\"ends\")) {\n parser.requireToken(\"with\");\n operator = \"end with\";\n } else if (parser.matchToken(\"precedes\") || parser.matchToken(\"precede\")) {\n operator = \"precede\";\n } else if (parser.matchToken(\"follows\") || parser.matchToken(\"follow\")) {\n operator = \"follow\";\n } else if (parser.matchToken(\"do\") || parser.matchToken(\"does\")) {\n parser.requireToken(\"not\");\n if (parser.matchToken(\"matches\") || parser.matchToken(\"match\")) {\n operator = \"not match\";\n } else if (parser.matchToken(\"contains\") || parser.matchToken(\"contain\")) {\n operator = \"not contain\";\n } else if (parser.matchToken(\"exist\")) {\n operator = \"not exist\";\n hasRightValue = false;\n } else if (parser.matchToken(\"include\")) {\n operator = \"not include\";\n } else if (parser.matchToken(\"start\")) {\n parser.requireToken(\"with\");\n operator = \"not start with\";\n } else if (parser.matchToken(\"end\")) {\n parser.requireToken(\"with\");\n operator = \"not end with\";\n } else if (parser.matchToken(\"precede\")) {\n operator = \"not precede\";\n } else if (parser.matchToken(\"follow\")) {\n operator = \"not follow\";\n } else {\n parser.raiseExpected('matches', 'contains', 'starts with', 'ends with', 'precede', 'follow');\n }\n }\n }\n\n if (operator) {\n var typeName, nullOk, rhs;\n if (typeCheck) {\n typeName = parser.requireTokenType(\"IDENTIFIER\");\n nullOk = !parser.matchOpToken(\"!\");\n } else if (hasRightValue) {\n rhs = parser.requireElement(\"mathOperator\");\n if (operator === \"match\" || operator === \"not match\") {\n rhs = rhs.css ? rhs.css : rhs;\n }\n }\n var rhs2 = null;\n if (operator === \"between\" || operator === \"not between\") {\n parser.requireToken(\"and\");\n rhs2 = parser.requireElement(\"mathOperator\");\n }\n var ignoringCase = false;\n if (parser.matchToken(\"ignoring\")) {\n parser.requireToken(\"case\");\n ignoringCase = true;\n }\n var lhs = expr;\n expr = new ComparisonOperator(lhs, operator, rhs, typeName, nullOk, ignoringCase, rhs2);\n }\n return expr;\n }\n\n resolve(context, { lhs: lhsVal, rhs: rhsVal, rhs2: rhs2Val }) {\n const operator = this.operator;\n const lhs = this.lhs;\n const rhs = this.rhs;\n const typeName = this.typeName;\n const nullOk = this.nullOk;\n\n if (this.ignoringCase) {\n if (typeof lhsVal === \"string\") lhsVal = lhsVal.toLowerCase();\n if (typeof rhsVal === \"string\") rhsVal = rhsVal.toLowerCase();\n }\n\n if (operator === \"is\") {\n if (rhsVal === undefined && rhs.type === \"symbol\" && rhs.scope === \"local\"\n && rhs.name !== \"undefined\" && rhs.name !== \"null\") {\n return !!context.meta.runtime.resolveProperty(lhsVal, rhs.name);\n }\n return lhsVal == rhsVal;\n }\n if (operator === \"is not\") {\n if (rhsVal === undefined && rhs.type === \"symbol\" && rhs.scope === \"local\"\n && rhs.name !== \"undefined\" && rhs.name !== \"null\") {\n return !context.meta.runtime.resolveProperty(lhsVal, rhs.name);\n }\n return lhsVal != rhsVal;\n }\n if (operator === \"==\") return lhsVal == rhsVal;\n if (operator === \"!=\") return lhsVal != rhsVal;\n if (operator === \"===\") return lhsVal === rhsVal;\n if (operator === \"!==\") return lhsVal !== rhsVal;\n if (operator === \"<\") return lhsVal < rhsVal;\n if (operator === \">\") return lhsVal > rhsVal;\n if (operator === \"<=\") return lhsVal <= rhsVal;\n if (operator === \">=\") return lhsVal >= rhsVal;\n if (operator === \"match\") return lhsVal != null && this.sloppyMatches(lhs, lhsVal, rhsVal);\n if (operator === \"not match\") return lhsVal == null || !this.sloppyMatches(lhs, lhsVal, rhsVal);\n if (operator === \"in\") return rhsVal != null && this.sloppyContains(rhs, rhsVal, lhsVal);\n if (operator === \"not in\") return rhsVal == null || !this.sloppyContains(rhs, rhsVal, lhsVal);\n if (operator === \"contain\" || operator === \"include\") return lhsVal != null && this.sloppyContains(lhs, lhsVal, rhsVal);\n if (operator === \"not contain\" || operator === \"not include\") return lhsVal == null || !this.sloppyContains(lhs, lhsVal, rhsVal);\n if (operator === \"start with\") return lhsVal != null && String(lhsVal).startsWith(rhsVal);\n if (operator === \"not start with\") return lhsVal == null || !String(lhsVal).startsWith(rhsVal);\n if (operator === \"end with\") return lhsVal != null && String(lhsVal).endsWith(rhsVal);\n if (operator === \"not end with\") return lhsVal == null || !String(lhsVal).endsWith(rhsVal);\n if (operator === \"between\") return lhsVal >= rhsVal && lhsVal <= rhs2Val;\n if (operator === \"not between\") return lhsVal < rhsVal || lhsVal > rhs2Val;\n if (operator === \"precede\") return lhsVal != null && rhsVal != null && (lhsVal.compareDocumentPosition(rhsVal) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0;\n if (operator === \"not precede\") return lhsVal == null || rhsVal == null || (lhsVal.compareDocumentPosition(rhsVal) & Node.DOCUMENT_POSITION_FOLLOWING) === 0;\n if (operator === \"follow\") return lhsVal != null && rhsVal != null && (lhsVal.compareDocumentPosition(rhsVal) & Node.DOCUMENT_POSITION_PRECEDING) !== 0;\n if (operator === \"not follow\") return lhsVal == null || rhsVal == null || (lhsVal.compareDocumentPosition(rhsVal) & Node.DOCUMENT_POSITION_PRECEDING) === 0;\n if (operator === \"empty\") return context.meta.runtime.isEmpty(lhsVal);\n if (operator === \"not empty\") return !context.meta.runtime.isEmpty(lhsVal);\n if (operator === \"exist\") return context.meta.runtime.doesExist(lhsVal);\n if (operator === \"not exist\") return !context.meta.runtime.doesExist(lhsVal);\n if (operator === \"a\") return context.meta.runtime.typeCheck(lhsVal, typeName.value, nullOk);\n if (operator === \"not a\") return !context.meta.runtime.typeCheck(lhsVal, typeName.value, nullOk);\n throw new Error(\"Unknown comparison : \" + operator);\n }\n}\n\n/**\n * LogicalOperator - Logical and/or operations\n *\n * Parses: expr and expr | expr or expr\n * Returns: boolean result\n * Note: Enforces same operator throughout chain (must parenthesize mixed operators)\n */\nexport class LogicalOperator extends Expression {\n static grammarName = \"logicalOperator\";\n static expressionType = \"top\";\n\n constructor(lhs, operator, rhs) {\n super();\n this.operator = operator;\n this.lhs = lhs;\n this.rhs = rhs;\n this.args = { lhs, rhs };\n }\n\n static parse(parser) {\n var expr = parser.parseElement(\"comparisonOperator\");\n var logicalOp, initialLogicalOp = null;\n logicalOp = parser.matchToken(\"and\") || parser.matchToken(\"or\");\n while (logicalOp) {\n initialLogicalOp = initialLogicalOp || logicalOp;\n if (initialLogicalOp.value !== logicalOp.value) {\n parser.raiseError(\"You must parenthesize logical operations with different operators\");\n }\n var rhs = parser.requireElement(\"comparisonOperator\");\n const operator = logicalOp.value;\n expr = new LogicalOperator(expr, operator, rhs);\n logicalOp = parser.matchToken(\"and\") || parser.matchToken(\"or\");\n }\n return expr;\n }\n\n resolve(context, { lhs: lhsVal, rhs: rhsVal }) {\n if (this.operator === \"and\") {\n return lhsVal && rhsVal;\n } else {\n return lhsVal || rhsVal;\n }\n }\n\n // override to handle promise-compatible and/or short-circuiting\n evaluate(context) {\n var self = this;\n var shortCircuitValue = this.operator === \"or\"; // `or` short-circuits on truthy, `and` on falsy\n var lhsVal = this.lhs.evaluate(context);\n\n var continueWith = function (resolvedLhs) {\n if (!!resolvedLhs === shortCircuitValue) {\n return resolvedLhs;\n }\n var rhsVal = self.rhs.evaluate(context);\n if (rhsVal && rhsVal.then) {\n return rhsVal.then(r => self.resolve(context, { lhs: resolvedLhs, rhs: r }));\n }\n return self.resolve(context, { lhs: resolvedLhs, rhs: rhsVal });\n };\n\n if (lhsVal && lhsVal.then) {\n return lhsVal.then(continueWith);\n }\n return continueWith(lhsVal);\n }\n}\n\n\n/**\n * DotOrColonPath - Path with dots or colons\n *\n * Parses: identifier.identifier.identifier OR identifier:identifier:identifier\n * Returns: joined path string\n */\nclass DotOrColonPathNode extends Expression {\n constructor(path, separator) {\n super();\n this.type = \"dotOrColonPath\";\n this.path = path;\n this.separator = separator;\n }\n\n evalStatically() {\n return this.path.join(this.separator ? this.separator : \"\");\n }\n\n resolve() {\n return this.evalStatically();\n }\n}\n\n/**\n * CollectionOp - Centralized parser for collection postfix expressions.\n *\n * Handles: where, sorted by, mapped to, split by, joined by\n *\n * All collection keywords live in one list. When parsing the operand of any\n * collection op, the OTHER keywords are pushed as follows so they act as\n * boundaries. This is the single place to update when adding new collection ops.\n */\n/**\n * CollectionExpression - Collection operations (where, sorted by, mapped to, etc.)\n *\n * Lives above unaryExpression in the grammar so that collection ops bind\n * more loosely than indirect expressions like `in`, `.property`, `[index]`.\n *\n * Parses: where \n * sorted by [descending]\n * mapped to \n * split by \n * joined by \n */\nexport class CollectionExpression extends Expression {\n static grammarName = \"collectionExpression\";\n static KEYWORDS = [\"where\", \"sorted\", \"mapped\", \"split\", \"joined\"];\n\n static parseOperand(parser) {\n var count = parser.pushFollows(...this.KEYWORDS);\n try {\n return parser.requireElement(\"expression\");\n } finally {\n parser.popFollows(count);\n }\n }\n\n static parse(parser) {\n var root = parser.parseElement(\"unaryExpression\");\n var changed = true;\n while (changed) {\n changed = false;\n if (parser.matchToken(\"where\")) {\n root = new WhereExpression(root, this.parseOperand(parser));\n changed = true;\n } else if (parser.matchToken(\"sorted\")) {\n parser.requireToken(\"by\");\n var key = this.parseOperand(parser);\n var descending = parser.matchToken(\"descending\");\n root = new SortedByExpression(root, key, !!descending);\n changed = true;\n } else if (parser.matchToken(\"mapped\")) {\n parser.requireToken(\"to\");\n root = new MappedToExpression(root, this.parseOperand(parser));\n changed = true;\n } else if (parser.matchToken(\"split\")) {\n parser.requireToken(\"by\");\n root = new SplitByExpression(root, this.parseOperand(parser));\n changed = true;\n } else if (parser.matchToken(\"joined\")) {\n parser.requireToken(\"by\");\n root = new JoinedByExpression(root, this.parseOperand(parser));\n changed = true;\n }\n }\n return root;\n }\n}\n\n/** Filter a collection: where */\nclass WhereExpression extends Expression {\n constructor(root, condition) {\n super();\n this.root = root;\n this.condition = condition;\n this.args = { root };\n }\n\n resolve(context, { root: collection }) {\n if (!collection) return collection;\n var result = [];\n var items = Array.from(collection);\n for (var i = 0; i < items.length; i++) {\n context.beingTested = items[i];\n if (this.varName) context.locals[this.varName] = items[i];\n if (this.condition.evaluate(context)) {\n result.push(items[i]);\n }\n }\n context.beingTested = null;\n return result;\n }\n}\n\n/** Sort a collection: sorted by [descending] */\nclass SortedByExpression extends Expression {\n constructor(root, key, descending) {\n super();\n this.root = root;\n this.key = key;\n this.descending = descending;\n this.args = { root };\n }\n\n resolve(context, { root: collection }) {\n if (!collection) return collection;\n var items = Array.from(collection);\n var keys = [];\n for (var i = 0; i < items.length; i++) {\n context.beingTested = items[i];\n keys.push(this.key.evaluate(context));\n }\n context.beingTested = null;\n var indices = items.map(function (_, i) { return i; });\n var dir = this.descending ? -1 : 1;\n indices.sort(function (a, b) {\n var ka = keys[a], kb = keys[b];\n if (ka == kb) return 0;\n return (ka < kb ? -1 : 1) * dir;\n });\n return indices.map(function (i) { return items[i]; });\n }\n}\n\n/** Map a collection: mapped to */\nclass MappedToExpression extends Expression {\n constructor(root, projection) {\n super();\n this.root = root;\n this.projection = projection;\n this.args = { root };\n }\n\n resolve(context, { root: collection }) {\n if (!collection) return collection;\n var items = Array.from(collection);\n var result = [];\n for (var i = 0; i < items.length; i++) {\n context.beingTested = items[i];\n result.push(this.projection.evaluate(context));\n }\n context.beingTested = null;\n return result;\n }\n}\n\n/** Split a string: split by */\nclass SplitByExpression extends Expression {\n constructor(root, delimiter) {\n super();\n this.args = { root, delimiter };\n }\n\n resolve(context, { root, delimiter }) {\n if (!root) return root;\n return String(root).split(delimiter);\n }\n}\n\n/** Join an array: joined by */\nclass JoinedByExpression extends Expression {\n constructor(root, delimiter) {\n super();\n this.args = { root, delimiter };\n }\n\n resolve(context, { root, delimiter }) {\n if (!root) return root;\n return Array.from(root).join(delimiter);\n }\n}\n\nexport class DotOrColonPath extends Expression {\n static grammarName = \"dotOrColonPath\";\n\n static parse(parser) {\n var root = parser.matchTokenType(\"IDENTIFIER\");\n if (root) {\n var path = [root.value];\n\n var separator = parser.matchOpToken(\".\") || parser.matchOpToken(\":\");\n if (separator) {\n do {\n path.push(parser.requireTokenType(\"IDENTIFIER\", \"NUMBER\").value);\n } while (parser.matchOpToken(separator.value));\n }\n\n return new DotOrColonPathNode(path, separator ? separator.value : null);\n }\n }\n}", "/**\n * Web-related literal parse tree elements\n * References to DOM elements and attributes\n */\nimport { ElementCollection, TemplatedQueryElementCollection } from '../../core/runtime/collections.js';\nimport { Expression } from '../base.js';\nimport { Tokenizer } from '../../core/tokenizer.js';\n\n/**\n * IdRef - Represents ID references (#foo or #${expr})\n *\n * Parses: #elementId | #${expression}\n * Returns: Element with matching ID\n */\nexport class IdRef extends Expression {\n static grammarName = \"idRef\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n constructor(variant, css, value, innerExpression) {\n super();\n this.variant = variant;\n this.type = variant === \"template\" ? \"idRefTemplate\" : \"idRef\";\n this.css = css;\n this.value = value;\n this.args = variant === \"template\" ? { expr: innerExpression } : null;\n }\n\n static parse(parser) {\n\n var elementId = parser.matchTokenType(\"ID_REF\");\n if (!elementId) return;\n if (!elementId.value) return;\n if (elementId.template) {\n var templateValue = elementId.value.substring(2);\n var innerTokens = Tokenizer.tokenize(templateValue);\n var innerParser = parser.createChildParser(innerTokens);\n var innerExpression = innerParser.requireElement(\"expression\");\n return new IdRef(\"template\", null, null, innerExpression);\n } else {\n const value = elementId.value.substring(1);\n return new IdRef(\"static\", elementId.value, value, null);\n }\n }\n\n resolve(context, { expr } = {}) {\n if (this.variant === \"template\") {\n return context.meta.runtime.getRootNode(context.me).getElementById(expr);\n } else {\n return context.meta.runtime.getRootNode(context.me).getElementById(this.value);\n }\n }\n\n get lhs() { return {}; }\n set(ctx, lhs, value) {\n var target = this.resolve(ctx);\n if (target) ctx.meta.runtime.replaceInDom(target, value);\n }\n}\n\n/**\n * ClassRef - Represents class references (.foo or .${expr})\n *\n * Parses: .className | .${expression}\n * Returns: ElementCollection with matching class\n */\nexport class ClassRef extends Expression {\n static grammarName = \"classRef\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n constructor(variant, css, className, innerExpression) {\n super();\n this.variant = variant;\n this.type = variant === \"template\" ? \"classRefTemplate\" : \"classRef\";\n this.css = css;\n this.className = className;\n this.args = variant === \"template\" ? { expr: innerExpression } : null;\n }\n\n static parse(parser) {\n\n var classRef = parser.matchTokenType(\"CLASS_REF\");\n if (!classRef) return;\n if (!classRef.value) return;\n if (classRef.template) {\n var templateValue = classRef.value.substring(2);\n var innerTokens = Tokenizer.tokenize(templateValue);\n var innerParser = parser.createChildParser(innerTokens);\n var innerExpression = innerParser.requireElement(\"expression\");\n return new ClassRef(\"template\", null, null, innerExpression);\n } else {\n const css = classRef.value;\n const className = css.slice(1);\n return new ClassRef(\"static\", css, className, null);\n }\n }\n\n resolve(context, { expr } = {}) {\n if (this.variant === \"template\") {\n return new ElementCollection(\".\" + expr, context.me, true, context.meta.runtime);\n } else {\n return new ElementCollection(this.css, context.me, true, context.meta.runtime);\n }\n }\n\n get lhs() { return {}; }\n set(ctx, lhs, value) {\n var targets = Array.from(this.resolve(ctx));\n ctx.meta.runtime.replaceInDom(targets, value);\n }\n}\n\n/**\n * QueryRef - Represents query selector references ()\n *\n * Parses: | <.foo/> | <#bar/>\n * Returns: ElementCollection matching query\n */\nexport class QueryRef extends Expression {\n static grammarName = \"queryRef\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n constructor(css, args, template) {\n super();\n this.css = css;\n this.templateArgs = args;\n this.args = template ? { parts: args } : null;\n this.template = template;\n }\n\n static parse(parser) {\n\n\n var queryStart = parser.matchOpToken(\"<\");\n if (!queryStart) return;\n var queryTokens = parser.consumeUntil(\"/\");\n parser.requireOpToken(\"/\");\n parser.requireOpToken(\">\");\n var queryValue = queryTokens\n .map(function (t) {\n if (t.type === \"STRING\") {\n return '\"' + t.value + '\"';\n } else {\n return t.value;\n }\n })\n .join(\"\");\n\n var template, innerTokens, args;\n if (/\\$[^=]/.test(queryValue)) {\n template = true;\n innerTokens = Tokenizer.tokenize(queryValue, true);\n var innerParser = parser.createChildParser(innerTokens);\n args = innerParser.parseStringTemplate();\n }\n\n return new QueryRef(queryValue, args, template);\n }\n\n resolve(context, { parts } = {}) {\n if (this.template) {\n return new TemplatedQueryElementCollection(this.css, context.me, parts, context.meta.runtime);\n } else {\n return new ElementCollection(this.css, context.me, false, context.meta.runtime);\n }\n }\n\n get lhs() { return this.template ? { parts: this.templateArgs } : {}; }\n set(ctx, lhs, value) {\n var targets = Array.from(this.resolve(ctx, lhs));\n ctx.meta.runtime.replaceInDom(targets, value);\n }\n}\n\n/**\n * AttributeRef - Represents attribute references (@attr or [@attr=\"value\"])\n *\n * Parses: @name | @name=\"value\"\n * Returns: Attribute value or ElementCollection\n */\nexport class AttributeRef extends Expression {\n static grammarName = \"attributeRef\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n constructor(name, css, value) {\n super();\n this.name = name;\n this.css = css;\n this.value = value;\n }\n\n static parse(parser) {\n var attributeRef = parser.matchTokenType(\"ATTRIBUTE_REF\");\n if (!attributeRef) return;\n if (!attributeRef.value) return;\n var outerVal = attributeRef.value;\n if (outerVal.startsWith(\"[\")) {\n var innerValue = outerVal.substring(2, outerVal.length - 1);\n } else {\n var innerValue = outerVal.substring(1);\n }\n var css = \"[\" + innerValue + \"]\";\n var split = innerValue.split(\"=\");\n var name = split[0];\n var value = split[1];\n if (value) {\n // strip quotes\n if (value.startsWith('\"') || value.startsWith(\"'\")) {\n value = value.substring(1, value.length - 1);\n }\n }\n return new AttributeRef(name, css, value);\n }\n\n resolve(context) {\n var target = context.you || context.me;\n if (target) {\n return context.meta.runtime.resolveAttribute(target, this.name);\n }\n }\n\n get lhs() { return {}; }\n\n set(ctx, lhs, value) {\n var target = ctx.you || ctx.me;\n if (target) {\n value == null ? target.removeAttribute(this.name) : target.setAttribute(this.name, value);\n }\n }\n}\n\n/**\n * StyleRef - Represents style references (*prop or *computed-prop)\n *\n * Parses: *color | *computed-width\n * Returns: Style property value (regular or computed)\n */\nexport class StyleRef extends Expression {\n static grammarName = \"styleRef\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n constructor(variant, name) {\n super();\n this.variant = variant;\n this.type = variant === \"computed\" ? \"computedStyleRef\" : \"styleRef\";\n this.name = name;\n }\n\n static parse(parser) {\n var styleRef = parser.matchTokenType(\"STYLE_REF\");\n if (!styleRef) return;\n if (!styleRef.value) return;\n var styleProp = styleRef.value.slice(1);\n if (styleProp.startsWith(\"computed-\")) {\n styleProp = styleProp.slice(\"computed-\".length);\n return new StyleRef(\"computed\", styleProp);\n } else {\n return new StyleRef(\"style\", styleProp);\n }\n }\n\n resolve(context) {\n var target = context.you || context.me;\n if (target) {\n if (this.variant === \"computed\") {\n return context.meta.runtime.resolveComputedStyle(target, this.name);\n } else {\n return context.meta.runtime.resolveStyle(target, this.name);\n }\n }\n }\n\n get lhs() { return {}; }\n\n set(ctx, lhs, value) {\n var target = ctx.you || ctx.me;\n if (target) { target.style[this.name] = value; }\n }\n}\n\n/**\n * StyleLiteral - Represents templated style strings\n *\n * Parses: { css-text-with-$variables }\n * Returns: Interpolated CSS string\n */\nexport class StyleLiteral extends Expression {\n static grammarName = \"styleLiteral\";\n\n constructor(stringParts, exprs) {\n super();\n this.stringParts = stringParts;\n this.args = { exprs };\n }\n\n static parse(parser) {\n if (!parser.matchOpToken(\"{\")) return;\n\n var stringParts = [\"\"]\n var exprs = []\n\n while (parser.hasMore()) {\n if (parser.matchOpToken(\"\\\\\")) {\n parser.consumeToken();\n } else if (parser.matchOpToken(\"}\")) {\n break;\n } else if (parser.matchToken(\"$\")) {\n var opencurly = parser.matchOpToken(\"{\");\n var expr = parser.parseElement(\"expression\");\n if (opencurly) parser.requireOpToken(\"}\");\n\n exprs.push(expr)\n stringParts.push(\"\")\n } else {\n var tok = parser.consumeToken();\n stringParts[stringParts.length-1] += parser.source.substring(tok.start, tok.end);\n }\n\n stringParts[stringParts.length-1] += parser.lastWhitespace();\n }\n\n return new StyleLiteral(stringParts, exprs);\n }\n\n resolve(ctx, { exprs }) {\n var rv = \"\";\n const stringParts = this.stringParts;\n\n stringParts.forEach(function (part, idx) {\n rv += part;\n if (idx in exprs) rv += exprs[idx];\n });\n\n return rv;\n }\n}\n", "/**\n * Postfix expression parse tree elements\n * Handles CSS units, time expressions, and type checking\n */\n\nimport { Expression } from '../base.js';\n\n// CSS unit postfixes\n// taken from https://drafts.csswg.org/css-values-4/#relative-length\n// and https://drafts.csswg.org/css-values-4/#absolute-length\n// (NB: we do not support `in` due to conflicts w/ the hyperscript grammar)\nconst STRING_POSTFIXES = [\n 'em', 'ex', 'cap', 'ch', 'ic', 'rem', 'lh', 'rlh', 'vw', 'vh', 'vi', 'vb', 'vmin', 'vmax',\n 'cm', 'mm', 'Q', 'pc', 'pt', 'px'\n];\n\nexport class StringPostfixExpression extends Expression {\n static grammarName = \"stringPostfixExpression\";\n static expressionType = \"postfix\";\n\n constructor(root, postfix) {\n super();\n this.postfix = postfix;\n this.args = { value: root };\n }\n\n static parse(parser, root) {\n let stringPostfix = parser.matchAnyToken(...STRING_POSTFIXES) || parser.matchOpToken(\"%\");\n if (!stringPostfix) return;\n\n return new StringPostfixExpression(root, stringPostfix.value);\n }\n\n resolve(context, { value: val }) {\n return \"\" + val + this.postfix;\n }\n}\n\nexport class TimeExpression extends Expression {\n static grammarName = \"timeExpression\";\n static expressionType = \"postfix\";\n\n constructor(root, timeFactor) {\n super();\n this.time = root;\n this.factor = timeFactor;\n this.args = { value: root };\n }\n\n static parse(parser, root) {\n var timeFactor = null;\n if (parser.matchToken(\"s\") || parser.matchToken(\"seconds\")) {\n timeFactor = 1000;\n } else if (parser.matchToken(\"ms\") || parser.matchToken(\"milliseconds\")) {\n timeFactor = 1;\n }\n if (!timeFactor) return;\n\n return new TimeExpression(root, timeFactor);\n }\n\n evalStatically() {\n return this.time.evalStatically() * this.factor;\n }\n\n resolve(context, { value: val }) {\n return val * this.factor;\n }\n}\n\nexport class TypeCheckExpression extends Expression {\n static grammarName = \"typeCheckExpression\";\n static expressionType = \"postfix\";\n\n constructor(root, typeName, nullOk) {\n super();\n this.typeName = typeName;\n this.nullOk = nullOk;\n this.args = { value: root };\n }\n\n static parse(parser, root) {\n if (!parser.matchOpToken(\":\")) return;\n\n var typeName = parser.requireTokenType(\"IDENTIFIER\");\n if (!typeName.value) return;\n var nullOk = !parser.matchOpToken(\"!\");\n\n return new TypeCheckExpression(root, typeName, nullOk);\n }\n\n resolve(context, { value: val }) {\n var passed = context.meta.runtime.typeCheck(val, this.typeName.value, this.nullOk);\n if (passed) {\n return val;\n } else {\n throw new Error(\"Typecheck failed! Expected: \" + this.typeName.value);\n }\n }\n}\n", "/**\n * Positional expression parse tree elements\n * DOM query and position-based selections\n */\n\nimport { Expression } from '../base.js';\nimport { AttributeRefAccess } from './expressions.js';\n\n/**\n * RelativePositionalExpression - Relative DOM navigation\n *\n * Parses: next | previous | next from in \n * Returns: matching element relative to starting point\n */\nexport class RelativePositionalExpression extends Expression {\n static grammarName = \"relativePositionalExpression\";\n static expressionType = \"unary\";\n\n constructor(thingElt, from, forwardSearch, inSearch, wrapping, inElt, withinElt, operator) {\n super();\n this.thingElt = thingElt;\n this.from = from;\n this.forwardSearch = forwardSearch;\n this.inSearch = inSearch;\n this.wrapping = wrapping;\n this.inElt = inElt;\n this.withinElt = withinElt;\n this.operator = operator;\n this.args = { thing: thingElt, from, inElt, withinElt };\n }\n\n static parse(parser) {\n var op = parser.matchAnyToken(\"next\", \"previous\");\n if (!op) return;\n var forwardSearch = op.value === \"next\";\n\n var thingElt = parser.parseElement(\"leaf\");\n\n if (parser.matchToken(\"from\")) {\n parser.pushFollow(\"in\");\n try {\n var from = parser.requireElement(\"unaryExpression\");\n } finally {\n parser.popFollow();\n }\n } else {\n var from = parser.requireElement(\"implicitMeTarget\");\n }\n\n var inSearch = false;\n var withinElt;\n if (parser.matchToken(\"in\")) {\n inSearch = true;\n var inElt = parser.requireElement(\"unaryExpression\");\n } else if (parser.matchToken(\"within\")) {\n withinElt = parser.requireElement(\"unaryExpression\");\n } else {\n withinElt = null; // resolved to document.body at runtime\n }\n\n var wrapping = false;\n if (parser.matchToken(\"with\")) {\n parser.requireToken(\"wrapping\")\n wrapping = true;\n }\n\n return new RelativePositionalExpression(\n thingElt,\n from,\n forwardSearch,\n inSearch,\n wrapping,\n inElt,\n withinElt,\n op.value\n );\n }\n\n scanForwardQuery(start, root, match, wrap) {\n var results = root.querySelectorAll(match);\n for (var i = 0; i < results.length; i++) {\n var elt = results[i];\n if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_PRECEDING) {\n return elt;\n }\n }\n if (wrap) {\n return results[0];\n }\n }\n\n scanBackwardsQuery(start, root, match, wrap) {\n var results = root.querySelectorAll(match);\n for (var i = results.length - 1; i >= 0; i--) {\n var elt = results[i];\n if (elt.compareDocumentPosition(start) === Node.DOCUMENT_POSITION_FOLLOWING) {\n return elt;\n }\n }\n if (wrap) {\n return results[results.length - 1];\n }\n }\n\n scanForwardArray(start, array, match, wrap) {\n var matches = [];\n for (var elt of array) {\n if (elt.matches(match) || elt === start) {\n matches.push(elt);\n }\n }\n for (var i = 0; i < matches.length - 1; i++) {\n var elt = matches[i];\n if (elt === start) {\n return matches[i + 1];\n }\n }\n if (wrap) {\n var first = matches[0];\n if (first && first.matches(match)) {\n return first;\n }\n }\n }\n\n scanBackwardsArray(start, array, match, wrap) {\n return this.scanForwardArray(start, Array.from(array).reverse(), match, wrap);\n }\n\n resolve(context, { thing, from, inElt, withinElt }) {\n var css = thing.css;\n if (css == null) {\n throw new Error(\"Expected a CSS value to be returned by \" + this.thingElt.sourceFor());\n }\n\n if(this.inSearch) {\n if (inElt) {\n if (this.forwardSearch) {\n return this.scanForwardArray(from, inElt, css, this.wrapping);\n } else {\n return this.scanBackwardsArray(from, inElt, css, this.wrapping);\n }\n }\n } else {\n var root = withinElt ?? document.body;\n if (this.forwardSearch) {\n return this.scanForwardQuery(from, root, css, this.wrapping);\n } else {\n return this.scanBackwardsQuery(from, root, css, this.wrapping);\n }\n }\n }\n\n}\n\n/**\n * PositionalExpression - Array/collection position selection\n *\n * Parses: first | last | random \n * Returns: selected element from collection\n */\nexport class PositionalExpression extends Expression {\n static grammarName = \"positionalExpression\";\n static expressionType = \"unary\";\n\n constructor(rhs, operator) {\n super();\n this.rhs = rhs;\n this.operator = operator;\n this.args = { value: rhs };\n }\n\n static parse(parser) {\n var op = parser.matchAnyToken(\"first\", \"last\", \"random\");\n if (!op) return;\n parser.matchAnyToken(\"in\", \"from\", \"of\");\n var rhs = parser.requireElement(\"unaryExpression\");\n return new PositionalExpression(rhs, op.value);\n }\n\n resolve(context, { value: rhsVal }) {\n if (rhsVal && !Array.isArray(rhsVal)) {\n if (rhsVal.children) {\n rhsVal = rhsVal.children;\n } else {\n rhsVal = Array.from(rhsVal);\n }\n }\n if (rhsVal) {\n if (this.operator === \"first\") {\n return rhsVal[0];\n } else if (this.operator === \"last\") {\n return rhsVal[rhsVal.length - 1];\n } else if (this.operator === \"random\") {\n return rhsVal[Math.floor(Math.random() * rhsVal.length)];\n }\n }\n }\n\n}\n\n/**\n * ClosestExprNode - Closest ancestor matching selector node\n */\nclass ClosestExprNode extends Expression {\n constructor(parentSearch, expr, css, to) {\n super();\n this.type = \"closestExpr\";\n this.parentSearch = parentSearch;\n this.expr = expr;\n this.css = css;\n this.to = to;\n this.args = { to };\n }\n\n resolve(ctx, { to }) {\n if (to == null) return null;\n let result = [];\n const css = this.css;\n const parentSearch = this.parentSearch;\n ctx.meta.runtime.implicitLoop(to, function(to){\n if (parentSearch) {\n result.push(to.parentElement ? to.parentElement.closest(css) : null);\n } else {\n result.push(to.closest(css));\n }\n })\n return ctx.meta.runtime.shouldAutoIterate(to) ? result : result[0];\n }\n\n get lhs() { return { to: this.to }; }\n set(ctx, lhs, value) {\n var target = this.resolve(ctx, lhs);\n if (target) ctx.meta.runtime.replaceInDom(target, value);\n }\n}\n\n/**\n * ClosestExpr - Finds closest ancestor matching selector\n *\n * Parses: closest [to element] | closest parent [to element]\n * Returns: Closest matching element\n */\nexport class ClosestExpr extends Expression {\n static grammarName = \"closestExpr\";\n static expressionType = \"leaf\";\n static assignable = true;\n\n static parse(parser) {\n if (!parser.matchToken(\"closest\")) return;\n\n var parentSearch = false;\n if (parser.matchToken(\"parent\")) {\n parentSearch = true;\n }\n\n var css = null;\n var attributeRef = null;\n if (parser.currentToken().type === \"ATTRIBUTE_REF\") {\n attributeRef = parser.requireElement(\"attributeRefAccess\", null);\n css = \"[\" + attributeRef.attribute.name + \"]\";\n }\n\n if (css == null) {\n var expr = parser.requireElement(\"unaryExpression\");\n if (expr.css == null) {\n parser.raiseError(\"Expected a CSS expression\");\n } else {\n css = expr.css;\n }\n }\n\n if (parser.matchToken(\"to\")) {\n var to = parser.parseElement(\"expression\");\n } else {\n var to = parser.parseElement(\"implicitMeTarget\");\n }\n\n var closestExpr = new ClosestExprNode(parentSearch, expr, css, to);\n\n // If we parsed an attributeRef, create a new AttributeRefAccess with the correct root\n if (attributeRef) {\n return new AttributeRefAccess(closestExpr, attributeRef.attribute);\n } else {\n return closestExpr;\n }\n }\n}\n", "/**\n * Existential expression parse tree elements\n * Expressions that check for existence, emptiness, etc.\n */\n\nimport { Expression } from '../base.js';\n\n/**\n * NoExpression - Represents the \"no\" keyword for empty/null checks\n *\n * Parses: no \n * Returns: true if the expression is empty/null, false otherwise\n */\nexport class NoExpression extends Expression {\n static grammarName = \"noExpression\";\n static expressionType = \"unary\";\n\n constructor(root) {\n super();\n this.root = root;\n this.args = { value: root };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"no\")) return;\n var root = parser.requireElement(\"collectionExpression\");\n return new NoExpression(root);\n }\n\n resolve(context, { value: val }) {\n return context.meta.runtime.isEmpty(val);\n }\n}\n\n/**\n * SomeExpression - Represents the \"some\" keyword for existential checks\n *\n * Parses: some \n * Returns: true if the expression is not empty/null, false otherwise\n */\nexport class SomeExpression extends Expression {\n static grammarName = \"some\";\n static expressionType = \"leaf\";\n\n constructor(root) {\n super();\n this.root = root;\n this.args = { value: root };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"some\")) return;\n var root = parser.requireElement(\"expression\");\n return new SomeExpression(root);\n }\n\n resolve(context, { value: val }) {\n return !context.meta.runtime.isEmpty(val);\n }\n}\n", "/**\n * Target expression parse tree elements\n * Elements that represent targets for operations (me, you, etc.)\n */\n\nimport { Expression } from '../base.js';\n\n/**\n * ImplicitMeTarget - Represents the implicit \"me\" or \"you\" target\n *\n * Parses: implicit me/you reference\n * Returns: context.you || context.me\n */\nexport class ImplicitMeTarget extends Expression {\n static grammarName = \"implicitMeTarget\";\n\n constructor() {\n super();\n }\n\n static parse(parser) {\n return new ImplicitMeTarget();\n }\n\n resolve(context) {\n return context.you || context.me;\n }\n}\n", "/**\n * Basic command parse tree elements\n * Simple commands with no control flow, plus data manipulation commands\n */\n\nimport { RegExpIterable } from '../../core/runtime/collections.js';\nimport { Command, Expression } from '../base.js';\nimport { config } from '../../core/config.js';\n\n/**\n * ImplicitResultSymbol - Represents the implicit \"result\" symbol\n */\nclass ImplicitResultSymbol extends Expression {\n constructor() {\n super();\n this.type = \"symbol\";\n }\n\n resolve(context) {\n return context.meta.runtime.resolveSymbol(\"result\", context);\n }\n\n get lhs() { return {}; }\n\n set(ctx, lhs, value) {\n ctx.meta.runtime.setSymbol(\"result\", ctx, null, value);\n }\n}\n\n/**\n * LogCommand - Log values to console\n *\n * Parses: log expr1, expr2, ... [with customLogger]\n * Executes: Logs values to console or custom logger\n */\nexport class LogCommand extends Command {\n static keyword = \"log\";\n\n constructor(exprs, withExpr) {\n super();\n this.exprs = exprs;\n this.withExpr = withExpr;\n this.args = { logger: withExpr, values: exprs };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"log\")) return;\n var exprs = [parser.parseElement(\"expression\")];\n while (parser.matchOpToken(\",\")) {\n exprs.push(parser.requireElement(\"expression\"));\n }\n if (parser.matchToken(\"with\")) {\n var withExpr = parser.requireElement(\"expression\");\n }\n return new LogCommand(exprs, withExpr);\n }\n\n resolve(ctx, { logger, values }) {\n if (logger) {\n logger(...values);\n } else {\n console.log(...values);\n }\n return this.findNext(ctx);\n }\n}\n\n/**\n * BeepCommand - Debug beep to console\n *\n * Parses: beep! expr1, expr2, ...\n * Executes: Logs values with debug formatting\n */\nexport class BeepCommand extends Command {\n static keyword = \"beep!\";\n\n constructor(exprs) {\n super();\n this.exprs = exprs;\n this.args = { values: exprs };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"beep!\")) return;\n var exprs = [parser.parseElement(\"expression\")];\n while (parser.matchOpToken(\",\")) {\n exprs.push(parser.requireElement(\"expression\"));\n }\n return new BeepCommand(exprs);\n }\n\n resolve(ctx, { values }) {\n for (let i = 0; i < this.exprs.length; i++) {\n const expr = this.exprs[i];\n const val = values[i];\n ctx.meta.runtime.beepValueToConsole(ctx.me, expr, val);\n }\n return this.findNext(ctx);\n }\n}\n\n/**\n * ThrowCommand - Throw an error\n *\n * Parses: throw expression\n * Executes: Throws the evaluated expression\n */\nexport class ThrowCommand extends Command {\n static keyword = \"throw\";\n\n constructor(expr) {\n super();\n this.expr = expr;\n this.args = { value: expr };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"throw\")) return;\n var expr = parser.requireElement(\"expression\");\n return new ThrowCommand(expr);\n }\n\n resolve(ctx, { value }) {\n ctx.meta.runtime.registerHyperTrace(ctx, value);\n throw value;\n }\n}\n\n/**\n * ReturnCommand - Return a value from handler\n *\n * Parses: return expression\n * Executes: Returns value and halts execution\n */\nexport class ReturnCommand extends Command {\n static keyword = \"return\";\n\n constructor(value) {\n super();\n this.value = value;\n this.args = { value };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"return\")) return;\n var value;\n if (!parser.commandBoundary(parser.currentToken())) {\n value = parser.requireElement(\"expression\");\n }\n return new ReturnCommand(value);\n }\n\n resolve(context, { value }) {\n var resolve = context.meta.resolve;\n context.meta.returned = true;\n context.meta.returnValue = value;\n if (resolve) resolve(value);\n return context.meta.runtime.HALT;\n }\n}\n\n/**\n * ExitCommand - Exit handler without returning value\n *\n * Parses: exit\n * Executes: Exits and halts execution\n */\nexport class ExitCommand extends Command {\n static keyword = \"exit\";\n\n static parse(parser) {\n if (!parser.matchToken(\"exit\")) return;\n return new ExitCommand();\n }\n\n resolve(context) {\n var resolve = context.meta.resolve;\n context.meta.returned = true;\n context.meta.returnValue = null;\n if (resolve) {\n resolve();\n }\n return context.meta.runtime.HALT;\n }\n}\n\n/**\n * HaltCommand - Halt event bubbling/default behavior\n *\n * Parses: halt [the event] [bubbling|default]\n * Executes: Stops event propagation/default\n */\nexport class HaltCommand extends Command {\n static keyword = \"halt\";\n\n constructor(bubbling, haltDefault, keepExecuting, exit) {\n super();\n this.keepExecuting = keepExecuting;\n this.bubbling = bubbling;\n this.haltDefault = haltDefault;\n this.exit = exit;\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"halt\")) return;\n if (parser.matchToken(\"the\")) {\n parser.requireToken(\"event\");\n // optional possessive\n if (parser.matchOpToken(\"'\")) {\n parser.requireToken(\"s\");\n }\n var keepExecuting = true;\n }\n if (parser.matchToken(\"bubbling\")) {\n var bubbling = true;\n } else if (parser.matchToken(\"default\")) {\n var haltDefault = true;\n }\n var exit = new ExitCommand();\n return new HaltCommand(bubbling, haltDefault, keepExecuting, exit);\n }\n\n resolve(ctx) {\n if (ctx.event) {\n if (this.bubbling) {\n ctx.event.stopPropagation();\n } else if (this.haltDefault) {\n ctx.event.preventDefault();\n } else {\n ctx.event.stopPropagation();\n ctx.event.preventDefault();\n }\n }\n if (this.keepExecuting) {\n return this.findNext(ctx);\n } else {\n return this.exit;\n }\n }\n}\n\n/**\n * MakeCommand - Create/instantiate objects or elements\n *\n * Parses: make [a|an] [from ] [called ]\n * Executes: Creates DOM elements from query refs or instantiates objects\n */\nexport class MakeCommand extends Command {\n static keyword = \"make\";\n\n constructor(variant, expr, constructorArgs, target) {\n super();\n this.variant = variant;\n this.expr = expr;\n this.constructorArgs = constructorArgs;\n this.target = target;\n this.args = variant === \"queryRef\" ? null : { expr, constructorArgs };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"make\")) return;\n parser.matchToken(\"a\") || parser.matchToken(\"an\");\n\n var expr = parser.requireElement(\"expression\");\n\n var args = [];\n if (expr.type !== \"queryRef\" && parser.matchToken(\"from\")) {\n do {\n args.push(parser.requireElement(\"expression\"));\n } while (parser.matchOpToken(\",\"));\n }\n\n if (parser.matchToken(\"called\")) {\n var target = parser.requireElement(\"symbol\");\n }\n\n if (expr.type === \"queryRef\") {\n return new MakeCommand(\"queryRef\", expr, null, target);\n } else {\n return new MakeCommand(\"constructor\", expr, args, target);\n }\n }\n\n resolve(ctx, { expr, constructorArgs } = {}) {\n if (this.variant === \"queryRef\") {\n var match,\n tagname = \"div\",\n id,\n classes = [];\n var re = /(?:(^|#|\\.)([^#\\. ]+))/g;\n while ((match = re.exec(this.expr.css))) {\n if (match[1] === \"\") tagname = match[2].trim();\n else if (match[1] === \"#\") id = match[2].trim();\n else classes.push(match[2].trim());\n }\n\n var result = document.createElement(tagname);\n if (id !== undefined) result.id = id;\n result.classList.add(...classes);\n\n ctx.result = result;\n } else {\n ctx.result = new expr(...constructorArgs);\n }\n\n if (this.target) {\n ctx.meta.runtime.setSymbol(this.target.name, ctx, this.target.scope, ctx.result);\n }\n\n return this.findNext(ctx);\n }\n}\n\n/**\n * AppendCommand - Append to collection/string/DOM\n *\n * Parses: append [to ]\n * Executes: Appends value to array, string, or DOM element\n */\nexport class AppendCommand extends Command {\n static keyword = \"append\";\n\n constructor(value, targetExpr, assignable) {\n super();\n this.value = value;\n this._target = targetExpr;\n this.assignable = assignable;\n if (assignable) {\n this.args = { target: targetExpr, value, ...targetExpr.lhs };\n } else {\n this.args = { target: targetExpr, value };\n }\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"append\")) return;\n var targetExpr = null;\n\n var value = parser.requireElement(\"expression\");\n\n if (parser.matchToken(\"to\")) {\n targetExpr = parser.requireElement(\"expression\");\n } else {\n targetExpr = new ImplicitResultSymbol();\n }\n\n var checkTarget = targetExpr;\n while (checkTarget.type === \"parenthesized\") checkTarget = checkTarget.expr;\n var assignable = checkTarget.set != null;\n\n return new AppendCommand(value, targetExpr, assignable);\n }\n\n resolve(context, args) {\n var { target, value, ...lhs } = args;\n if (Array.isArray(target)) {\n target.push(value);\n context.meta.runtime.notifyMutation(target);\n } else if (target instanceof Set) {\n target.add(value);\n context.meta.runtime.notifyMutation(target);\n } else if (target instanceof Element) {\n if (value instanceof Element) {\n target.insertAdjacentElement(\"beforeend\", value);\n } else {\n target.insertAdjacentHTML(\"beforeend\", value);\n }\n context.meta.runtime.processNode(target);\n } else if(this.assignable) {\n this._target.set(context, lhs, (target || \"\") + value);\n } else {\n throw new Error(\"Unable to append a value!\")\n }\n return this.findNext(context);\n }\n}\n\n/**\n * PickCommand - Extract items from collections\n *\n * Parses: pick first of \n * pick last of \n * pick random [] of \n * pick [the] item[s]|character[s] of|from \n * pick [the] match[es] [of] [|] of|from \n */\nexport class PickCommand extends Command {\n static keyword = \"pick\";\n\n constructor(variant, root, range, re, flags, count) {\n super();\n this.variant = variant;\n this.range = range;\n this.flags = flags;\n if (variant === \"range\") {\n this.args = { root, from: range.from, to: range.to };\n } else if (variant === \"first\" || variant === \"last\" || variant === \"random\") {\n this.args = { root, count };\n } else {\n this.args = { root, re };\n }\n }\n\n static parsePickRange(parser) {\n parser.matchToken(\"at\") || parser.matchToken(\"from\");\n var rv = { includeStart: true, includeEnd: false };\n\n rv.from = parser.matchToken(\"start\") ? 0 : parser.requireElement(\"expression\");\n\n if (parser.matchToken(\"to\") || parser.matchOpToken(\"..\")) {\n if (parser.matchToken(\"end\")) {\n rv.toEnd = true;\n } else {\n rv.to = parser.requireElement(\"expression\");\n }\n }\n\n if (parser.matchToken(\"inclusive\")) rv.includeEnd = true;\n else if (parser.matchToken(\"exclusive\")) rv.includeStart = false;\n\n return rv;\n }\n\n static parseSource(parser) {\n if (!parser.matchAnyToken(\"of\", \"from\")) {\n parser.raiseExpected('of', 'from');\n }\n return parser.requireElement(\"expression\");\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"pick\")) return;\n\n parser.matchToken(\"the\");\n\n if (parser.matchToken(\"first\")) {\n var follows = parser.pushFollows(\"of\", \"from\");\n try { var count = parser.requireElement(\"expression\"); }\n finally { parser.popFollows(follows); }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"first\", root, null, null, null, count);\n }\n\n if (parser.matchToken(\"last\")) {\n var follows = parser.pushFollows(\"of\", \"from\");\n try { var count = parser.requireElement(\"expression\"); }\n finally { parser.popFollows(follows); }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"last\", root, null, null, null, count);\n }\n\n if (parser.matchToken(\"random\")) {\n var count = null;\n if (parser.currentToken().type === \"NUMBER\") {\n var follows = parser.pushFollows(\"of\", \"from\");\n try { count = parser.requireElement(\"expression\"); }\n finally { parser.popFollows(follows); }\n }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"random\", root, null, null, null, count);\n }\n\n if (parser.matchToken(\"item\") || parser.matchToken(\"items\")\n || parser.matchToken(\"character\") || parser.matchToken(\"characters\")) {\n var follows = parser.pushFollows(\"of\", \"from\");\n try { var range = PickCommand.parsePickRange(parser); }\n finally { parser.popFollows(follows); }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"range\", root, range, null, null);\n }\n\n if (parser.matchToken(\"match\")) {\n parser.matchToken(\"of\");\n var follows = parser.pushFollows(\"of\", \"from\");\n try {\n var re = parser.parseElement(\"expression\");\n var flags = \"\";\n if (parser.matchOpToken(\"|\")) {\n flags = parser.requireTokenType(\"IDENTIFIER\").value;\n }\n } finally { parser.popFollows(follows); }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"match\", root, null, re, flags);\n }\n\n if (parser.matchToken(\"matches\")) {\n parser.matchToken(\"of\");\n var follows = parser.pushFollows(\"of\", \"from\");\n try {\n var re = parser.parseElement(\"expression\");\n var flags = \"gu\";\n if (parser.matchOpToken(\"|\")) {\n flags = 'g' + parser.requireTokenType(\"IDENTIFIER\").value.replace('g', '');\n }\n } finally { parser.popFollows(follows); }\n var root = PickCommand.parseSource(parser);\n return new PickCommand(\"matches\", root, null, re, flags);\n }\n }\n\n resolve(ctx, { root, from, to, re, count }) {\n if (root == null) { ctx.result = root; return this.findNext(ctx); }\n if (this.variant === \"first\") {\n ctx.result = root.slice(0, count);\n } else if (this.variant === \"last\") {\n ctx.result = root.slice(-count);\n } else if (this.variant === \"random\") {\n if (count == null) {\n ctx.result = root[Math.floor(Math.random() * root.length)];\n } else {\n var copy = Array.from(root);\n var result = [];\n for (var i = 0; i < count && copy.length > 0; i++) {\n var idx = Math.floor(Math.random() * copy.length);\n result.push(copy.splice(idx, 1)[0]);\n }\n ctx.result = result;\n }\n } else if (this.variant === \"range\") {\n if (this.range.toEnd) to = root.length;\n if (!this.range.includeStart) from++;\n if (this.range.includeEnd) to++;\n if (to == null) to = from + 1;\n ctx.result = root.slice(from, to);\n } else if (this.variant === \"match\") {\n ctx.result = new RegExp(re, this.flags).exec(root);\n } else {\n ctx.result = new RegExpIterable(re, this.flags, root);\n }\n return this.findNext(ctx);\n }\n}\n\n/**\n * FetchCommand - HTTP fetch\n *\n * Parses: fetch [as ] [with ]\n * Executes: Performs HTTP fetch with optional response conversion\n */\nexport class FetchCommand extends Command {\n static keyword = \"fetch\";\n\n constructor(url, argExprs, conversionType, conversion, dontThrow) {\n super();\n this.url = url;\n this.argExpressions = argExprs;\n this.args = { url, options: argExprs };\n this.conversionType = conversionType;\n this.conversion = conversion;\n this.dontThrow = dontThrow;\n }\n\n static parseConversionInfo(parser) {\n var type = \"text\";\n var conversion;\n parser.matchToken(\"a\") || parser.matchToken(\"an\");\n if (parser.matchToken(\"json\") || parser.matchToken(\"JSON\") || parser.matchToken(\"Object\")) {\n type = \"json\";\n } else if (parser.matchToken(\"response\") || parser.matchToken(\"Response\")) {\n type = \"response\";\n } else if (parser.matchToken(\"html\") || parser.matchToken(\"HTML\")) {\n type = \"html\";\n } else if (parser.matchToken(\"text\") || parser.matchToken(\"Text\") || parser.matchToken(\"String\")) {\n // default\n } else {\n conversion = parser.requireElement(\"dotOrColonPath\").evalStatically();\n }\n return {type, conversion};\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"fetch\")) return;\n var url = parser.parseURLOrExpression();\n\n if (parser.matchToken(\"as\")) {\n var conversionInfo = FetchCommand.parseConversionInfo(parser);\n }\n\n if (parser.matchToken(\"with\") && parser.currentToken().value !== \"{\") {\n var argExprs = parser.parseElement(\"nakedNamedArgumentList\");\n } else {\n var argExprs = parser.parseElement(\"objectLiteral\");\n }\n\n if (conversionInfo == null && parser.matchToken(\"as\")) {\n conversionInfo = FetchCommand.parseConversionInfo(parser);\n }\n\n var dontThrow = false;\n if (parser.matchToken(\"do\")) {\n parser.requireToken(\"not\");\n parser.requireToken(\"throw\");\n dontThrow = true;\n } else if (parser.currentToken().value === \"don\" &&\n parser.token(1).value === \"'\" &&\n parser.token(2).value === \"t\" &&\n parser.token(1).start === parser.currentToken().end &&\n parser.token(2).start === parser.token(1).end) {\n parser.consumeToken(); // don\n parser.consumeToken(); // '\n parser.consumeToken(); // t\n parser.requireToken(\"throw\");\n dontThrow = true;\n }\n\n var type = conversionInfo ? conversionInfo.type : \"text\";\n var conversion = conversionInfo ? conversionInfo.conversion : null;\n\n return new FetchCommand(url, argExprs, type, conversion, dontThrow);\n }\n\n resolve(context, { url, options }) {\n var detail = options || {};\n detail.sender = context.me;\n detail.headers = detail.headers || {};\n detail.conversion = this.conversion || this.conversionType;\n var abortController = new AbortController();\n var abortListener = () => abortController.abort();\n context.me.addEventListener('fetch:abort', abortListener, {once: true});\n detail.signal = abortController.signal;\n context.meta.runtime.triggerEvent(context.me, \"hyperscript:beforeFetch\", detail);\n context.meta.runtime.triggerEvent(context.me, \"fetch:beforeRequest\", detail);\n var finished = false;\n if (detail.timeout) {\n setTimeout(() => { if (!finished) abortController.abort(); }, detail.timeout);\n }\n\n var complete = (result) => {\n context.result = result;\n context.meta.runtime.triggerEvent(context.me, \"fetch:afterRequest\", {result});\n finished = true;\n return this.findNext(context);\n };\n\n var checkThrow = !this.dontThrow && this.conversionType !== \"response\";\n\n return fetch(url, detail)\n .then((resp) => {\n var resultDetails = {response: resp};\n context.meta.runtime.triggerEvent(context.me, \"fetch:afterResponse\", resultDetails);\n resp = resultDetails.response;\n\n if (checkThrow) {\n var statusStr = String(resp.status);\n var patterns = config.fetchThrowsOn || [];\n for (var i = 0; i < patterns.length; i++) {\n if (patterns[i].test(statusStr)) {\n var err = new Error(\"fetch failed: \" + resp.status + \" \" + resp.statusText + \" (\" + url + \")\");\n err.response = resp;\n err.status = resp.status;\n throw err;\n }\n }\n }\n\n if (this.conversionType === \"response\") return complete(resp);\n if (this.conversionType === \"json\") return resp.json().then(complete);\n if (this.conversion) {\n var convFn = config.conversions[this.conversion];\n if (convFn && convFn._rawResponse) {\n return complete(convFn(resp, context.meta.runtime, context));\n }\n }\n return resp.text().then((result) => {\n if (this.conversion) result = context.meta.runtime.convertValue(result, this.conversion);\n if (this.conversionType === \"html\") result = context.meta.runtime.convertValue(result, \"Fragment\");\n return complete(result);\n });\n })\n .catch((reason) => {\n context.meta.runtime.triggerEvent(context.me, \"fetch:error\", {reason});\n throw reason;\n })\n .finally(() => {\n context.me.removeEventListener('fetch:abort', abortListener);\n });\n }\n}\n\nfunction _parseScrollModifiers(parser) {\n parser.matchToken(\"the\");\n var verticalPosition = parser.matchAnyToken(\"top\", \"middle\", \"bottom\");\n var horizontalPosition = parser.matchAnyToken(\"left\", \"center\", \"right\");\n if (verticalPosition || horizontalPosition) {\n parser.requireToken(\"of\");\n }\n var target = parser.requireElement(\"unaryExpression\");\n\n var plusOrMinus = parser.matchAnyOpToken(\"+\", \"-\");\n var offset;\n if (plusOrMinus) {\n parser.pushFollow(\"px\");\n try {\n offset = parser.requireElement(\"expression\");\n } finally {\n parser.popFollow();\n }\n }\n parser.matchToken(\"px\");\n\n var container;\n if (parser.matchToken(\"in\")) {\n container = parser.requireElement(\"unaryExpression\");\n }\n\n var smoothness = parser.matchAnyToken(\"smoothly\", \"instantly\");\n\n var scrollOptions = { block: \"start\", inline: \"nearest\" };\n\n var blockMap = { top: \"start\", bottom: \"end\", middle: \"center\" };\n var inlineMap = { left: \"start\", center: \"center\", right: \"end\" };\n var behaviorMap = { smoothly: \"smooth\", instantly: \"instant\" };\n if (verticalPosition) scrollOptions.block = blockMap[verticalPosition.value];\n if (horizontalPosition) scrollOptions.inline = inlineMap[horizontalPosition.value];\n if (smoothness) scrollOptions.behavior = behaviorMap[smoothness.value];\n\n return { target, offset, plusOrMinus, scrollOptions, container };\n}\n\nfunction _parseSmoothness(parser) {\n var smoothness = parser.matchAnyToken(\"smoothly\", \"instantly\");\n if (!smoothness) return undefined;\n return smoothness.value === \"smoothly\" ? \"smooth\" : \"instant\";\n}\n\nfunction _resolveScroll(ctx, to, offset, plusOrMinus, scrollOptions, container) {\n ctx.meta.runtime.implicitLoop(to, function (target) {\n if (target === window) target = document.body;\n\n // \"scroll to #item in #container\" - scroll within a specific container\n if (container) {\n var ctr = container instanceof Element ? container : container;\n var top = target.offsetTop - ctr.offsetTop;\n var left = target.offsetLeft - ctr.offsetLeft;\n if (plusOrMinus) {\n var adj = plusOrMinus.value === \"+\" ? offset : offset * -1;\n top += adj;\n }\n ctr.scrollTo({ top, left, behavior: scrollOptions.behavior || \"auto\" });\n return;\n }\n\n if (plusOrMinus) {\n var boundingRect = target.getBoundingClientRect();\n var scrollShim = document.createElement(\"div\");\n var actualOffset = plusOrMinus.value === \"+\" ? offset : offset * -1;\n var offsetX = scrollOptions.inline == \"start\" || scrollOptions.inline == \"end\" ? actualOffset : 0;\n var offsetY = scrollOptions.block == \"start\" || scrollOptions.block == \"end\" ? actualOffset : 0;\n\n scrollShim.style.position = \"absolute\";\n scrollShim.style.top = (boundingRect.top + window.scrollY + offsetY) + \"px\";\n scrollShim.style.left = (boundingRect.left + window.scrollX + offsetX) + \"px\";\n scrollShim.style.height = boundingRect.height + \"px\";\n scrollShim.style.width = boundingRect.width + \"px\";\n scrollShim.style.zIndex = \"\" + Number.MIN_SAFE_INTEGER;\n scrollShim.style.opacity = \"0\";\n\n document.body.appendChild(scrollShim);\n setTimeout(function () { document.body.removeChild(scrollShim); }, 100);\n target = scrollShim;\n }\n\n target.scrollIntoView(scrollOptions);\n });\n}\n\n/**\n * ScrollCommand - Scroll to element or scroll by amount\n *\n * Parses:\n * scroll to [the] [top|middle|bottom] [left|center|right] [of] [+/- px] [in ] [smoothly|instantly]\n * scroll [] [up|down|left|right] by px [smoothly|instantly]\n */\nexport class ScrollCommand extends Command {\n static keyword = \"scroll\";\n\n constructor(target, offset, plusOrMinus, scrollOptions, container, byMode) {\n super();\n this.target = target;\n this.plusOrMinus = plusOrMinus;\n this.scrollOptions = scrollOptions;\n this.byMode = byMode;\n this.args = { target, offset, container };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"scroll\")) return;\n\n // scroll to ... form\n if (parser.matchToken(\"to\")) {\n var scroll = _parseScrollModifiers(parser);\n return new ScrollCommand(scroll.target, scroll.offset, scroll.plusOrMinus, scroll.scrollOptions, scroll.container);\n }\n\n // scroll [] [up|down|left|right] by px [smoothly|instantly]\n var direction = parser.matchAnyToken(\"up\", \"down\", \"left\", \"right\");\n var target;\n\n if (!direction && parser.currentToken().value !== \"by\") {\n target = parser.requireElement(\"unaryExpression\");\n direction = parser.matchAnyToken(\"up\", \"down\", \"left\", \"right\");\n }\n\n parser.requireToken(\"by\");\n\n parser.pushFollow(\"px\");\n var offset;\n try {\n offset = parser.requireElement(\"expression\");\n } finally {\n parser.popFollow();\n }\n parser.matchToken(\"px\");\n\n var behavior = _parseSmoothness(parser);\n var scrollOptions = {};\n if (behavior) scrollOptions.behavior = behavior;\n\n var byMode = { direction: direction ? direction.value : \"down\" };\n return new ScrollCommand(target, offset, null, scrollOptions, null, byMode);\n }\n\n resolve(ctx, { target, offset, container }) {\n if (this.byMode) {\n var el = target || document.documentElement;\n var dir = this.byMode.direction;\n var top = 0, left = 0;\n if (dir === \"up\") top = -offset;\n else if (dir === \"down\") top = offset;\n else if (dir === \"left\") left = -offset;\n else if (dir === \"right\") left = offset;\n var opts = { top, left };\n if (this.scrollOptions.behavior) opts.behavior = this.scrollOptions.behavior;\n el.scrollBy(opts);\n } else {\n _resolveScroll(ctx, target, offset, this.plusOrMinus, this.scrollOptions, container);\n }\n return this.findNext(ctx);\n }\n}\n\n/**\n * GoCommand - Navigate or scroll (scroll form deprecated, use ScrollCommand)\n *\n * Parses: go back | go [to] [in new window]\n */\nexport class GoCommand extends Command {\n static keyword = \"go\";\n\n constructor(target, offset, back, newWindow, plusOrMinus, scrollOptions) {\n super();\n this.target = target;\n this.args = { target, offset };\n this.back = back;\n this.newWindow = newWindow;\n this.plusOrMinus = plusOrMinus;\n this.scrollOptions = scrollOptions;\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"go\")) return;\n\n if (parser.matchToken(\"back\")) {\n return new GoCommand(null, null, true);\n }\n\n parser.matchToken(\"to\");\n\n // deprecated: go [to] url \n if (parser.matchToken(\"url\")) {\n var target = parser.requireElement(\"stringLike\");\n var newWindow = false;\n if (parser.matchToken(\"in\")) {\n parser.requireToken(\"new\");\n parser.requireToken(\"window\");\n newWindow = true;\n }\n return new GoCommand(target, null, false, newWindow);\n }\n\n // deprecated: go [to] [the] top/middle/bottom ... of (scroll form)\n var cur = parser.currentToken();\n if (cur.value === \"the\" || cur.value === \"top\" || cur.value === \"middle\" || cur.value === \"bottom\"\n || cur.value === \"left\" || cur.value === \"center\" || cur.value === \"right\") {\n var scroll = _parseScrollModifiers(parser);\n return new GoCommand(scroll.target, scroll.offset, false, false, scroll.plusOrMinus, scroll.scrollOptions);\n }\n\n // new: go [to] [in new window]\n var target = parser.parseURLOrExpression();\n var newWindow = false;\n if (parser.matchToken(\"in\")) {\n parser.requireToken(\"new\");\n parser.requireToken(\"window\");\n newWindow = true;\n }\n return new GoCommand(target, null, false, newWindow);\n }\n\n resolve(ctx, { target: to, offset }) {\n if (this.back) {\n window.history.back();\n } else if (this.scrollOptions) {\n // deprecated scroll form\n _resolveScroll(ctx, to, offset, this.plusOrMinus, this.scrollOptions);\n } else if (to != null) {\n if (to instanceof Element) {\n // element -> scroll (backwards compat)\n to.scrollIntoView({ block: \"start\", inline: \"nearest\" });\n } else {\n var str = String(to);\n if (str.startsWith(\"#\")) {\n window.location.hash = str;\n } else if (this.newWindow) {\n window.open(str);\n } else {\n window.location.href = str;\n }\n }\n }\n return this.findNext(ctx);\n }\n}\n", "/**\n * Setter command parse tree elements\n * Commands that modify values (set, default, increment, decrement, put)\n */\n\nimport { Command } from '../base.js';\n\n/**\n * SetCommand - Set variable or property\n *\n * Parses: set {obj} on target OR set target to value\n * Executes: Assigns value to target using target's lhs/set() contract\n */\nexport class SetCommand extends Command {\n static keyword = \"set\";\n\n constructor(target, valueExpr, objectLiteral = null) {\n super();\n this.target = target;\n this.objectLiteral = objectLiteral;\n\n if (objectLiteral) {\n this.args = { obj: objectLiteral, setTarget: target };\n } else {\n this.args = { ...target.lhs, value: valueExpr };\n }\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"set\")) return;\n\n // set {obj} on target form\n if (parser.currentToken().type === \"L_BRACE\") {\n var obj = parser.requireElement(\"objectLiteral\");\n parser.requireToken(\"on\");\n var target = parser.requireElement(\"expression\");\n return new SetCommand(target, null, obj);\n }\n\n // set target to value form\n try {\n parser.pushFollow(\"to\");\n var target = parser.requireElement(\"assignableExpression\");\n } finally {\n parser.popFollow();\n }\n // Unwrap parenthesized expressions\n while (target.type === \"parenthesized\") target = target.expr;\n parser.requireToken(\"to\");\n var value = parser.requireElement(\"expression\");\n return new SetCommand(target, value);\n }\n\n resolve(context, args) {\n if (this.objectLiteral) {\n var { obj, setTarget } = args;\n Object.assign(setTarget, obj);\n } else {\n var { value, ...lhs } = args;\n this.target.set(context, lhs, value);\n }\n return this.findNext(context);\n }\n}\n\n/**\n * DefaultCommand - Set default value if undefined\n *\n * Parses: default target to value\n * Executes: Sets target to value only if target is null or undefined\n */\nexport class DefaultCommand extends Command {\n static keyword = \"default\";\n\n constructor(target, setter) {\n super();\n this.target = target;\n this.setter = setter;\n this.args = { targetValue: target };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"default\")) return;\n try {\n parser.pushFollow(\"to\");\n var target = parser.requireElement(\"assignableExpression\");\n } finally {\n parser.popFollow();\n }\n // Unwrap parenthesized expressions\n while (target.type === \"parenthesized\") target = target.expr;\n parser.requireToken(\"to\");\n\n var value = parser.requireElement(\"expression\");\n\n var setter = new SetCommand(target, value);\n var defaultCmd = new DefaultCommand(target, setter);\n setter.parent = defaultCmd;\n return defaultCmd;\n }\n\n resolve(context, { targetValue }) {\n if (targetValue != null && targetValue !== \"\") {\n return this.findNext(context);\n } else {\n return this.setter;\n }\n }\n}\n\n/**\n * IncrementCommand - Increment numeric value\n *\n * Parses: increment target [by amount]\n * Executes: Adds amount (default 1) to target\n */\nexport class IncrementCommand extends Command {\n static keyword = \"increment\";\n\n constructor(target, amountExpr) {\n super();\n this.target = target;\n this.amountExpr = amountExpr;\n this.args = { targetValue: target, amount: amountExpr, ...target.lhs };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"increment\")) return;\n var amountExpr;\n\n // This is optional. Defaults to \"result\"\n var target = parser.parseElement(\"assignableExpression\");\n // Unwrap parenthesized expressions\n while (target.type === \"parenthesized\") target = target.expr;\n\n // This is optional. Defaults to 1.\n if (parser.matchToken(\"by\")) {\n amountExpr = parser.requireElement(\"expression\");\n }\n\n return new IncrementCommand(target, amountExpr);\n }\n\n resolve(context, args) {\n var { targetValue, amount, ...lhs } = args;\n targetValue = targetValue ? parseFloat(targetValue) : 0;\n amount = this.amountExpr ? parseFloat(amount) : 1;\n var newValue = targetValue + amount;\n context.result = newValue;\n this.target.set(context, lhs, newValue);\n return this.findNext(context);\n }\n}\n\n/**\n * DecrementCommand - Decrement numeric value\n *\n * Parses: decrement target [by amount]\n * Executes: Subtracts amount (default 1) from target\n */\nexport class DecrementCommand extends Command {\n static keyword = \"decrement\";\n\n constructor(target, amountExpr) {\n super();\n this.target = target;\n this.amountExpr = amountExpr;\n this.args = { targetValue: target, amount: amountExpr, ...target.lhs };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"decrement\")) return;\n var amountExpr;\n\n // This is optional. Defaults to \"result\"\n try {\n parser.pushFollow(\"by\");\n var target = parser.parseElement(\"assignableExpression\");\n } finally {\n parser.popFollow();\n }\n // Unwrap parenthesized expressions\n while (target.type === \"parenthesized\") target = target.expr;\n\n // This is optional. Defaults to 1.\n if (parser.matchToken(\"by\")) {\n amountExpr = parser.requireElement(\"expression\");\n }\n\n return new DecrementCommand(target, amountExpr);\n }\n\n resolve(context, args) {\n var { targetValue, amount, ...lhs } = args;\n targetValue = targetValue ? parseFloat(targetValue) : 0;\n amount = this.amountExpr ? parseFloat(amount) : 1;\n var newValue = targetValue - amount;\n context.result = newValue;\n this.target.set(context, lhs, newValue);\n return this.findNext(context);\n }\n}\n\n/**\n * SwapCommand - Swap two values\n *\n * Parses: swap target1 with target2\n * Executes: Swaps the values of two assignable expressions\n */\nexport class SwapCommand extends Command {\n static keyword = \"swap\";\n\n constructor(target1, target2) {\n super();\n this.target1 = target1;\n this.target2 = target2;\n this.args = {\n value1: target1, value2: target2,\n root1: target1.lhs.root, index1: target1.lhs.index,\n root2: target2.lhs.root, index2: target2.lhs.index,\n };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"swap\")) return;\n try {\n parser.pushFollow(\"with\");\n var target1 = parser.requireElement(\"assignableExpression\");\n } finally {\n parser.popFollow();\n }\n while (target1.type === \"parenthesized\") target1 = target1.expr;\n parser.requireToken(\"with\");\n var target2 = parser.requireElement(\"assignableExpression\");\n while (target2.type === \"parenthesized\") target2 = target2.expr;\n return new SwapCommand(target1, target2);\n }\n\n resolve(context, { value1, value2, root1, index1, root2, index2 }) {\n if (value1 instanceof Element && value2 instanceof Element) {\n // DOM swap needs placeholders to avoid position interference\n var placeholder = document.createComment('');\n value1.replaceWith(placeholder);\n value2.replaceWith(value1);\n placeholder.replaceWith(value2);\n } else {\n this.target1.set(context, { root: root1, index: index1 }, value2);\n this.target2.set(context, { root: root2, index: index2 }, value1);\n }\n return this.findNext(context);\n }\n}\n\n/**\n * PutCommand - Put value into/before/after target (web-specific)\n *\n * Parses: put expr into target | put expr before/after target | put expr at start/end of target\n * Executes: Inserts value into DOM or variable\n */\nexport class PutCommand extends Command {\n static keyword = \"put\";\n\n constructor(target, operation, value, rootExpr) {\n super();\n this.target = target;\n this.operation = operation;\n this.value = value;\n this.rootExpr = rootExpr;\n\n // Derive flags from target type\n this.symbolWrite = target.type === \"symbol\" && operation === \"into\";\n this.arrayIndex = target.type === \"arrayIndex\";\n this.attributeWrite = (target.type === \"attributeRef\" ||\n (target.attribute && target.attribute.type === \"attributeRef\")) &&\n operation === \"into\";\n this.styleWrite = (target.type === \"styleRef\" ||\n (target.attribute && target.attribute.type === \"styleRef\")) &&\n operation === \"into\";\n\n // Derive property/prop\n if (this.arrayIndex) {\n this.prop = target.prop;\n } else if (this.symbolWrite) {\n this.prop = target.name;\n } else if (target.type === \"attributeRef\" || target.type === \"styleRef\") {\n this.prop = target.name;\n } else if (target.attribute) {\n this.prop = target.attribute.name;\n } else if (target.prop) {\n this.prop = target.prop.value;\n } else {\n this.prop = null;\n }\n\n this.args = { root: rootExpr, prop: this.prop, value };\n }\n\n static parse(parser) {\n if (!parser.matchToken(\"put\")) return;\n\n var value = parser.requireElement(\"expression\");\n\n var operationToken = parser.matchAnyToken(\"into\", \"before\", \"after\");\n\n if (operationToken == null && parser.matchToken(\"at\")) {\n parser.matchToken(\"the\"); // optional \"the\"\n operationToken = parser.matchAnyToken(\"start\", \"end\");\n parser.requireToken(\"of\");\n }\n\n if (operationToken == null) {\n parser.raiseExpected('into', 'before', 'at start of', 'at end of', 'after');\n }\n var target = parser.requireElement(\"expression\");\n // Unwrap parenthesized expressions\n while (target.type === \"parenthesized\") target = target.expr;\n\n var operation = operationToken.value;\n\n // Determine rootExpr based on target type\n var rootExpr;\n if (target.type === \"arrayIndex\" && operation === \"into\") {\n rootExpr = target.root;\n } else if (target.prop && target.root && operation === \"into\") {\n rootExpr = target.root;\n } else if (target.type === \"symbol\" && operation === \"into\") {\n rootExpr = null;\n } else if (target.type === \"attributeRef\" && operation === \"into\") {\n rootExpr = parser.requireElement(\"implicitMeTarget\");\n } else if (target.type === \"styleRef\" && operation === \"into\") {\n rootExpr = parser.requireElement(\"implicitMeTarget\");\n } else if (target.attribute && operation === \"into\") {\n rootExpr = target.root;\n } else {\n rootExpr = target;\n }\n\n return new PutCommand(target, operation, value, rootExpr);\n }\n\n putInto(context, root, prop, valueToPut) {\n if (root == null) {\n var value = context.meta.runtime.resolveSymbol(prop, context);\n } else {\n var value = root;\n }\n if ((root == null || prop == null) && (value instanceof Element || value instanceof Document)) {\n while (value.firstChild) value.removeChild(value.firstChild);\n value.append(context.meta.runtime.convertValue(valueToPut, \"Fragment\"));\n context.meta.runtime.processNode(value);\n } else {\n if (root == null) {\n context.meta.runtime.setSymbol(prop, context, null, valueToPut);\n } else {\n root[prop] = valueToPut\n }\n }\n }\n\n resolve(context, { root, prop, value: valueToPut }) {\n if (this.symbolWrite) {\n this.putInto(context, root, prop, valueToPut);\n } else {\n context.meta.runtime.nullCheck(root, this.rootExpr);\n if (this.operation === \"into\") {\n if (this.attributeWrite) {\n context.meta.runtime.implicitLoop(root, function (elt) {\n if (valueToPut == null) {\n elt.removeAttribute(prop);\n } else {\n elt.setAttribute(prop, valueToPut);\n }\n });\n } else if (this.styleWrite) {\n context.meta.runtime.implicitLoop(root, function (elt) {\n elt.style[prop] = valueToPut;\n });\n } else if (this.arrayIndex) {\n root[prop] = valueToPut;\n } else {\n var cmd = this;\n context.meta.runtime.implicitLoop(root, function (elt) {\n cmd.putInto(context, elt, prop, valueToPut);\n });\n }\n } else if (Array.isArray(root)) {\n if (this.operation === \"start\") {\n root.unshift(valueToPut);\n } else {\n root.push(valueToPut);\n }\n context.meta.runtime.notifyMutation(root);\n } else {\n var ops = { before: Element.prototype.before, after: Element.prototype.after,\n start: Element.prototype.prepend, end: Element.prototype.append };\n var op = ops[this.operation] || Element.prototype.append;\n\n context.meta.runtime.implicitLoop(root, function (elt) {\n op.call(\n elt,\n valueToPut instanceof Node\n ? valueToPut\n : context.meta.runtime.convertValue(valueToPut, \"Fragment\")\n );\n // process any new content\n if (elt.parentElement) {\n context.meta.runtime.processNode(elt.parentElement);\n } else {\n context.meta.runtime.processNode(elt);\n }\n });\n }\n }\n return this.findNext(context);\n }\n}\n", "/**\n * Event-related command parse tree elements\n * Commands for event handling and waiting (wait, trigger, send)\n */\n\nimport { Command, Expression, ParseElement } from '../base.js';\n\n/**\n * WaitCommand - Wait for time or event\n *\n * Parses: wait [a tick] | wait