var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __hasOwnProp = Object.prototype.hasOwnProperty;
function __accessProp(key) {
  return this[key];
}
var __toCommonJS = (from) => {
  var entry = (__moduleCache ??= new WeakMap).get(from), desc;
  if (entry)
    return entry;
  entry = __defProp({}, "__esModule", { value: true });
  if (from && typeof from === "object" || typeof from === "function") {
    for (var key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(entry, key))
        __defProp(entry, key, {
          get: __accessProp.bind(from, key),
          enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
        });
  }
  __moduleCache.set(from, entry);
  return entry;
};
var __moduleCache;
var __returnValue = (v) => v;
function __exportSetter(name, newValue) {
  this[name] = __returnValue.bind(null, newValue);
}
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, {
      get: all[name],
      enumerable: true,
      configurable: true,
      set: __exportSetter.bind(all, name)
    });
};

// ../../packages/compiler/src/index.ts
var exports_src = {};
__export(exports_src, {
  parse: () => parse,
  generateNative: () => generateNative,
  generate: () => generate,
  compileWireFile: () => compileWireFile,
  compileNativeWireFile: () => compileNativeWireFile,
  compile: () => compile,
  ParseError: () => ParseError,
  NativeCompileError: () => NativeCompileError,
  Lexer: () => Lexer,
  LexError: () => LexError
});
module.exports = __toCommonJS(exports_src);

// ../../packages/compiler/src/tokenizer.ts
class LexError extends Error {
}
var isWs = (c) => c === " " || c === "\t" || c === `
` || c === "\r";
var isIdentStart = (c) => /[A-Za-z_]/.test(c);
var isIdentPart = (c) => /[A-Za-z0-9_]/.test(c);

class Lexer {
  src;
  pos = 0;
  constructor(src) {
    this.src = src;
  }
  skipTrivia() {
    const { src } = this;
    while (this.pos < src.length) {
      const c = src[this.pos];
      if (isWs(c)) {
        this.pos++;
        continue;
      }
      if (c === "/" && src[this.pos + 1] === "/") {
        while (this.pos < src.length && src[this.pos] !== `
`)
          this.pos++;
        continue;
      }
      break;
    }
  }
  next() {
    this.skipTrivia();
    const { src } = this;
    const pos = this.pos;
    if (pos >= src.length)
      return { type: "eof", value: "", pos };
    const c = src[pos];
    switch (c) {
      case "{":
        this.pos++;
        return { type: "lbrace", value: c, pos };
      case "}":
        this.pos++;
        return { type: "rbrace", value: c, pos };
      case "(":
        this.pos++;
        return { type: "lparen", value: c, pos };
      case ")":
        this.pos++;
        return { type: "rparen", value: c, pos };
      case "@":
        this.pos++;
        return { type: "at", value: c, pos };
      case "=":
        this.pos++;
        return { type: "eq", value: c, pos };
      case ",":
        this.pos++;
        return { type: "comma", value: c, pos };
      case '"':
      case "'":
        return this.readString(c, pos);
    }
    if (isIdentStart(c)) {
      let v = "";
      while (this.pos < src.length && isIdentPart(src[this.pos]))
        v += src[this.pos++];
      return { type: "ident", value: v, pos };
    }
    throw new LexError(`Unexpected character '${c}' at offset ${pos} (line ${this.lineAt(pos)})`);
  }
  peek() {
    const save = this.pos;
    const t = this.next();
    this.pos = save;
    return t;
  }
  readString(quote, pos) {
    const { src } = this;
    let v = "";
    this.pos++;
    while (this.pos < src.length) {
      const c = src[this.pos++];
      if (c === "\\") {
        const n = src[this.pos++];
        v += n === "n" ? `
` : n === "t" ? "\t" : n;
        continue;
      }
      if (c === quote)
        return { type: "string", value: v, pos };
      v += c;
    }
    throw new LexError(`Unterminated string at offset ${pos}`);
  }
  readPath() {
    this.skipTrivia();
    const { src } = this;
    let v = "";
    while (this.pos < src.length && !isWs(src[this.pos]) && src[this.pos] !== "{") {
      v += src[this.pos++];
    }
    if (!v)
      throw new LexError(`Expected a path at offset ${this.pos}`);
    return v;
  }
  readToLineEnd() {
    const { src } = this;
    let v = "";
    while (this.pos < src.length && src[this.pos] !== `
`)
      v += src[this.pos++];
    return v.trim();
  }
  readBalancedBraces() {
    this.skipTrivia();
    const { src } = this;
    if (src[this.pos] !== "{") {
      throw new LexError(`Expected '{' at offset ${this.pos}`);
    }
    const start = this.pos + 1;
    let depth = 0;
    let i = this.pos;
    let str = null;
    for (;i < src.length; i++) {
      const c = src[i];
      if (str) {
        if (c === "\\") {
          i++;
          continue;
        }
        if (c === str)
          str = null;
        continue;
      }
      if (c === '"' || c === "'" || c === "`") {
        str = c;
        continue;
      }
      if (c === "{")
        depth++;
      else if (c === "}") {
        depth--;
        if (depth === 0) {
          this.pos = i + 1;
          return src.slice(start, i);
        }
      }
    }
    throw new LexError(`Unbalanced braces starting at offset ${this.pos}`);
  }
  lineAt(pos) {
    let line = 1;
    for (let i = 0;i < pos && i < this.src.length; i++) {
      if (this.src[i] === `
`)
        line++;
    }
    return line;
  }
}

// ../../packages/compiler/src/parser.ts
var VOID_ELEMENTS = new Set([
  "area",
  "base",
  "br",
  "col",
  "embed",
  "hr",
  "img",
  "input",
  "link",
  "meta",
  "param",
  "source",
  "track",
  "wbr"
]);

class ParseError extends Error {
}
function parseSeoBlock(body) {
  const out = {};
  const pair = /([A-Za-z][A-Za-z0-9_-]*)\s*=\s*(?:"((?:\\.|[^"\\])*)"|'((?:\\.|[^'\\])*)'|([^\n;]+))/g;
  for (const match of body.matchAll(pair)) {
    const key = match[1];
    const rawValue = match[2] ?? match[3] ?? match[4] ?? "";
    out[key] = unescapeSeoValue(rawValue.trim());
  }
  return out;
}
function unescapeSeoValue(value) {
  return value.replace(/\\(["'\\nrt])/g, (_match, ch) => {
    if (ch === "n")
      return `
`;
    if (ch === "r")
      return "\r";
    if (ch === "t")
      return "\t";
    return ch;
  });
}
function parse(source) {
  const lx = new Lexer(source);
  const expect = (type) => {
    const t = lx.next();
    if (t.type !== type) {
      throw new ParseError(`Expected ${type} but got '${t.value || t.type}' at offset ${t.pos}`);
    }
    return t;
  };
  const expectKeyword = (kw) => {
    const t = lx.next();
    if (t.type !== "ident" || t.value !== kw) {
      throw new ParseError(`Expected '${kw}' but got '${t.value || t.type}' at offset ${t.pos}`);
    }
  };
  try {
    const opener = lx.next();
    if (opener.type !== "ident" || !["page", "component", "layout"].includes(opener.value)) {
      throw new ParseError(`Expected 'page', 'component', or 'layout' but got '${opener.value || opener.type}' at offset ${opener.pos}`);
    }
    const kind = opener.value;
    const name = expect("ident").value;
    expect("lbrace");
    let layout;
    const props = [];
    const states = [];
    const seo = {};
    const view = [];
    const styles = [];
    const functions = [];
    const dataApis = [];
    const modeFunctions = [];
    const lifecycle = {};
    const watches = [];
    const apis = [];
    const realtimes = [];
    while (lx.peek().type !== "rbrace") {
      const kw = lx.peek();
      if (kw.type === "eof")
        throw new ParseError(`Unexpected end of input inside ${kind}`);
      if (kw.type !== "ident") {
        throw new ParseError(`Expected a ${kind} member keyword at offset ${kw.pos}`);
      }
      switch (kw.value) {
        case "layout": {
          lx.next();
          expect("eq");
          layout = expect("string").value;
          break;
        }
        case "props": {
          lx.next();
          expect("lbrace");
          while (lx.peek().type !== "rbrace") {
            const t = lx.peek();
            if (t.type === "eof")
              throw new ParseError("Unexpected end of input inside props");
            if (t.type !== "ident") {
              throw new ParseError(`Expected a prop name at offset ${t.pos}`);
            }
            const pName = expect("ident").value;
            expect("eq");
            props.push({ name: pName, default: lx.readToLineEnd() });
          }
          expect("rbrace");
          break;
        }
        case "state": {
          lx.next();
          const sName = expect("ident").value;
          expect("eq");
          states.push({ name: sName, expr: lx.readToLineEnd() });
          break;
        }
        case "view": {
          lx.next();
          expect("lbrace");
          const { nodes, endPos } = parseHtmlView(lx.src, lx.pos);
          view.push(...nodes);
          lx.pos = endPos;
          expect("rbrace");
          break;
        }
        case "seo": {
          lx.next();
          Object.assign(seo, parseSeoBlock(lx.readBalancedBraces()));
          break;
        }
        case "api": {
          lx.next();
          const method = expect("ident").value.toUpperCase();
          const path = lx.readPath();
          const body = lx.readBalancedBraces();
          apis.push({ method, path, body });
          break;
        }
        case "ssr":
        case "client": {
          const mode = kw.value === "ssr" ? "ssr" : "client";
          lx.next();
          expect("lbrace");
          while (lx.peek().type !== "rbrace") {
            const member = lx.peek();
            if (member.type === "eof") {
              throw new ParseError(`Unexpected end of input inside ${mode} block`);
            }
            if (member.type !== "ident") {
              throw new ParseError(`Expected a ${mode} member keyword at offset ${member.pos}`);
            }
            switch (member.value) {
              case "api": {
                lx.next();
                const name2 = expect("ident").value;
                const method = expect("ident").value.toUpperCase();
                const path = lx.readPath();
                const body = lx.readBalancedBraces();
                dataApis.push({ mode, name: name2, method, path, body });
                break;
              }
              case "functions": {
                lx.next();
                modeFunctions.push({ mode, body: lx.readBalancedBraces() });
                break;
              }
              default:
                throw new ParseError(`Unknown ${mode} member '${member.value}' at offset ${member.pos}`);
            }
          }
          expect("rbrace");
          break;
        }
        case "realtime": {
          lx.next();
          const rName = expect("ident").value;
          expect("lbrace");
          const handlers = [];
          while (lx.peek().type !== "rbrace") {
            expectKeyword("on");
            const event = expect("ident").value;
            expect("lparen");
            const args = [];
            while (lx.peek().type !== "rparen") {
              args.push(expect("ident").value);
              if (lx.peek().type === "comma")
                lx.next();
            }
            expect("rparen");
            handlers.push({ event, args, body: lx.readBalancedBraces() });
          }
          expect("rbrace");
          realtimes.push({ name: rName, handlers });
          break;
        }
        case "style": {
          lx.next();
          styles.push(lx.readBalancedBraces());
          break;
        }
        case "lifecycle": {
          lx.next();
          expect("lbrace");
          while (lx.peek().type !== "rbrace") {
            const hook = lx.peek();
            if (hook.type === "eof") {
              throw new ParseError("Unexpected end of input inside lifecycle block");
            }
            if (hook.type !== "ident") {
              throw new ParseError(`Expected a lifecycle hook at offset ${hook.pos}`);
            }
            if (hook.value !== "mount" && hook.value !== "update" && hook.value !== "unmount") {
              throw new ParseError(`Unknown lifecycle hook '${hook.value}' at offset ${hook.pos}`);
            }
            const hookName = hook.value;
            lx.next();
            if (lifecycle[hookName] !== undefined) {
              throw new ParseError(`Duplicate lifecycle hook '${hookName}' at offset ${hook.pos}`);
            }
            lifecycle[hookName] = lx.readBalancedBraces();
          }
          expect("rbrace");
          break;
        }
        case "watch": {
          lx.next();
          const stateName = expect("ident").value;
          const body = lx.readBalancedBraces();
          watches.push({
            state: stateName,
            body
          });
          break;
        }
        case "functions": {
          lx.next();
          functions.push(lx.readBalancedBraces());
          break;
        }
        default:
          throw new ParseError(`Unknown page member '${kw.value}' at offset ${kw.pos}`);
      }
    }
    expect("rbrace");
    const declaredStates = new Set(states.map((state) => state.name));
    for (const watcher of watches) {
      if (!declaredStates.has(watcher.state)) {
        throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
      }
    }
    return {
      type: "page",
      kind,
      name,
      layout,
      props,
      states,
      seo,
      view,
      styles,
      functions,
      dataApis,
      modeFunctions,
      lifecycle,
      watches,
      apis,
      realtimes
    };
  } catch (err) {
    if (err instanceof LexError)
      throw new ParseError(err.message);
    throw err;
  }
}
function parseHtmlView(src, pos) {
  let i = pos;
  const isNameStart = (c) => /[A-Za-z_]/.test(c);
  const isTagNamePart = (c) => /[A-Za-z0-9_$:.-]/.test(c);
  const isAttributeNamePart = (c, next) => {
    if (c === "/") {
      return next !== ">";
    }
    return /[A-Za-z0-9_$:.[\]%-]/.test(c);
  };
  const isWs2 = (c) => c === " " || c === "\t" || c === `
` || c === "\r";
  const fail = (msg) => {
    throw new ParseError(`${msg} at offset ${i}`);
  };
  const skipWs = () => {
    while (i < src.length && isWs2(src[i]))
      i++;
  };
  const readInterpolation = () => {
    const start = i;
    let depth = 0;
    for (;i < src.length; i++) {
      if (src[i] === "{")
        depth++;
      else if (src[i] === "}" && --depth === 0) {
        i++;
        return src.slice(start, i);
      }
    }
    return fail("Unterminated `{` interpolation in view");
  };
  const readQuoted = () => {
    const quote = src[i];
    if (quote !== '"' && quote !== "'")
      return fail("Expected a quoted attribute value");
    i++;
    const start = i;
    while (i < src.length && src[i] !== quote)
      i++;
    if (i >= src.length)
      return fail("Unterminated attribute value");
    const value = src.slice(start, i);
    i++;
    return value;
  };
  const readTagName = () => {
    if (i >= src.length || !isNameStart(src[i])) {
      return fail("Expected a tag name");
    }
    const start = i++;
    while (i < src.length && isTagNamePart(src[i])) {
      i++;
    }
    return src.slice(start, i);
  };
  const readAttributeName = () => {
    const first = src[i];
    if (i >= src.length || !isNameStart(first) && first !== ":" && first !== "$") {
      return fail("Expected an attribute name");
    }
    const start = i++;
    while (i < src.length && isAttributeNamePart(src[i], src[i + 1])) {
      i++;
    }
    return src.slice(start, i);
  };
  const parseTag = () => {
    i++;
    const tag = readTagName();
    const attrs = [];
    for (;; ) {
      skipWs();
      const c = src[i];
      if (c === undefined)
        return fail(`Unterminated <${tag}> tag`);
      if (c === ">") {
        i++;
        break;
      }
      if (c === "/" && src[i + 1] === ">") {
        i += 2;
        return { type: "element", tag, attrs, children: [] };
      }
      if (c === "@") {
        i++;
        const name2 = readAttributeName();
        skipWs();
        if (src[i] !== "=")
          return fail(`Expected '=' after @${name2}`);
        i++;
        skipWs();
        attrs.push({ name: name2, value: readQuoted(), event: true });
        continue;
      }
      const name = readAttributeName();
      skipWs();
      if (src[i] === "=") {
        i++;
        skipWs();
        attrs.push({ name, value: readQuoted(), event: false });
      } else {
        attrs.push({ name, value: "", event: false, boolean: true });
      }
    }
    if (VOID_ELEMENTS.has(tag.toLowerCase())) {
      return { type: "element", tag, attrs, children: [] };
    }
    const children = parseNodeList("element");
    if (src[i] !== "<" || src[i + 1] !== "/")
      return fail(`Expected </${tag}>`);
    i += 2;
    skipWs();
    const close = readTagName();
    if (close !== tag)
      return fail(`Mismatched </${close}>, expected </${tag}>`);
    skipWs();
    if (src[i] !== ">")
      return fail(`Expected '>' to close </${tag}>`);
    i++;
    return { type: "element", tag, attrs, children };
  };
  const EACH_HEADER = /^\{#each\s+([\s\S]+?)\s+as\s+([A-Za-z_$][\w$]*)\s*(?:,\s*([A-Za-z_$][\w$]*)\s*)?\}$/;
  function parseEach() {
    const header = readInterpolation();
    const m = EACH_HEADER.exec(header);
    if (!m)
      return fail(`Invalid {#each …} header: ${header}`);
    const list = m[1].trim();
    const item = m[2];
    const index = m[3];
    const body = parseNodeList("each");
    let empty = [];
    if (src.startsWith("{:empty}", i)) {
      i += "{:empty}".length;
      empty = parseNodeList("each");
    }
    if (!src.startsWith("{/each}", i))
      return fail("Expected `{/each}` to close `{#each}`");
    i += "{/each}".length;
    return { type: "each", list, item, index, body, empty };
  }
  function parseIf() {
    const header = readInterpolation();
    const m = /^\{#if\s+([\s\S]+?)\s*\}$/.exec(header);
    if (!m)
      return fail(`Invalid {#if …} header: ${header}`);
    const branches = [
      { cond: m[1].trim(), body: parseNodeList("if") }
    ];
    for (;; ) {
      if (src.startsWith("{:else if", i)) {
        const h = readInterpolation();
        const mm = /^\{:else if\s+([\s\S]+?)\s*\}$/.exec(h);
        if (!mm)
          return fail(`Invalid {:else if …}: ${h}`);
        branches.push({ cond: mm[1].trim(), body: parseNodeList("if") });
        continue;
      }
      if (src.startsWith("{:else}", i)) {
        i += "{:else}".length;
        branches.push({ cond: null, body: parseNodeList("if") });
        continue;
      }
      break;
    }
    if (!src.startsWith("{/if}", i))
      return fail("Expected `{/if}` to close `{#if}`");
    i += "{/if}".length;
    return { type: "if", branches };
  }
  function parseNodeList(mode) {
    const nodes2 = [];
    let text = "";
    const flush = () => {
      if (text.length > 0) {
        nodes2.push({ type: "text", value: text });
        text = "";
      }
    };
    for (;; ) {
      if (i >= src.length) {
        return mode === "root" ? fail("Unexpected end of view (missing `}`)") : fail("Unclosed block");
      }
      const c = src[i];
      if (c === "<") {
        const next = src[i + 1];
        if (next === "/") {
          flush();
          break;
        }
        if (src.startsWith("<!--", i)) {
          const end = src.indexOf("-->", i + 4);
          i = end === -1 ? src.length : end + 3;
          continue;
        }
        if (next !== undefined && (isNameStart(next) || next === "!")) {
          flush();
          nodes2.push(parseTag());
          continue;
        }
        text += c;
        i++;
        continue;
      }
      if (c === "{") {
        if (src.startsWith("{#each", i)) {
          flush();
          nodes2.push(parseEach());
          continue;
        }
        if (src.startsWith("{#if", i)) {
          flush();
          nodes2.push(parseIf());
          continue;
        }
        if (mode === "each" && (src.startsWith("{:empty}", i) || src.startsWith("{/each}", i))) {
          flush();
          break;
        }
        if (mode === "if" && (src.startsWith("{:else", i) || src.startsWith("{/if}", i))) {
          flush();
          break;
        }
        text += readInterpolation();
        continue;
      }
      if (c === "}" && mode === "root") {
        flush();
        break;
      }
      text += c;
      i++;
    }
    return nodes2;
  }
  const nodes = parseNodeList("root");
  return { nodes, endPos: i };
}

// ../../packages/compiler/src/codegen.ts
function isComponentTag(tag) {
  return /^[A-Z][A-Za-z0-9_$]*$/.test(tag);
}
function attrEscape(value) {
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function templateEscape(html) {
  return html.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
}
function styleEscape(css) {
  return css.replace(/<\/style/gi, "<\\/style");
}
function attrValue(attrs, name) {
  return attrs.find((attr) => !attr.event && attr.name === name)?.value;
}
function renderAttr(attr) {
  if (attr.event)
    return ` ${eventAttribute(attr.name)}="${attrEscape(attr.value)}"`;
  switch (attr.name) {
    case "api":
    case "ssrGet":
    case "ssrText":
    case "csrGet":
    case "csrText":
      return "";
    default:
      return attr.boolean ? ` ${attr.name}` : ` ${attr.name}="${attrEscape(attr.value)}"`;
  }
}
function eventAttribute(name) {
  if (name.startsWith("window:")) {
    return `data-on-window-${name.slice("window:".length)}`;
  }
  if (name.startsWith("document:")) {
    return `data-on-document-${name.slice("document:".length)}`;
  }
  if (name.startsWith("browser-")) {
    return `data-on-wrnexus-browser-${name.slice(8)}`;
  }
  if (name.startsWith("mobile-")) {
    return `data-on-wrnexus-mobile-${name.slice(7)}`;
  }
  return `data-on-${name}`;
}
function reactiveAttrValue(raw, reactive) {
  let found = false;
  const value = raw.replace(/\{([^{}]+)\}/g, (whole, inner) => {
    const expr = inner.trim();
    if (!exprRefsState(expr, reactive.stateNames))
      return whole;
    found = true;
    try {
      const result = new Function("with(this){return (" + expr + ");}").call(reactive.scope);
      return result == null ? "" : String(result);
    } catch {
      return whole;
    }
  });
  return found ? value : null;
}
function renderAttrs(attrs, csrId, reactive = null) {
  let bindIndex = 0;
  const rendered = attrs.map((attr) => {
    const base = renderAttr(attr);
    if (!reactive || attr.event || attr.boolean || !base || !attr.value.includes("{"))
      return base;
    const initial = reactiveAttrValue(attr.value, reactive);
    if (initial === null)
      return base;
    const marker = JSON.stringify([attr.name, attr.value]);
    return ` ${attr.name}="${attrEscape(initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
  }).join("");
  return csrId ? `${rendered} data-wrnexus-csr="${attrEscape(csrId)}"` : rendered;
}
function substituteTMarkers(text) {
  return text.replace(/\{t:([^{}]+)\}/g, (_m, key) => `<span data-t="${attrEscape(key.trim())}"></span>`);
}
function htmlTextEscape(value) {
  return value.replace(/[&<>]/g, (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : "&gt;");
}
function evalStateSeeds(states) {
  const scope = {};
  for (const s of states) {
    try {
      scope[s.name] = new Function("with(this){return (" + s.expr + ");}").call(scope);
    } catch {
      scope[s.name] = undefined;
    }
  }
  return scope;
}
function substituteReactiveText(raw, reactive) {
  const text = substituteTMarkers(raw);
  if (!reactive || reactive.stateNames.size === 0)
    return text;
  return text.replace(/\{([^{}]+)\}/g, (whole, inner) => {
    const expr = inner.trim();
    if (expr.startsWith("t:") || !exprRefsState(expr, reactive.stateNames))
      return whole;
    let value;
    try {
      value = new Function("with(this){return (" + expr + ");}").call(reactive.scope);
    } catch {
      return whole;
    }
    const baked = htmlTextEscape(value == null ? "" : String(value));
    return `<span data-text="${attrEscape(expr)}">${baked}</span>`;
  });
}
function bakeLoopText(raw) {
  let out = "";
  let last = 0;
  let m;
  const re = /\{([^{}]+)\}/g;
  while (m = re.exec(raw)) {
    out += escLit(raw.slice(last, m.index));
    const expr = m[1].trim();
    if (expr.startsWith("t:")) {
      out += escLit(`<span data-t="${attrEscape(expr.slice(2).trim())}"></span>`);
    } else {
      out += "${__wrnexusEscapeHtml(" + expr + ")}";
    }
    last = m.index + m[0].length;
  }
  return out + escLit(raw.slice(last));
}
function bakeLoopAttr(raw) {
  if (!raw.includes("{"))
    return escLit(attrEscape(raw));
  let out = "";
  let last = 0;
  let m;
  const re = /\{([^{}]+)\}/g;
  while (m = re.exec(raw)) {
    out += escLit(attrEscape(raw.slice(last, m.index)));
    out += "${__wrnexusEscapeHtml(" + m[1].trim() + ")}";
    last = m.index + m[0].length;
  }
  return out + escLit(attrEscape(raw.slice(last)));
}
function renderLoopBody(node) {
  if (node.type === "text") {
    return bakeLoopText(node.value);
  }
  if (node.type === "each") {
    return compileEachExpr(node);
  }
  if (node.type === "if") {
    return compileIfExpr(node);
  }
  const componentTag = isComponentTag(node.tag);
  const attrs = node.attrs.filter((attr) => attr.name !== "data-component").map((attr) => {
    const name = attr.event ? eventAttribute(attr.name) : attr.name;
    if (attr.boolean) {
      return escLit(` ${name}`);
    }
    return escLit(` ${name}="`) + bakeLoopAttr(attr.value) + escLit(`"`);
  }).join("");
  const inner = node.children.map(renderLoopBody).join("");
  if (componentTag) {
    return escLit(`<div data-component="${attrEscape(node.tag)}"`) + attrs + escLit(">") + inner + escLit("</div>");
  }
  if (VOID_ELEMENTS.has(node.tag.toLowerCase())) {
    return escLit(`<${node.tag}`) + attrs + escLit(">");
  }
  return escLit(`<${node.tag}`) + attrs + escLit(">") + inner + escLit(`</${node.tag}>`);
}
function compileEachExpr(node) {
  const item = node.item;
  const index = node.index ?? "__wi";
  const body = node.body.map(renderLoopBody).join("");
  const empty = node.empty.map(renderLoopBody).join("");
  return "${(() => { const __wl = Array.isArray(" + node.list + ") ? (" + node.list + ") : []; return __wl.length ? __wl.map((" + item + ", " + index + ") => `" + body + '`).join("") : `' + empty + "`; })()}";
}
function compileIfExpr(node) {
  let expr = "``";
  for (let k = node.branches.length - 1;k >= 0; k--) {
    const b = node.branches[k];
    const bodySrc = "`" + b.body.map(renderLoopBody).join("") + "`";
    expr = b.cond === null ? bodySrc : "(" + b.cond + ") ? " + bodySrc + " : " + expr;
  }
  return "${" + expr + "}";
}
function collectControlExprs(nodes, out = []) {
  for (const node of nodes) {
    if (node.type === "each") {
      out.push(node.list);
      collectControlExprs(node.body, out);
      collectControlExprs(node.empty, out);
    } else if (node.type === "if") {
      for (const b of node.branches) {
        if (b.cond)
          out.push(b.cond);
        collectControlExprs(b.body, out);
      }
    } else if (node.type === "element") {
      collectControlExprs(node.children, out);
    }
  }
  return out;
}
function renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive = null) {
  if (node.type === "text")
    return substituteReactiveText(node.value, reactive);
  if (node.type === "each" || node.type === "if") {
    loops.push(node.type === "each" ? compileEachExpr(node) : compileIfExpr(node));
    return `\x00WRNEACH${loops.length - 1}\x00`;
  }
  if (isComponentTag(node.tag)) {
    return renderPageComponentInvocation(node, ssrBindings, csrBindings, apiBindings, loops, reactive);
  }
  const apiName = attrValue(node.attrs, "api");
  const apiBinding = apiName ? apiBindings.get(apiName) : undefined;
  if (apiName && !apiBinding) {
    throw new Error(`Unknown .wrn api binding "${apiName}"`);
  }
  const ssrGet = attrValue(node.attrs, "ssrGet");
  const ssrText = attrValue(node.attrs, "ssrText");
  const csrGet = attrValue(node.attrs, "csrGet");
  const csrText = attrValue(node.attrs, "csrText");
  const csrId = apiBinding?.mode === "client" ? csrMarker(csrBindings, renderBinding(apiBinding)) : csrGet && csrText ? csrMarker(csrBindings, {
    method: "GET",
    path: apiRoutePath(csrGet),
    body: expressionBody(csrText),
    helpers: ""
  }) : undefined;
  if (VOID_ELEMENTS.has(node.tag.toLowerCase())) {
    return `<${node.tag}${renderAttrs(node.attrs, csrId, reactive)}>`;
  }
  const inner = apiBinding?.mode === "ssr" ? ssrMarker(ssrBindings, renderBinding(apiBinding)) : ssrGet && ssrText ? ssrMarker(ssrBindings, {
    method: "GET",
    path: apiRoutePath(ssrGet),
    body: expressionBody(ssrText),
    helpers: ""
  }) : node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join("");
  return `<${node.tag}${renderAttrs(node.attrs, csrId, reactive)}>${inner}</${node.tag}>`;
}
function renderPageComponentInvocation(node, ssrBindings, csrBindings, apiBindings, loops, reactive) {
  const attrs = node.attrs.filter((attr) => attr.name !== "data-component");
  const inner = node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join("");
  return `<div data-component="${attrEscape(node.tag)}"${renderAttrs(attrs, undefined, reactive)}>${inner}</div>`;
}
function renderNestedComponentInvocation(node, ctx) {
  let bindIndex = 0;
  const attrs = node.attrs.filter((attr) => attr.name !== "data-component").map((attr) => {
    if (attr.event) {
      return escLit(` ${eventAttribute(attr.name)}="`) + escLit(attrEscape(attr.value)) + escLit(`"`);
    }
    if (attr.boolean) {
      return ` ${attr.name}`;
    }
    const rendered = ` ${attr.name}="` + `${compileAttrValue(attr.value, ctx)}"`;
    if (!attr.value.includes("{") || !exprRefsState(attr.value, ctx.stateNames)) {
      return rendered;
    }
    const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
    return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`;
  }).join("");
  const loops = loopVarsOf(node);
  const childCtx = loops.length > 0 ? {
    ...ctx,
    loopVars: new Set([...ctx.loopVars ?? [], ...loops])
  } : ctx;
  const inner = node.children.map((child) => renderComponentNode(child, childCtx)).join("");
  return `<div data-component="${attrEscape(node.tag)}"${attrs}>${inner}</div>`;
}
function ssrMarker(bindings, binding) {
  const marker = `<!--wrnexus-ssr:${bindings.length}-->`;
  bindings.push({ marker, ...binding });
  return marker;
}
function csrMarker(bindings, binding) {
  const id = String(bindings.length);
  bindings.push({ id, ...binding });
  return id;
}
function renderBinding(binding) {
  return {
    method: binding.method,
    path: binding.path,
    body: binding.body,
    helpers: binding.helpers
  };
}
function hasClientBehavior(nodes) {
  return nodes.some((node) => {
    if (node.type === "text")
      return /\{(?!t:)[^{}]+\}/.test(node.value);
    if (node.type === "each" || node.type === "if")
      return false;
    return node.attrs.some((attr) => attr.event || attr.name === "csrGet" || attr.name === "csrText") || hasClientBehavior(node.children);
  });
}
function apiRoutePath(path) {
  const trimmed = path.trim();
  if (!trimmed.startsWith("/")) {
    throw new Error(`.wrn API paths must start with "/": ${path}`);
  }
  if (trimmed.includes("\x00") || trimmed.includes("\\") || /(^|\/)\.\.(\/|$)/.test(trimmed)) {
    throw new Error(`Unsafe .wrn API path: ${path}`);
  }
  if (trimmed === "/api" || trimmed.startsWith("/api/"))
    return trimmed;
  return `/api${trimmed}`;
}
function expressionBody(expr) {
  return `return (${expr});`;
}
function dataBody(source) {
  const trimmed = source.trim();
  if (!trimmed)
    return "return undefined;";
  return /\breturn\b/.test(trimmed) ? trimmed : expressionBody(trimmed);
}
function modeHelpers(ast, mode, sharedHelpers) {
  return [
    sharedHelpers,
    ...ast.modeFunctions.filter((block) => block.mode === mode).map((block) => block.body.trim()).filter(Boolean)
  ].filter(Boolean).join(`

`);
}
function apiBindingMap(ast, sharedHelpers) {
  const bindings = new Map;
  for (const block of ast.dataApis) {
    if (bindings.has(block.name)) {
      throw new Error(`Duplicate .wrn api binding "${block.name}"`);
    }
    bindings.set(block.name, {
      mode: block.mode,
      method: block.method,
      path: apiRoutePath(block.path),
      body: dataBody(block.body),
      helpers: modeHelpers(ast, block.mode, sharedHelpers)
    });
  }
  return bindings;
}
function ssrRuntimeSource() {
  return `const __wrnexusHtmlEscapes = { "&": "&amp;", "<": "&lt;", ">": "&gt;", "\\"": "&quot;", "'": "&#39;" };
function __wrnexusEscapeHtml(value: unknown): string {
  return String(value).replace(/[&<>"']/g, (ch) => __wrnexusHtmlEscapes[ch] ?? ch);
}

function __wrnexusEvalData(data: unknown, body: string, helpers = "", ctx: any): unknown {
  const adapters = {
    cookies: ctx.cookies,
    session: ctx.session,
    localStorage: ctx.localStorage,
  };
  return new Function("$data", "$adapters", "const cookies = $adapters.cookies;\\nconst session = $adapters.session;\\nconst localStorage = $adapters.localStorage;\\nwith ($data ?? {}) {\\n" + helpers + "\\n" + body + "\\n}")(data, adapters);
}

async function __wrnexusCallApi(path: string, method: string, ctx: any): Promise<unknown> {
  if (typeof ctx.__wrnexusCallApi === "function") {
    return await ctx.__wrnexusCallApi(path, method);
  }

  const url = new URL(path, ctx.req.url);
  const res = await fetch(new Request(url, { method, headers: ctx.req.headers }));
  if (!res.ok) {
    throw new Error(".wrn data API request failed with status " + res.status);
  }

  const type = res.headers.get("content-type") || "";
  return type.includes("application/json") ? await res.json() : await res.text();
}

async function __wrnexusRenderSsrBindings(html: string, ctx: any): Promise<string> {
  for (const binding of __wrnexusSsrBindings) {
    const data = await __wrnexusCallApi(binding.path, binding.method, ctx);
    const value = __wrnexusEvalData(data, binding.body, binding.helpers, ctx);
    html = html.replace(binding.marker, __wrnexusEscapeHtml(value));
  }
  return html;
}`;
}
function generate(ast) {
  if (ast.kind === "component" || ast.kind === "layout") {
    return generateComponent(ast);
  }
  const out = [];
  const ssrBindings = [];
  const csrBindings = [];
  const helpers = ast.functions.map((body2) => body2.trim()).filter(Boolean).join(`

`);
  const apiBindings = apiBindingMap(ast, helpers);
  if (helpers) {
    out.push(`// --- .wrn functions ---
${helpers}`);
  }
  out.push(`export const meta = ${JSON.stringify({ title: ast.name, ...ast.seo }, null, 2)};`);
  if (ast.layout)
    out.push(`export const layout = ${JSON.stringify(ast.layout)};`);
  const reactive = ast.states.length > 0 ? { stateNames: new Set(ast.states.map((s) => s.name)), scope: evalStateSeeds(ast.states) } : null;
  const loops = [];
  let html = ast.view.map((node) => renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive)).join("");
  const styles = ast.styles.map((body2) => body2.trim()).filter(Boolean);
  const needsClientRuntime = ast.states.length > 0 || hasClientBehavior(ast.view);
  if (needsClientRuntime) {
    const scopePlaceholder = "__WRNEXUS_DYNAMIC_SCOPE__";
    html = `<div data-scope="${scopePlaceholder}">${html}</div>`;
  }
  if (styles.length > 0) {
    const css = styles.map(styleEscape).join(`
`);
    html = `<style data-wrnexus-style="${attrEscape(ast.name)}">
${css}
</style>${html}`;
  }
  if (csrBindings.length > 0) {
    out.push(`export const __wrnexusCsr = ${JSON.stringify(csrBindings, null, 2)};`);
  }
  let body = templateEscape(html);
  const dynamicStateScope = ast.states.map((state) => `${JSON.stringify(state.name)}: (() => { try { return (${state.expr}); } catch { return undefined; } })()`).join(", ");
  loops.forEach((code, idx) => {
    body = body.replace(`\x00WRNEACH${idx}\x00`, () => code);
  });
  const loopConsts = [];
  if (loops.length > 0) {
    const lists = collectControlExprs(ast.view);
    for (const [name, binding] of apiBindings) {
      if (binding.mode !== "ssr")
        continue;
      if (!lists.some((expr) => new RegExp(`\\b${name}\\b`).test(expr)))
        continue;
      loopConsts.push(`  const ${name} = __wrnexusEvalData(await __wrnexusCallApi(${JSON.stringify(binding.path)}, ${JSON.stringify(binding.method)}, ctx), ${JSON.stringify(binding.body)}, ${JSON.stringify(binding.helpers)}, ctx);`);
    }
  }
  const needsSsrRuntime = ssrBindings.length > 0 || loops.length > 0 || ast.states.some((state) => /\bctx\b/.test(state.expr));
  if (needsSsrRuntime) {
    out.push(ssrRuntimeSource());
    out.push(`const __wrnexusSsrBindings = ${JSON.stringify(ssrBindings, null, 2)};`);
    const decls = loopConsts.length > 0 ? loopConsts.join(`
`) + `
` : "";
    out.push(`export default async function ${ast.name}(ctx: any) {
      ${decls}
        const __state = { ${dynamicStateScope} };

        const __scopeValue = Object.entries(__state)
          .map(([key, value]) => {
            const encoded =
              typeof value === "number" || typeof value === "boolean"
                ? String(value)
                : JSON.stringify(value == null ? "" : String(value));

            return key + ": " + encoded;
          })
          .join(", ")
          .replace(/&/g, "&amp;")
          .replace(/"/g, "&quot;")
          .replace(/</g, "&lt;")
          .replace(/>/g, "&gt;");

        const html = \`${body}\`.replace(
          "__WRNEXUS_DYNAMIC_SCOPE__",
          __scopeValue,
        );

        return await __wrnexusRenderSsrBindings(html, ctx);
      }`);
  } else {
    out.push(`export default function ${ast.name}(ctx: any) {
        const __state = { ${dynamicStateScope} };

        const __scopeValue = Object.entries(__state)
          .map(([key, value]) => {
            const encoded =
              typeof value === "number" || typeof value === "boolean"
                ? String(value)
                : JSON.stringify(value == null ? "" : String(value));

            return key + ": " + encoded;
          })
          .join(", ")
          .replace(/&/g, "&amp;")
          .replace(/"/g, "&quot;")
          .replace(/</g, "&lt;")
          .replace(/>/g, "&gt;");

        return \`${body}\`.replace(
          "__WRNEXUS_DYNAMIC_SCOPE__",
          __scopeValue,
        );
      }`);
  }
  if (ast.apis.length > 0) {
    ast.apis.forEach((api, index) => {
      const name = `__wrnexusApi_${api.method}_${index}`;
      out.push(`// ${api.method} ${apiRoutePath(api.path)}
const ${name} = async (ctx: any) => {${api.body}};`);
    });
    const entries = ast.apis.map((api, index) => `  ${JSON.stringify(`${api.method} ${apiRoutePath(api.path)}`)}: __wrnexusApi_${api.method}_${index},`);
    out.push(`export const __wrnexusApi = {
${entries.join(`
`)}
};`);
    const exported = new Set;
    ast.apis.forEach((api, index) => {
      if (exported.has(api.method))
        return;
      exported.add(api.method);
      out.push(`export const ${api.method} = __wrnexusApi_${api.method}_${index};`);
    });
  }
  if (ast.realtimes.length > 0) {
    const handlers = ast.realtimes.flatMap((rt) => rt.handlers.map((h) => {
      const params = ["ws", ...h.args].join(", ");
      return `  ${h.event}(${params}: any) {${h.body}},`;
    }));
    out.push(`export const websocket = {
${handlers.join(`
`)}
};`);
  }
  return out.join(`

`) + `
`;
}
function parseForExpr(value) {
  const m = /^\s*([A-Za-z_$][\w$]*)\s*(?:,\s*([A-Za-z_$][\w$]*)\s*)?\s+in\s+([\s\S]+?)\s*$/.exec(value);
  if (!m)
    return null;
  return { item: m[1], index: m[2], list: m[3] };
}
function loopVarsOf(node) {
  if (node.type !== "element")
    return [];
  const attr = node.attrs.find((a) => !a.event && a.name === "data-for");
  if (!attr)
    return [];
  const parsed = parseForExpr(attr.value);
  return parsed ? [parsed.item, ...parsed.index ? [parsed.index] : []] : [];
}
var JS_RESERVED = new Set([
  "class",
  "for",
  "default",
  "function",
  "return",
  "if",
  "else",
  "new",
  "delete",
  "typeof",
  "in",
  "instanceof",
  "void",
  "do",
  "while",
  "switch",
  "case",
  "break",
  "continue",
  "this",
  "super",
  "import",
  "export",
  "extends",
  "var",
  "let",
  "const",
  "null",
  "true",
  "false",
  "try",
  "catch",
  "finally",
  "throw",
  "yield",
  "await",
  "enum",
  "with",
  "debugger"
]);
function safeRef(name) {
  return JS_RESERVED.has(name) ? `__p_${name}` : name;
}
function escLit(s) {
  return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
}
function componentBehavior(ast) {
  const functions = ast.functions.map((body) => body.trim()).filter(Boolean).join(`

`);
  const lifecycle = {
    ...ast.lifecycle.mount?.trim() ? { mount: ast.lifecycle.mount.trim() } : {},
    ...ast.lifecycle.update?.trim() ? { update: ast.lifecycle.update.trim() } : {},
    ...ast.lifecycle.unmount?.trim() ? { unmount: ast.lifecycle.unmount.trim() } : {}
  };
  const watches = ast.watches.map((watch) => ({
    state: watch.state,
    body: watch.body.trim()
  }));
  if (!functions && Object.keys(lifecycle).length === 0 && watches.length === 0) {
    return null;
  }
  return {
    functions,
    lifecycle,
    watches
  };
}
function behaviorAttribute(behavior) {
  if (!behavior) {
    return "";
  }
  return ` data-wrn-behavior="${attrEscape(JSON.stringify(behavior))}"`;
}
var INTERP_RE = /\{([^{}]+)\}/g;
function exprRefsState(expr, stateNames) {
  for (const name of stateNames) {
    if (new RegExp(`\\b${name}\\b`).test(expr))
      return true;
  }
  return false;
}
function viewHasEvents(nodes) {
  return nodes.some((n) => n.type === "element" && (n.attrs.some((a) => a.event) || viewHasEvents(n.children)));
}
function compileText(raw, ctx) {
  let out = "";
  let last = 0;
  let m;
  INTERP_RE.lastIndex = 0;
  while (m = INTERP_RE.exec(raw)) {
    out += escLit(raw.slice(last, m.index));
    const expr = m[1].trim();
    if (expr.startsWith("t:")) {
      out += escLit(`<span data-t="${attrEscape(expr.slice(2).trim())}"></span>`);
    } else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
      out += escLit(`{${expr}}`);
    } else if (exprRefsState(expr, ctx.stateNames)) {
      out += escLit(`<span data-text="${attrEscape(expr)}">`) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(`</span>`);
    } else if (expr === "content") {
      out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
    } else {
      out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`;
    }
    last = m.index + m[0].length;
  }
  return out + escLit(raw.slice(last));
}
function compileAttrValue(raw, ctx) {
  if (!raw.includes("{"))
    return escLit(attrEscape(raw));
  let out = "";
  let last = 0;
  let m;
  INTERP_RE.lastIndex = 0;
  while (m = INTERP_RE.exec(raw)) {
    out += escLit(attrEscape(raw.slice(last, m.index)));
    const expr = m[1].trim();
    if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
      out += escLit(`{${expr}}`);
    } else {
      out += `\${__wireAttr(${ctx.resolveExpr(expr)})}`;
    }
    last = m.index + m[0].length;
  }
  return out + escLit(attrEscape(raw.slice(last)));
}
function renderComponentNode(node, ctx) {
  if (node.type === "text")
    return compileText(node.value, ctx);
  if (node.type === "each" || node.type === "if") {
    throw new Error("Server `{#each}` / `{#if}` blocks are supported in pages, not components. Move them into a page (or use data-for / data-show on the client).");
  }
  if (isComponentTag(node.tag)) {
    return renderNestedComponentInvocation(node, ctx);
  }
  let bindIndex = 0;
  const staticClasses = [];
  const conditionalClasses = [];
  for (const attr of node.attrs) {
    if (!attr.event && attr.name === "class") {
      staticClasses.push(attr.value);
    }
    if (!attr.event && attr.name.startsWith("class:")) {
      conditionalClasses.push({
        className: attr.name.slice("class:".length),
        expression: attr.value
      });
    }
  }
  const attrs = node.attrs.filter((a) => a.name !== "class" && !a.name.startsWith("class:")).map((a) => {
    if (a.event) {
      return ` ${eventAttribute(a.name)}="${escLit(attrEscape(a.value))}"`;
    }
    if (a.boolean) {
      return ` ${a.name}`;
    }
    const rendered = ` ${a.name}="${compileAttrValue(a.value, ctx)}"`;
    if (!a.value.includes("{") || !exprRefsState(a.value, ctx.stateNames)) {
      return rendered;
    }
    const marker = attrEscape(JSON.stringify([a.name, a.value]));
    return `${rendered} data-wrn-bind-${bindIndex++}="${escLit(marker)}"`;
  }).join("");
  const initialConditionalClasses = conditionalClasses.map(({ className, expression }) => {
    return `\${(${ctx.resolveExpr(expression)}) ? ${JSON.stringify(` ${className}`)} : ""}`;
  }).join("");
  const classAttribute = staticClasses.length > 0 || conditionalClasses.length > 0 ? ` class="${compileAttrValue(staticClasses.join(" "), ctx)}${initialConditionalClasses}"` : "";
  const classBindings = conditionalClasses.map(({ className, expression }, index) => {
    const marker = attrEscape(JSON.stringify([className, expression]));
    return ` data-wrn-class-${index}="${escLit(marker)}"`;
  }).join("");
  const loops = loopVarsOf(node);
  const childCtx = loops.length > 0 ? { ...ctx, loopVars: new Set([...ctx.loopVars ?? [], ...loops]) } : ctx;
  const allAttrs = `${classAttribute}${classBindings}${attrs}`;
  if (VOID_ELEMENTS.has(node.tag.toLowerCase())) {
    return `<${node.tag}${allAttrs}>`;
  }
  const inner = node.children.map((child) => renderComponentNode(child, childCtx)).join("");
  return `<${node.tag}${allAttrs}>${inner}</${node.tag}>`;
}
function generateComponent(ast) {
  const out = [];
  const effectiveProps = ast.kind === "layout" && !ast.props.some((prop) => prop.name === "content") ? [
    {
      name: "content",
      default: '""'
    },
    ...ast.props
  ] : ast.props;
  const stateNames = new Set(ast.states.map((s) => s.name));
  const nameRefs = new Map;
  for (const p of effectiveProps) {
    nameRefs.set(p.name, safeRef(p.name));
  }
  for (const s of ast.states)
    nameRefs.set(s.name, safeRef(s.name));
  const resolveExpr = (expr) => {
    let result = expr;
    for (const [name, ref] of nameRefs) {
      if (name !== ref)
        result = result.replace(new RegExp(`\\b${name}\\b`, "g"), ref);
    }
    return result;
  };
  const ctx = { stateNames, resolveExpr };
  const viewCode = ast.view.map((node) => renderComponentNode(node, ctx)).join("");
  const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
  const styleTag = styles.length > 0 ? escLit(`<style data-wrnexus-style="${attrEscape(ast.name)}">
${styles.map(styleEscape).join(`
`)}
</style>`) : "";
  const behavior = componentBehavior(ast);
  const needsScope = ast.states.length > 0 || viewHasEvents(ast.view) || behavior !== null;
  const scopeKeys = [
    ...effectiveProps.map((prop) => prop.name),
    ...ast.states.map((state) => state.name)
  ];
  const behaviorAttr = behaviorAttribute(behavior);
  const decls = [];
  for (const prop of effectiveProps) {
    decls.push(`  const ${nameRefs.get(prop.name)} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}));`);
  }
  for (const state of ast.states) {
    decls.push(`  const ${nameRefs.get(state.name)} = (${resolveExpr(state.expr)});`);
  }
  const returnExpr = needsScope ? "`" + styleTag + `<div data-scope="\${__scope}"${behaviorAttr}>` + viewCode + "</div>`" : "`" + styleTag + viewCode + "`";
  const scopeLine = needsScope && scopeKeys.length > 0 ? `  const __scope = __wrnexusScopeDecl({ ${scopeKeys.map((k) => `${JSON.stringify(k)}: ${nameRefs.get(k)}`).join(", ")} });
` : needsScope ? `  const __scope = "";
` : "";
  if (ast.kind === "layout") {
    out.push(`export const __wrnexusLayout = ${JSON.stringify(ast.name)};`);
  } else {
    out.push(`export const __wrnexusComponent = ${JSON.stringify(ast.name)};`);
  }
  if (behavior) {
    out.push(`export const __wrnexusBehavior = ${JSON.stringify(behavior, null, 2)};`);
  }
  out.push(`function __coerce(v: any, def: any): any {
  if (v === undefined || v === null) return def;
  if (typeof def === "number") return Number(v);
  if (typeof def === "boolean") return v === true || v === "" || v === "true";
  return String(v);
}
function __wireHtml(v: any): string {
  return String(v == null ? "" : v).replace(/[&<>]/g, (c) => (c === "&" ? "&amp;" : c === "<" ? "&lt;" : "&gt;"));
}
function __wireAttr(v: any): string {
  return String(v == null ? "" : v).replace(/[&<>"]/g, (c) =>
    c === "&" ? "&amp;" : c === "<" ? "&lt;" : c === ">" ? "&gt;" : "&quot;",
  );
}`);
  if (needsScope) {
    out.push(`function __wrnexusScopeDecl(obj: Record<string, any>): string {
  const lit = (v: any) =>
    typeof v === "number" || typeof v === "boolean"
      ? String(v)
      : "'" + String(v).replace(/\\\\/g, "\\\\\\\\").replace(/'/g, "\\\\'").replace(/\\n/g, "\\\\n") + "'";
  return Object.keys(obj)
    .map((k) => k + ": " + lit(obj[k]))
    .join(", ")
    .replace(/&/g, "&amp;")
    .replace(/"/g, "&quot;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");
}`);
  }
  out.push(`export function render(props: Record<string, any> = {}): string {
` + `  const __p = props || {};
` + (decls.length > 0 ? decls.join(`
`) + `
` : "") + scopeLine + `  return ${returnExpr};
` + `}`);
  return out.join(`

`) + `
`;
}

// ../../packages/compiler/src/native-codegen.ts
class NativeCompileError extends Error {
  constructor(message) {
    super(message);
    this.name = "NativeCompileError";
  }
}
var tagMap = {
  div: "View",
  main: "View",
  section: "View",
  article: "View",
  nav: "View",
  header: "View",
  footer: "View",
  aside: "View",
  form: "View",
  ul: "View",
  ol: "View",
  li: "View",
  p: "Text",
  span: "Text",
  strong: "Text",
  em: "Text",
  small: "Text",
  label: "Text",
  h1: "Text",
  h2: "Text",
  h3: "Text",
  h4: "Text",
  h5: "Text",
  h6: "Text",
  button: "Pressable",
  a: "Pressable",
  input: "TextInput",
  textarea: "TextInput",
  img: "Image",
  view: "View",
  text: "Text",
  pressable: "Pressable",
  textinput: "TextInput",
  image: "Image",
  scrollview: "ScrollView",
  safeareaview: "SafeAreaView",
  flatlist: "FlatList",
  activityindicator: "ActivityIndicator"
};
var attrMap = {
  class: "style",
  className: "style",
  src: "source",
  alt: "accessibilityLabel",
  placeholder: "placeholder",
  disabled: "disabled",
  value: "value",
  href: "__href",
  "aria-label": "accessibilityLabel"
};
function expression(value) {
  const exact = /^\{([\s\S]+)\}$/.exec(value.trim());
  return exact?.[1]?.trim() ?? null;
}
function textJsx(value) {
  const pieces = [];
  let last = 0;
  for (const match of value.matchAll(/\{([^{}]+)\}/g)) {
    if (match.index > last)
      pieces.push(value.slice(last, match.index));
    const expr = match[1].trim();
    pieces.push(expr.startsWith("t:") ? `{${JSON.stringify(expr.slice(2).trim())}}` : `{${expr}}`);
    last = match.index + match[0].length;
  }
  pieces.push(value.slice(last));
  return pieces.join("").replace(/([<>])/g, (char) => char === "<" ? "&lt;" : "&gt;");
}
function eventBody(value, states) {
  let body = expression(value) ?? value;
  for (const state of states) {
    const cap = state[0].toUpperCase() + state.slice(1);
    body = body.replace(new RegExp(`\\b${state}\\+\\+`, "g"), `set${cap}(value => value + 1)`).replace(new RegExp(`\\b${state}--`, "g"), `set${cap}(value => value - 1)`).replace(new RegExp(`\\b${state}\\s*=\\s*([^;]+)`, "g"), `set${cap}($1)`);
  }
  return `() => { ${body} }`;
}
function renderAttrs2(attrs, states) {
  return attrs.map((attr) => {
    if (attr.event) {
      if (attr.name.startsWith("browser-"))
        return "";
      const eventName = attr.name.startsWith("mobile-") ? attr.name.slice(7) : attr.name;
      const event = eventName === "click" || eventName === "press" ? "onPress" : eventName === "input" || eventName === "change" ? "onChangeText" : `on${eventName[0].toUpperCase()}${eventName.slice(1)}`;
      return ` ${event}={${eventBody(attr.value, states)}}`;
    }
    if (attr.name === "data-native-browser" || attr.name.startsWith("data-native-on-browser-"))
      return "";
    if (attr.name === "data-native-options" || attr.name === "data-native-only" || attr.name === "data-native-requires" || attr.name === "data-native-unsupported")
      return "";
    if (attr.name === "data-native-mobile") {
      throw new NativeCompileError(`Declarative native capability "${attr.value}" currently targets browser/Capacitor pages. In Expo output, call the installed Expo package from an @mobile-event handler.`);
    }
    const name = attrMap[attr.name] ?? attr.name;
    if (name === "__href")
      return ` onPress={() => router.push(${JSON.stringify(attr.value)})}`;
    if (name === "source") {
      const expr2 = expression(attr.value);
      return ` source={${expr2 ? `{ uri: ${expr2} }` : `{ uri: ${JSON.stringify(attr.value)} }`}}`;
    }
    if (name === "style" && attr.name !== "style") {
      return ` style={[${attr.value.split(/\s+/).filter(Boolean).map((value) => `styles[${JSON.stringify(value)}]`).join(", ")} ]}`;
    }
    if (name === "style") {
      const inlineExpression = expression(attr.value);
      if (inlineExpression)
        return ` style={${inlineExpression}}`;
      throw new NativeCompileError('Inline CSS strings are not portable to native; use class="name" and a page style block');
    }
    if (attr.boolean)
      return ` ${name}`;
    const expr = expression(attr.value);
    return expr ? ` ${name}={${expr}}` : ` ${name}=${JSON.stringify(attr.value)}`;
  }).join("");
}
function renderNode2(node, states, key) {
  if (node.type === "text")
    return textJsx(node.value);
  if (node.type === "each") {
    const params = node.index ? `${node.item}, ${node.index}` : `${node.item}, __index`;
    const body = node.body.map((child, index) => renderNode2(child, states, index === 0 ? node.index ?? "__index" : undefined)).join("");
    const empty = node.empty.map((child) => renderNode2(child, states)).join("");
    return `{(${node.list})?.length ? (${node.list}).map((${params}) => <>${body}</>) : <>${empty}</>}`;
  }
  if (node.type === "if") {
    const result = node.branches.reduceRight((fallback, branch) => branch.cond === null ? `<>${branch.body.map((child) => renderNode2(child, states)).join("")}</>` : `(${branch.cond}) ? <>${branch.body.map((child) => renderNode2(child, states)).join("")}</> : ${fallback}`, "null");
    return `{${result}}`;
  }
  const nativeOnly = node.attrs.find((attr) => !attr.event && attr.name === "data-native-only")?.value;
  if (nativeOnly === "browser" || nativeOnly === "web")
    return "";
  const nativeTag = tagMap[node.tag.toLowerCase()] ?? (/^[A-Z]/.test(node.tag) ? node.tag : undefined);
  if (!nativeTag)
    throw new NativeCompileError(`HTML element <${node.tag}> has no native equivalent`);
  const attrs = renderAttrs2(node.attrs, states) + (key ? ` key={${key}}` : "");
  if (nativeTag === "TextInput" || nativeTag === "Image" || nativeTag === "ActivityIndicator")
    return `<${nativeTag}${attrs} />`;
  const children = node.children.map((child) => {
    if (child.type !== "text")
      return renderNode2(child, states);
    if (!child.value.trim())
      return "";
    const text = textJsx(child.value);
    return nativeTag === "Text" ? text : `<Text>${text}</Text>`;
  }).join("");
  return `<${nativeTag}${attrs}>${children}</${nativeTag}>`;
}
function nativeStyles(blocks) {
  const entries = [];
  for (const block of blocks) {
    for (const match of block.matchAll(/\.([A-Za-z_][\w-]*)\s*\{([^}]*)\}/g)) {
      const props = [];
      for (const declaration of match[2].split(";")) {
        const colon = declaration.indexOf(":");
        if (colon < 0)
          continue;
        const name = declaration.slice(0, colon).trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
        let value = declaration.slice(colon + 1).trim();
        if (/^-?\d+(?:\.\d+)?px$/.test(value))
          value = Number(value.slice(0, -2));
        props.push(`${JSON.stringify(name)}: ${typeof value === "number" ? value : JSON.stringify(value)}`);
      }
      entries.push(`${JSON.stringify(match[1])}: { ${props.join(", ")} }`);
    }
  }
  return `const styles = StyleSheet.create({ ${entries.join(`,
`)} });`;
}
function generateNative(ast) {
  if (ast.kind !== "page")
    throw new NativeCompileError("Native route compilation currently accepts page files only");
  if (ast.dataApis.length)
    throw new NativeCompileError("Data API blocks are not yet portable to native screens; fetch through the generated native backend helper");
  const states = new Set(ast.states.map((state) => state.name));
  const hooks = ast.states.map((state) => {
    const cap = state.name[0].toUpperCase() + state.name.slice(1);
    return `  const [${state.name}, set${cap}] = useState(${state.expr});`;
  }).join(`
`);
  const body = ast.view.map((node) => renderNode2(node, states)).join("");
  return `// generated from .wrn for Expo/React Native
import React, { useState } from "react";
import { ActivityIndicator, FlatList, Image, Pressable, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View } from "react-native";
import { useRouter } from "expo-router";

export default function ${ast.name}() {
  const router = useRouter();
${hooks}
  return <>${body}</>;
}

${nativeStyles(ast.styles)}
`;
}

// ../../packages/compiler/src/index.ts
function compileNativeWireFile(source) {
  return generateNative(parse(source));
}
function compileWireFile(source) {
  const ast = parse(source);
  return `// compiled from .wrn
${generate(ast)}`;
}
function compile(source) {
  const diagnostics = [];
  try {
    const ast = parse(source);
    return { code: `// compiled from .wrn
${generate(ast)}`, ast, diagnostics };
  } catch (err) {
    if (err instanceof ParseError)
      diagnostics.push(err.message);
    throw err;
  }
}
