ladrillosjs 2.0.0-rc.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +171 -16
  2. package/dist/core/cache/expressionCache.d.ts +5 -70
  3. package/dist/core/component/loader.d.ts +1 -1
  4. package/dist/core/configure.d.ts +24 -0
  5. package/dist/core/diff/listDiff.d.ts +16 -0
  6. package/dist/core/html/controlTagEscape.d.ts +47 -0
  7. package/dist/core/js/moduleExecutor.d.ts +19 -0
  8. package/dist/core/js/scriptParser.d.ts +35 -1
  9. package/dist/core.d.ts +2 -2
  10. package/dist/core.dev.js +12 -0
  11. package/dist/core.dev.js.map +1 -0
  12. package/dist/core.js +1 -1
  13. package/dist/core.js.map +1 -1
  14. package/dist/events.dev.js +2 -0
  15. package/dist/events.js +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.dev.js +22 -0
  18. package/dist/index.dev.js.map +1 -0
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/lazy.dev.js +2 -0
  22. package/dist/lazy.js +1 -1
  23. package/dist/shared-CMbR-Hhy.js +3 -0
  24. package/dist/shared-CMbR-Hhy.js.map +1 -0
  25. package/dist/shared-DqWGO1vN.js +2 -0
  26. package/dist/{shared-D-P0qKQY.js.map → shared-DqWGO1vN.js.map} +1 -1
  27. package/dist/shared-R1SSiaIW.dev.js +6785 -0
  28. package/dist/shared-R1SSiaIW.dev.js.map +1 -0
  29. package/dist/shared-Sk_U4mcq.dev.js +161 -0
  30. package/dist/shared-Sk_U4mcq.dev.js.map +1 -0
  31. package/dist/types/index.d.ts +6 -0
  32. package/dist/utils/devWarnings.d.ts +24 -3
  33. package/dist/utils/directives.d.ts +10 -0
  34. package/dist/utils/jsevents.d.ts +5 -0
  35. package/dist/utils/sandbox.d.ts +11 -0
  36. package/dist/utils/stateTransform.d.ts +58 -0
  37. package/package.json +22 -8
  38. package/dist/core/reactivity/dependencyTracker.d.ts +0 -120
  39. package/dist/shared-18P4lj9w.js +0 -2
  40. package/dist/shared-18P4lj9w.js.map +0 -1
  41. package/dist/shared-D-P0qKQY.js +0 -2
  42. package/dist/shared-mjNRZBte.js +0 -3
  43. package/dist/shared-mjNRZBte.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-R1SSiaIW.dev.js","names":[],"sources":["../src/utils/regex.ts","../src/core/helpers/frameworkHelpers.ts","../src/core/cache/expressionCache.ts","../src/core/js/reactivity.ts","../src/utils/stateTransform.ts","../src/utils/devWarnings.ts","../src/core/js/moduleExecutor.ts","../src/core/html/controlTagEscape.ts","../src/core/component/extract.ts","../src/core/component/cache.ts","../src/core/component/loader.ts","../src/core/css/cssParser/cssParser.ts","../src/core/component/bindingParser.ts","../src/core/lazy/lazyStrategies.ts","../src/core/builtins/lazyElement.ts","../src/core/html/htmlparser.ts","../src/utils/jsevents.ts","../src/utils/directives.ts","../src/utils/sandbox.ts","../src/utils/keyModifiers.ts","../src/core/js/scriptParser.ts","../src/core/configure.ts","../src/core/diff/listDiff.ts","../src/core/directives/directiveProcessor.ts","../src/core/scheduler/batchScheduler.ts","../src/core/component/webcomponent.ts","../src/core/lazy/lazyLoader.ts","../src/core/ladrillos.ts"],"sourcesContent":["type RegexPatterns = {\r\n bindings: RegExp;\r\n};\r\n\r\nexport const REGEX_PATTERNS: RegexPatterns = {\r\n bindings: /{([^}]+)}/g,\r\n};\r\n","/**\r\n * LadrillosJS Framework Helpers\r\n *\r\n * These are $ prefixed helper functions injected into component scripts.\r\n *\r\n * Available helpers:\r\n * - registerComponent(name, path, useShadowDOM?) - Register a child component\r\n * - registerComponents(configs) - Register multiple components at once (parallel)\r\n * - $use(path) - Shorthand for registerComponent with auto-derived tag name\r\n * - createRefsProxy(map) - Wrap a Map in a Proxy for cleaner dot notation access\r\n */\r\n\r\nimport {\r\n ladrillos,\r\n ComponentConfig,\r\n RegisterComponentsResult,\r\n} from \"../ladrillos\";\r\nimport type { LazyStrategy } from \"../lazy\";\r\n\r\n/**\r\n * Wraps a Map in a Proxy to allow cleaner dot notation access.\r\n * Supports both $refs.inputEl and $refs.get(\"inputEl\") syntax.\r\n *\r\n * @example\r\n * const $refs = createRefsProxy(new Map());\r\n * $refs.set(\"input\", document.querySelector(\"input\"));\r\n * $refs.input.focus(); // Works!\r\n * $refs.get(\"input\").focus(); // Also works!\r\n */\r\nexport function createRefsProxy<T extends HTMLElement = HTMLElement>(\r\n map: Map<string, T>,\r\n): Map<string, T> & Record<string, T> {\r\n return new Proxy(map, {\r\n get(target, prop, receiver) {\r\n // If the property exists on Map (get, set, has, etc.), use it\r\n if (prop in target) {\r\n const value = Reflect.get(target, prop, receiver);\r\n // Bind methods to the target Map\r\n return typeof value === \"function\" ? value.bind(target) : value;\r\n }\r\n // Otherwise, treat it as a ref name lookup\r\n if (typeof prop === \"string\") {\r\n return target.get(prop);\r\n }\r\n return undefined;\r\n },\r\n set(target, prop, value) {\r\n // Allow setting refs via dot notation: $refs.myEl = element\r\n if (typeof prop === \"string\") {\r\n target.set(prop, value);\r\n return true;\r\n }\r\n return false;\r\n },\r\n has(target, prop) {\r\n if (typeof prop === \"string\") {\r\n return target.has(prop) || prop in target;\r\n }\r\n return prop in target;\r\n },\r\n }) as Map<string, T> & Record<string, T>;\r\n}\r\n\r\n/**\r\n * Resolves a relative path against a base URL.\r\n * Used to resolve \"./buttons.html\" relative to the parent component's URL.\r\n */\r\nfunction resolvePath(path: string, baseUrl: string): string {\r\n // If path is already absolute, return as-is\r\n if (\r\n path.startsWith(\"http://\") ||\r\n path.startsWith(\"https://\") ||\r\n path.startsWith(\"/\")\r\n ) {\r\n return path.startsWith(\"/\")\r\n ? new URL(path, window.location.origin).href\r\n : path;\r\n }\r\n\r\n // Resolve relative path against base URL\r\n return new URL(path, baseUrl).href;\r\n}\r\n\r\n/**\r\n * Converts a filename to a kebab-case tag name.\r\n * \"./HeaderButtons.html\" → \"header-buttons\"\r\n */\r\nfunction filenameToTagName(path: string): string {\r\n const filename =\r\n path\r\n .split(\"/\")\r\n .pop()\r\n ?.replace(/\\.[^.]+$/, \"\") || path;\r\n\r\n return filename\r\n .replace(/([a-z])([A-Z])/g, \"$1-$2\")\r\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1-$2\")\r\n .toLowerCase();\r\n}\r\n\r\n/**\r\n * Creates framework helpers bound to a specific component's base URL.\r\n * This ensures relative paths like \"./buttons.html\" resolve correctly\r\n * relative to the component that calls registerComponent.\r\n *\r\n * @param componentUrl - The absolute URL of the component (e.g., \"http://localhost/header/header.html\")\r\n * @returns Object containing bound helper functions\r\n */\r\nexport function createFrameworkHelpers(componentUrl: string) {\r\n /**\r\n * Registers a child component from within a component's script.\r\n * Paths are resolved relative to the calling component's location.\r\n *\r\n * @example\r\n * ```html\r\n * <!-- In /header/header.html -->\r\n * <script>\r\n * registerComponent(\"header-buttons\", \"./buttons.html\");\r\n * // Resolves to /header/buttons.html\r\n * </script>\r\n * ```\r\n */\r\n function registerComponent(\r\n name: string,\r\n path: string,\r\n useShadowDOM: boolean = true,\r\n lazy: boolean | LazyStrategy = false,\r\n ): Promise<void> {\r\n const resolvedPath = resolvePath(path, componentUrl);\r\n return ladrillos.registerComponent(name, resolvedPath, useShadowDOM, lazy);\r\n }\r\n\r\n /**\r\n * Register multiple components at once with parallel fetching.\r\n *\r\n * Benefits:\r\n * - Parallel network requests (faster than sequential registerComponent calls)\r\n * - Shared fetch cache\r\n * - Detailed error reporting\r\n *\r\n * @example\r\n * ```html\r\n * <script>\r\n * // Array syntax\r\n * await registerComponents([\r\n * { name: 'nav-item', path: './nav-item.html' },\r\n * { name: 'nav-dropdown', path: './nav-dropdown.html', useShadowDOM: false }\r\n * ]);\r\n *\r\n * // Object syntax\r\n * await registerComponents({\r\n * 'nav-item': './nav-item.html',\r\n * 'nav-dropdown': { path: './nav-dropdown.html', useShadowDOM: false }\r\n * });\r\n * </script>\r\n * ```\r\n */\r\n function registerComponents(\r\n configs:\r\n | ComponentConfig[]\r\n | Record<string, string | Omit<ComponentConfig, \"name\">>,\r\n ): Promise<RegisterComponentsResult> {\r\n // Normalize and resolve paths relative to component\r\n const normalizedConfigs: ComponentConfig[] = Array.isArray(configs)\r\n ? configs.map((config) => ({\r\n ...config,\r\n path: resolvePath(config.path, componentUrl),\r\n }))\r\n : Object.entries(configs).map(([name, value]) =>\r\n typeof value === \"string\"\r\n ? { name, path: resolvePath(value, componentUrl) }\r\n : { name, ...value, path: resolvePath(value.path, componentUrl) },\r\n );\r\n\r\n return ladrillos.registerComponents(normalizedConfigs);\r\n }\r\n\r\n /**\r\n * Shorthand for registering a component with auto-derived tag name.\r\n * \"./HeaderButtons.html\" → registers as <header-buttons>\r\n */\r\n function $use(\r\n path: string,\r\n useShadowDOM: boolean = true,\r\n lazy: boolean | LazyStrategy = false,\r\n ): Promise<void> {\r\n const tagName = filenameToTagName(path);\r\n const resolvedPath = resolvePath(path, componentUrl);\r\n return ladrillos.registerComponent(tagName, resolvedPath, useShadowDOM, lazy);\r\n }\r\n\r\n return { registerComponent, registerComponents, $use };\r\n}\r\n\r\n/**\r\n * Names of all framework helpers (for Function parameter lists)\r\n */\r\nexport const frameworkHelperNames = [\r\n \"registerComponent\",\r\n \"registerComponents\",\r\n \"$use\",\r\n];\r\n\r\n/**\r\n * Default helpers for entry point usage (resolve relative to page URL).\r\n * Inside components, use createFrameworkHelpers(componentUrl) instead.\r\n */\r\nexport function getFrameworkHelperValues(): ((...args: any[]) => any)[] {\r\n const helpers = createFrameworkHelpers(window.location.href);\r\n return [helpers.registerComponent, helpers.registerComponents, helpers.$use];\r\n}\r\n\r\n// For entry point / CDN usage - resolve relative to current page\r\nconst defaultHelpers = createFrameworkHelpers(window.location.href);\r\nexport const registerComponent = defaultHelpers.registerComponent;\r\nexport const registerComponents = defaultHelpers.registerComponents;\r\nexport const $use = defaultHelpers.$use;\r\n","/**\r\n * Variable Regex Cache\r\n *\r\n * Building a `RegExp` is comparatively expensive, and the reactivity layer\r\n * checks the same variable names against many binding expressions when working\r\n * out which bindings depend on which state keys. Caching the compiled regex per\r\n * variable name avoids recreating it on every check.\r\n */\r\n\r\n// ============================================================================\r\n// Caches\r\n// ============================================================================\r\n\r\n/**\r\n * Cache for regex patterns used to test whether an expression references a\r\n * given variable as a whole word.\r\n */\r\nconst regexCache = new Map<string, RegExp>();\r\n\r\n// ============================================================================\r\n// Regex Caching\r\n// ============================================================================\r\n\r\n/**\r\n * Gets or creates a cached regex for variable boundary matching.\r\n *\r\n * @param variableName - The variable name to match\r\n * @returns A regex that matches the variable as a whole word\r\n */\r\nexport function getCachedVariableRegex(variableName: string): RegExp\r\n{\r\n let regex = regexCache.get(variableName);\r\n\r\n if (!regex)\r\n {\r\n // Escape special regex characters in the variable name\r\n const escaped = variableName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n regex = new RegExp(`\\\\b${escaped}\\\\b`);\r\n regexCache.set(variableName, regex);\r\n }\r\n\r\n return regex;\r\n}\r\n\r\n","import { BindingDescriptor } from \"../../types\";\r\nimport { getCachedVariableRegex } from \"../cache/expressionCache\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Maps state keys to the bindings that depend on them.\r\n * When a key changes, all its dependent bindings need to be re-evaluated.\r\n */\r\ntype BindingRegistry = Map<string, Set<BindingDescriptor>>;\r\n\r\n/**\r\n * Function signature for updating a single binding with new state\r\n */\r\ntype UpdateBindingFn = (\r\n binding: BindingDescriptor,\r\n state: Record<string, unknown>\r\n) => void;\r\n\r\n/**\r\n * Symbol to mark arrays that have already been wrapped with reactivity.\r\n * Prevents double-wrapping and allows identification of reactive arrays.\r\n */\r\nconst REACTIVE_ARRAY = Symbol(\"reactive-array\");\r\n\r\n/**\r\n * Symbol exposing the set of mutation subscribers on a reactive array.\r\n * When the same array is shared across owners (e.g. a parent passes it to a\r\n * child component as a prop), each owner registers its own onMutate callback\r\n * here so a single mutation (push/splice/index assignment) re-renders every\r\n * component that depends on the array — not just the one that created it.\r\n */\r\nconst REACTIVE_ARRAY_SUBSCRIBERS = Symbol(\"reactive-array-subscribers\");\r\n\r\n/**\r\n * Array methods that mutate the array and should trigger reactivity updates.\r\n */\r\nconst ARRAY_MUTATION_METHODS = [\r\n \"push\",\r\n \"pop\",\r\n \"shift\",\r\n \"unshift\",\r\n \"splice\",\r\n \"sort\",\r\n \"reverse\",\r\n \"fill\",\r\n \"copyWithin\",\r\n] as const;\r\n\r\n// ============================================================================\r\n// Reactive Arrays\r\n// ============================================================================\r\n\r\n/**\r\n * Wraps an array in a Proxy that intercepts mutation methods.\r\n * When any mutation method is called, the onMutate callback is triggered,\r\n * which updates all directives (like $for loops).\r\n *\r\n * Example:\r\n * const items = createReactiveArray(['a', 'b'], () => console.log('changed!'));\r\n * items.push('c'); // Logs: \"changed!\"\r\n * items[0] = 'x'; // Also triggers reactivity (index assignment)\r\n *\r\n * @param arr - The array to make reactive\r\n * @param onMutate - Callback to trigger when the array is mutated\r\n * @returns A reactive proxy of the array\r\n */\r\nexport function createReactiveArray<T>(arr: T[], onMutate: () => void): T[]\r\n{\r\n // Already reactive: register this additional subscriber instead of\r\n // re-wrapping. This lets multiple owners (parent + child sharing the array\r\n // as a prop) all be notified when the SAME array reference mutates.\r\n if ((arr as any)[REACTIVE_ARRAY])\r\n {\r\n const subscribers = (arr as any)[REACTIVE_ARRAY_SUBSCRIBERS] as\r\n | Set<() => void>\r\n | undefined;\r\n if (subscribers && onMutate)\r\n {\r\n subscribers.add(onMutate);\r\n }\r\n return arr;\r\n }\r\n\r\n // Each reactive array owns a set of mutation callbacks. `notify` fans a\r\n // single mutation out to every registered subscriber.\r\n const subscribers = new Set<() => void>();\r\n if (onMutate)\r\n {\r\n subscribers.add(onMutate);\r\n }\r\n const notify = () =>\r\n {\r\n for (const subscriber of subscribers)\r\n {\r\n subscriber();\r\n }\r\n };\r\n\r\n const reactiveArray = new Proxy(arr, {\r\n get(target, key: string | symbol)\r\n {\r\n // Mark this array as reactive\r\n if (key === REACTIVE_ARRAY)\r\n {\r\n return true;\r\n }\r\n\r\n // Expose the subscriber set so additional owners can register.\r\n if (key === REACTIVE_ARRAY_SUBSCRIBERS)\r\n {\r\n return subscribers;\r\n }\r\n\r\n const value = target[key as keyof typeof target];\r\n\r\n // Intercept mutation methods\r\n if (\r\n typeof key === \"string\" &&\r\n ARRAY_MUTATION_METHODS.includes(key as any) &&\r\n typeof value === \"function\"\r\n )\r\n {\r\n return (...args: unknown[]) =>\r\n {\r\n // Wrap any array arguments (e.g., for splice adding new items)\r\n const wrappedArgs = args.map((arg) =>\r\n Array.isArray(arg) ? createReactiveArray(arg, notify) : arg\r\n );\r\n\r\n // Call the original method\r\n const result = (value as Function).apply(target, wrappedArgs);\r\n\r\n // Trigger reactivity update for every subscriber\r\n notify();\r\n\r\n return result;\r\n };\r\n }\r\n\r\n // Recursively wrap nested arrays\r\n if (Array.isArray(value))\r\n {\r\n return createReactiveArray(value, notify);\r\n }\r\n\r\n return value;\r\n },\r\n\r\n set(target, key: string | symbol, value)\r\n {\r\n const index = typeof key === \"string\" ? parseInt(key, 10) : NaN;\r\n const isIndexAssignment = !isNaN(index);\r\n const isLengthChange = key === \"length\";\r\n\r\n // Wrap array values being assigned\r\n const wrappedValue = Array.isArray(value)\r\n ? createReactiveArray(value, notify)\r\n : value;\r\n\r\n // Check if value actually changed\r\n const oldValue = target[key as keyof typeof target];\r\n if (oldValue === wrappedValue)\r\n {\r\n return true;\r\n }\r\n\r\n // Set the value\r\n (target as any)[key] = wrappedValue;\r\n\r\n // Trigger reactivity for index assignments or length changes\r\n if (isIndexAssignment || isLengthChange)\r\n {\r\n notify();\r\n }\r\n\r\n return true;\r\n },\r\n\r\n deleteProperty(target, key: string | symbol)\r\n {\r\n const result = delete (target as any)[key];\r\n if (result)\r\n {\r\n notify();\r\n }\r\n return result;\r\n },\r\n });\r\n\r\n return reactiveArray;\r\n}\r\n\r\n/**\r\n * Checks whether a value is a plain object (created via `{}` literal or\r\n * `Object.create(null)`). Dates, Maps, DOM nodes, class instances, and\r\n * arrays are excluded — only plain objects get deep reactive wrapping.\r\n */\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown>\r\n{\r\n if (value === null || typeof value !== \"object\" || Array.isArray(value))\r\n {\r\n return false;\r\n }\r\n const proto = Object.getPrototypeOf(value);\r\n return proto === Object.prototype || proto === null;\r\n}\r\n\r\n/**\r\n * Recursively wraps all arrays in an object with reactive proxies.\r\n * This ensures nested arrays also trigger reactivity updates.\r\n *\r\n * @param obj - Object containing potential arrays to wrap\r\n * @param onMutate - Callback when any array is mutated\r\n * @returns The object with all arrays wrapped\r\n */\r\nfunction wrapArraysInObject(\r\n obj: Record<string, unknown>,\r\n onMutate: () => void\r\n): Record<string, unknown>\r\n{\r\n for (const key of Object.keys(obj))\r\n {\r\n const value = obj[key];\r\n if (Array.isArray(value))\r\n {\r\n obj[key] = createReactiveArray(value, onMutate);\r\n } else if (value && typeof value === \"object\" && !Array.isArray(value))\r\n {\r\n // Recursively wrap arrays in nested objects\r\n wrapArraysInObject(value as Record<string, unknown>, onMutate);\r\n }\r\n }\r\n return obj;\r\n}\r\n\r\n// ============================================================================\r\n// Reactive State\r\n// ============================================================================\r\n\r\n/**\r\n * Creates a reactive state object that automatically updates the DOM\r\n * when properties change.\r\n *\r\n * How it works:\r\n * 1. Wraps the initial state in a Proxy\r\n * 2. When a property is set, finds all bindings that depend on it\r\n * 3. Re-evaluates those bindings and updates the DOM\r\n *\r\n * Supports dynamically adding new state keys (e.g., from module scripts).\r\n * When a new key is added, it automatically finds bindings that depend on it.\r\n *\r\n * Example:\r\n * const state = createReactiveState({ count: 0 }, bindings, updateFn);\r\n * state.count++; // Automatically updates all {count} bindings in the DOM\r\n * state.name = \"hello\"; // New key - finds and updates {name} bindings\r\n *\r\n * @param initialState - Initial state values extracted from component script\r\n * @param bindings - All template bindings that might depend on state\r\n * @param updateBinding - Function to re-evaluate and update a single binding\r\n * @param onStateChange - Optional callback when any state property changes (for directives)\r\n */\r\nexport function createReactiveState(\r\n initialState: Record<string, unknown>,\r\n bindings: BindingDescriptor[],\r\n updateBinding: UpdateBindingFn,\r\n onStateChange?: () => void\r\n): Record<string, unknown>\r\n{\r\n // Build dependency map: which bindings depend on which state keys\r\n const registry = buildBindingRegistry(bindings, Object.keys(initialState));\r\n\r\n // Helper to trigger all updates for a key\r\n const triggerUpdate = (key: string, target: Record<string, unknown>) =>\r\n {\r\n const dependentBindings = registry.get(key);\r\n if (dependentBindings)\r\n {\r\n for (const binding of dependentBindings)\r\n {\r\n updateBinding(binding, target);\r\n }\r\n }\r\n if (onStateChange)\r\n {\r\n onStateChange();\r\n }\r\n };\r\n\r\n // Key-aware mutation handler for reactive arrays. A push/splice/index\r\n // assignment must update the same bindings a reassignment of the key\r\n // would (e.g. {items.length}), not just the directives — so it routes\r\n // through triggerUpdate for the owning top-level key. During script\r\n // bootstrap (__suspendReactivity) bindings can't be evaluated yet, so\r\n // only the (batched) directive callback runs.\r\n const arrayOnMutate = (key: string) => () =>\r\n {\r\n if ((initialState as any).__suspendReactivity)\r\n {\r\n if (onStateChange)\r\n {\r\n onStateChange();\r\n }\r\n return;\r\n }\r\n triggerUpdate(key, initialState);\r\n };\r\n\r\n // External mutation channel: module-script arrays wrapped OUTSIDE this\r\n // closure (e.g. the __wrapReactiveArray helper injected into external\r\n // modules) can't reach triggerUpdate directly. The state proxy exposes\r\n // this function as `__notifyKeyChanged` so those wrappers can request\r\n // the same per-key binding updates a reassignment would produce.\r\n const notifyKeyChanged = (key: string): void =>\r\n {\r\n arrayOnMutate(key)();\r\n };\r\n\r\n // Wrap any arrays in initialState with reactive proxies, each tied to its\r\n // top-level key. This enables array.push(), array.splice(), etc. to\r\n // trigger updates for the bindings that depend on that key.\r\n for (const key of Object.keys(initialState))\r\n {\r\n const value = initialState[key];\r\n if (Array.isArray(value))\r\n {\r\n initialState[key] = createReactiveArray(value, arrayOnMutate(key));\r\n } else if (value && typeof value === \"object\")\r\n {\r\n wrapArraysInObject(value as Record<string, unknown>, arrayOnMutate(key));\r\n }\r\n }\r\n\r\n // Deep reactivity: nested plain objects read off the state are wrapped in\r\n // proxies (lazily, on property access) so writes like\r\n // `user.profile.name = \"x\"` — from scripts or $bind's setNestedValue —\r\n // trigger the bindings that depend on the ROOT key (\"user\"). The binding\r\n // registry is keyed by top-level state keys, so any nested write updates\r\n // everything that references that root. Proxies are cached per\r\n // (object, rootKey) pair to keep identity stable across reads.\r\n const deepProxyCache = new WeakMap<object, Map<string, object>>();\r\n\r\n const wrapDeep = (\r\n obj: Record<string, unknown>,\r\n rootKey: string\r\n ): Record<string, unknown> =>\r\n {\r\n let byRoot = deepProxyCache.get(obj);\r\n const cached = byRoot?.get(rootKey);\r\n if (cached)\r\n {\r\n return cached as Record<string, unknown>;\r\n }\r\n\r\n const proxy = new Proxy(obj, {\r\n get(target, key)\r\n {\r\n const value = target[key as keyof typeof target];\r\n if (typeof key === \"string\" && isPlainObject(value))\r\n {\r\n return wrapDeep(value, rootKey);\r\n }\r\n return value;\r\n },\r\n\r\n set(target, key, value)\r\n {\r\n if (typeof key !== \"string\")\r\n {\r\n (target as any)[key] = value;\r\n return true;\r\n }\r\n\r\n // Skip if value hasn't actually changed\r\n if (key in target && target[key] === value) return true;\r\n\r\n // Arrays assigned into nested objects become reactive, tied to\r\n // the same root key so mutations re-render its dependents.\r\n target[key] = Array.isArray(value)\r\n ? createReactiveArray(value, arrayOnMutate(rootKey))\r\n : value;\r\n\r\n if (!(initialState as any).__suspendReactivity)\r\n {\r\n triggerUpdate(rootKey, initialState);\r\n }\r\n return true;\r\n },\r\n\r\n deleteProperty(target, key)\r\n {\r\n const existed = key in target;\r\n delete (target as any)[key];\r\n if (\r\n existed &&\r\n typeof key === \"string\" &&\r\n !(initialState as any).__suspendReactivity\r\n )\r\n {\r\n triggerUpdate(rootKey, initialState);\r\n }\r\n return true;\r\n },\r\n });\r\n\r\n if (!byRoot)\r\n {\r\n byRoot = new Map();\r\n deepProxyCache.set(obj, byRoot);\r\n }\r\n byRoot.set(rootKey, proxy);\r\n return proxy;\r\n };\r\n\r\n // Create a Proxy that intercepts property changes\r\n const reactiveState = new Proxy(initialState, {\r\n get(target, key: string)\r\n {\r\n // Not an own property (get-trap only), so it never appears in\r\n // Object.keys(state) or event-handler destructuring.\r\n if (key === \"__notifyKeyChanged\")\r\n {\r\n return notifyKeyChanged;\r\n }\r\n\r\n const value = target[key];\r\n if (typeof key === \"string\" && isPlainObject(value))\r\n {\r\n return wrapDeep(value, key);\r\n }\r\n return value;\r\n },\r\n\r\n set(target, key: string, value)\r\n {\r\n // Check if this is a NEW key being added\r\n const isNewKey = !(key in target);\r\n\r\n // Skip if value hasn't actually changed (for existing keys)\r\n if (!isNewKey && target[key] === value) return true;\r\n\r\n // Wrap arrays with reactive proxies before storing, tied to this key\r\n // so mutations update the bindings that depend on it.\r\n const wrappedValue = Array.isArray(value)\r\n ? createReactiveArray(value, arrayOnMutate(key))\r\n : value;\r\n\r\n // Update the underlying value\r\n target[key] = wrappedValue;\r\n\r\n // If new key, register bindings that depend on it\r\n if (isNewKey)\r\n {\r\n registerNewKey(key, bindings, registry);\r\n }\r\n\r\n // Skip binding updates while reactivity is suspended (e.g. during\r\n // module-script bootstrap). Callers re-apply bindings once all state\r\n // is populated, avoiding spurious ReferenceErrors for variables that\r\n // are declared later in the same script.\r\n if ((target as any).__suspendReactivity)\r\n {\r\n return true;\r\n }\r\n\r\n // Find and update all bindings that depend on this key\r\n triggerUpdate(key, target);\r\n\r\n return true;\r\n },\r\n });\r\n\r\n return reactiveState;\r\n}\r\n\r\n// ============================================================================\r\n// Dependency Tracking\r\n// ============================================================================\r\n\r\n/**\r\n * Analyzes bindings to determine which state keys they depend on.\r\n *\r\n * Creates a reverse mapping from state keys to bindings:\r\n * \"name\" → [binding for \"{name}\", binding for \"{name.toUpperCase()}\"]\r\n * \"count\" → [binding for \"{count}\", binding for \"{count + 1}\"]\r\n *\r\n * This allows O(1) lookup when a state key changes to find which\r\n * bindings need to be updated.\r\n */\r\nfunction buildBindingRegistry(\r\n bindings: BindingDescriptor[],\r\n stateKeys: string[]\r\n): BindingRegistry\r\n{\r\n const registry: BindingRegistry = new Map();\r\n\r\n // Initialize empty sets for each state key\r\n for (const key of stateKeys)\r\n {\r\n registry.set(key, new Set());\r\n }\r\n\r\n // For each binding, figure out which state keys it references\r\n for (const descriptor of bindings)\r\n {\r\n for (const binding of descriptor.bindings)\r\n {\r\n // Check if any state key appears in the expression\r\n for (const key of stateKeys)\r\n {\r\n if (expressionDependsOn(binding.raw, key))\r\n {\r\n registry.get(key)!.add(descriptor);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return registry;\r\n}\r\n\r\n/**\r\n * Registers bindings for a newly added state key.\r\n * Called when a new property is added to the reactive state\r\n * (e.g., from module scripts loaded after initial setup).\r\n */\r\nfunction registerNewKey(\r\n key: string,\r\n bindings: BindingDescriptor[],\r\n registry: BindingRegistry\r\n): void\r\n{\r\n // Create a new set for this key\r\n registry.set(key, new Set());\r\n\r\n // Find all bindings that depend on this key\r\n for (const descriptor of bindings)\r\n {\r\n for (const binding of descriptor.bindings)\r\n {\r\n if (expressionDependsOn(binding.raw, key))\r\n {\r\n registry.get(key)!.add(descriptor);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Checks if an expression depends on a variable name.\r\n * Uses word boundary matching to avoid false positives.\r\n * Caches regex patterns for performance.\r\n *\r\n * Examples:\r\n * - expressionDependsOn(\"name.toUpperCase()\", \"name\") → true\r\n * - expressionDependsOn(\"username\", \"name\") → false (part of another word)\r\n * - expressionDependsOn(\"count + 1\", \"count\") → true\r\n * - expressionDependsOn(\"counter\", \"count\") → false\r\n */\r\nfunction expressionDependsOn(\r\n expression: string,\r\n variableName: string\r\n): boolean\r\n{\r\n // Use cached regex for performance (avoids creating new RegExp each call)\r\n const regex = getCachedVariableRegex(variableName);\r\n return regex.test(expression);\r\n}\r\n\r\n// ============================================================================\r\n// Binding Update Helper\r\n// ============================================================================\r\n\r\n/**\r\n * Creates the update function that re-evaluates a binding and updates the DOM.\r\n * This should be called once when setting up reactivity, then passed to\r\n * createReactiveState.\r\n *\r\n * @param evaluateExpression - Function to evaluate {expression} against state\r\n */\r\nexport function createBindingUpdater(\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>\r\n ) => unknown\r\n): UpdateBindingFn\r\n{\r\n return (descriptor: BindingDescriptor, state: Record<string, unknown>) =>\r\n {\r\n let result = descriptor.original;\r\n\r\n // Re-evaluate each {expression} in the binding\r\n for (const binding of descriptor.bindings)\r\n {\r\n const evaluated = evaluateExpression(binding.raw, state);\r\n const stringValue = String(evaluated ?? \"\");\r\n result = result.replace(`{${binding.raw}}`, stringValue);\r\n }\r\n\r\n // Update the DOM\r\n if (descriptor.isAttribute && descriptor.attributeName)\r\n {\r\n const element =\r\n (descriptor as any).element ?? descriptor.node.parentElement;\r\n if (element)\r\n {\r\n element.setAttribute(descriptor.attributeName, result);\r\n }\r\n } else\r\n {\r\n descriptor.node.textContent = result;\r\n }\r\n };\r\n}\r\n","/**\r\n * Shared reference-rewriting helper for the runtime \"state access\"\r\n * transforms in scriptParser.ts and moduleExecutor.ts.\r\n *\r\n * Rewrites standalone references to a reactive variable into\r\n * `__state__.varName`. A plain regex substitution corrupts ES6\r\n * object-literal shorthand, the one place a bare identifier reference\r\n * cannot be replaced by a member expression:\r\n *\r\n * $emit(\"msg\", { text, name }) // `name` is a reactive variable\r\n * plain rewrite → { text, __state__.name } // SyntaxError!\r\n * this helper → { text, name: __state__.name } // valid + reactive\r\n *\r\n * Destructuring DECLARATIONS (`const { name } = obj`) are left untouched:\r\n * they declare a local binding that shadows the state variable, and\r\n * rewriting the pattern would be a SyntaxError. Destructuring ASSIGNMENTS\r\n * (`({ name } = obj)`) are object literals in expression position, so the\r\n * shorthand expansion yields `({ name: __state__.name } = obj)` — valid,\r\n * and it correctly writes into reactive state.\r\n *\r\n * Callers must mask string literals BEFORE calling this (both transforms\r\n * already protect strings with placeholders); otherwise string contents\r\n * would be rewritten and could confuse the bracket scan.\r\n *\r\n * Known limitations (unchanged from the previous inline rewrites):\r\n * - Destructuring with defaults (`const { name = 1 } = o`) and state-named\r\n * function parameters are not scope-analyzed.\r\n * - Shorthand inside a plain statement block that happens to look like a\r\n * slot (e.g. a comma expression `{ name, other; }`) is treated as a\r\n * labeled statement after expansion, which is still valid JS.\r\n */\r\n\r\n/**\r\n * Full state-access transform shared by scriptParser.ts (component scripts\r\n * and re-created event-handler function definitions) and moduleExecutor.ts\r\n * (module scripts).\r\n *\r\n * Character-scans the code so that:\r\n * - \"...\" and '...' string literals are protected from rewriting\r\n * - template-literal TEXT segments are protected, while the expressions\r\n * inside ${...} are recursively transformed (and the transformed result\r\n * is itself protected, so restored string literals inside it are not\r\n * re-rewritten by the outer pass)\r\n * - comments are copied through untouched\r\n *\r\n * It then rewrites top-level declarations (`let x = v` → `__state__.x ??= v`,\r\n * so attribute overrides already in state win over script defaults) unless\r\n * `rewriteDeclarations` is false (the event-handler funcDefs path, which has\r\n * no declarations to rewrite), and finally rewrites standalone references\r\n * via replaceVarWithStateAccess (object-shorthand aware).\r\n */\r\nexport function transformCodeToStateAccess(\r\n code: string,\r\n variables: string[],\r\n options?: { rewriteDeclarations?: boolean },\r\n): string {\r\n if (variables.length === 0) return code;\r\n const rewriteDeclarations = options?.rewriteDeclarations !== false;\r\n\r\n // Step 1: Protect string literals by replacing them with placeholders.\r\n // For \"...\" and '...' the entire literal is protected. For template\r\n // literals (`...`), only the TEXT segments are protected; expressions\r\n // inside ${...} are recursively transformed so identifier references\r\n // (e.g. `${count}`) still get rewritten.\r\n const strings: string[] = [];\r\n const protect = (literal: string): string => {\r\n strings.push(literal);\r\n return `__STRING_PLACEHOLDER_${strings.length - 1}__`;\r\n };\r\n\r\n let protected_code = \"\";\r\n let i = 0;\r\n while (i < code.length) {\r\n const ch = code[i];\r\n\r\n // Single-line comment\r\n if (ch === \"/\" && code[i + 1] === \"/\") {\r\n const nl = code.indexOf(\"\\n\", i);\r\n const end = nl === -1 ? code.length : nl;\r\n protected_code += code.slice(i, end);\r\n i = end;\r\n continue;\r\n }\r\n // Block comment\r\n if (ch === \"/\" && code[i + 1] === \"*\") {\r\n const close = code.indexOf(\"*/\", i + 2);\r\n const end = close === -1 ? code.length : close + 2;\r\n protected_code += code.slice(i, end);\r\n i = end;\r\n continue;\r\n }\r\n\r\n // Single/double quote: protect whole literal\r\n if (ch === '\"' || ch === \"'\") {\r\n let j = i + 1;\r\n while (j < code.length && code[j] !== ch) {\r\n if (code[j] === \"\\\\\") j += 2;\r\n else j++;\r\n }\r\n protected_code += protect(code.slice(i, j + 1));\r\n i = j + 1;\r\n continue;\r\n }\r\n\r\n // Template literal: protect text segments, recurse into ${...}\r\n if (ch === \"`\") {\r\n protected_code += \"`\";\r\n i++;\r\n let textStart = i;\r\n while (i < code.length && code[i] !== \"`\") {\r\n if (code[i] === \"\\\\\") {\r\n i += 2;\r\n continue;\r\n }\r\n if (code[i] === \"$\" && code[i + 1] === \"{\") {\r\n if (i > textStart) {\r\n protected_code += protect(code.slice(textStart, i));\r\n }\r\n // Copy ${...} with brace nesting; nested strings/templates handled\r\n // by recursing through this same transform on the inner expression.\r\n protected_code += \"${\";\r\n i += 2;\r\n const exprStart = i;\r\n let depth = 1;\r\n while (i < code.length && depth > 0) {\r\n const c = code[i];\r\n if (c === '\"' || c === \"'\") {\r\n i++;\r\n while (i < code.length && code[i] !== c) {\r\n if (code[i] === \"\\\\\") i += 2;\r\n else i++;\r\n }\r\n i++;\r\n continue;\r\n }\r\n if (c === \"`\") {\r\n // skip nested template literal\r\n i++;\r\n let nestedDepth = 0;\r\n while (i < code.length) {\r\n if (code[i] === \"\\\\\") {\r\n i += 2;\r\n continue;\r\n }\r\n if (code[i] === \"`\" && nestedDepth === 0) {\r\n i++;\r\n break;\r\n }\r\n if (code[i] === \"$\" && code[i + 1] === \"{\") {\r\n nestedDepth++;\r\n i += 2;\r\n continue;\r\n }\r\n if (code[i] === \"}\" && nestedDepth > 0) {\r\n nestedDepth--;\r\n }\r\n i++;\r\n }\r\n continue;\r\n }\r\n if (c === \"{\") depth++;\r\n else if (c === \"}\") {\r\n depth--;\r\n if (depth === 0) break;\r\n }\r\n i++;\r\n }\r\n // Recursively transform the inner expression, then protect the\r\n // RESULT: its own string literals are already restored, and the\r\n // outer declaration/reference passes must not touch them.\r\n const innerExpr = code.slice(exprStart, i);\r\n protected_code += protect(\r\n transformCodeToStateAccess(innerExpr, variables, options),\r\n );\r\n // Skip closing brace\r\n if (code[i] === \"}\") i++;\r\n protected_code += \"}\";\r\n textStart = i;\r\n continue;\r\n }\r\n i++;\r\n }\r\n if (i > textStart) {\r\n protected_code += protect(code.slice(textStart, i));\r\n }\r\n protected_code += \"`\";\r\n i++; // skip closing backtick\r\n continue;\r\n }\r\n\r\n protected_code += ch;\r\n i++;\r\n }\r\n\r\n // Step 2: Transform top-level variable declarations\r\n // `let x = value;` → `__state__.x ??= value;`\r\n // Use ??= so attribute overrides (already in __state__) win over script defaults.\r\n if (rewriteDeclarations) {\r\n for (const varName of variables) {\r\n const declRegex = new RegExp(\r\n `\\\\b(let|const|var)\\\\s+(${escapeRegex(varName)})\\\\s*=`,\r\n \"g\",\r\n );\r\n protected_code = protected_code.replace(\r\n declRegex,\r\n `__state__.${varName} ??=`,\r\n );\r\n }\r\n }\r\n\r\n // Step 3: Replace standalone variable references with __state__.varName\r\n // (shorthand-aware — see replaceVarWithStateAccess below)\r\n for (const varName of variables) {\r\n protected_code = replaceVarWithStateAccess(protected_code, varName);\r\n }\r\n\r\n // Step 4: Restore string literals. Use a replacer FUNCTION so literals\r\n // containing replacement patterns (\"$&\", \"$'\", \"$1\", …) stay literal.\r\n let transformed = protected_code;\r\n for (let idx = 0; idx < strings.length; idx++) {\r\n transformed = transformed.replace(\r\n `__STRING_PLACEHOLDER_${idx}__`,\r\n () => strings[idx],\r\n );\r\n }\r\n\r\n return transformed;\r\n}\r\n\r\ntype ShorthandSlot = \"object\" | \"destructuring\" | \"none\";\r\n\r\n/** Keywords whose following `{` opens an object literal (expression position). */\r\nconst OBJECT_POSITION_KEYWORDS = new Set([\r\n \"return\",\r\n \"typeof\",\r\n \"case\",\r\n \"in\",\r\n \"of\",\r\n \"yield\",\r\n \"await\",\r\n \"throw\",\r\n \"void\",\r\n \"delete\",\r\n \"new\",\r\n]);\r\n\r\n/**\r\n * Replaces standalone references to `varName` with `__state__.varName`,\r\n * expanding object-literal shorthand and skipping destructuring declarations.\r\n */\r\nexport function replaceVarWithStateAccess(\r\n code: string,\r\n varName: string,\r\n): string {\r\n // Matches the variable name that is:\r\n // - NOT preceded by a single dot (property access like foo.bar),\r\n // but IS allowed after spread (...varName)\r\n // - NOT preceded by __state__. (already transformed)\r\n // - a word boundary on both sides\r\n // - NOT followed by : (object key) or ( (function call/declaration)\r\n const pattern = new RegExp(\r\n `(?<![^.]\\\\.)(?<!__state__\\\\.)\\\\b${escapeRegex(varName)}\\\\b(?!\\\\s*[:(])`,\r\n \"g\",\r\n );\r\n\r\n return code.replace(pattern, (match: string, offset: number) => {\r\n switch (classifyShorthandSlot(code, offset, match.length)) {\r\n case \"object\":\r\n // Object-literal shorthand: expand to an explicit key so the\r\n // member expression is legal ({ name } → { name: __state__.name })\r\n return `${varName}: __state__.${varName}`;\r\n case \"destructuring\":\r\n // `const { name } = obj` declares a local shadow — leave it alone\r\n return match;\r\n default:\r\n return `__state__.${varName}`;\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Decides whether the matched identifier occupies an object-literal\r\n * shorthand slot, a destructuring-declaration slot, or neither.\r\n */\r\nfunction classifyShorthandSlot(\r\n code: string,\r\n start: number,\r\n length: number,\r\n): ShorthandSlot {\r\n const prev = lastNonSpaceChar(code, start - 1);\r\n const next = firstNonSpaceChar(code, start + length);\r\n\r\n // Shorthand can only sit between `{` or `,` and `,` or `}`.\r\n if ((prev !== \"{\" && prev !== \",\") || (next !== \",\" && next !== \"}\")) {\r\n return \"none\";\r\n }\r\n\r\n // Only an enclosing `{` can make this an object/destructuring slot.\r\n // A `,` separator inside (…) or […] — call arguments, array literals —\r\n // falls through to the plain rewrite.\r\n const opener = findEnclosingOpener(code, start);\r\n if (opener === -1 || code[opener] !== \"{\") return \"none\";\r\n\r\n return classifyOpenBrace(code, opener);\r\n}\r\n\r\n/**\r\n * Classifies the `{` at braceIdx by its preceding token: object literal\r\n * (expression position), destructuring declaration pattern, or statement\r\n * block. Same token-lookbehind spirit as isRegexContext in scriptParser.\r\n */\r\nfunction classifyOpenBrace(code: string, braceIdx: number): ShorthandSlot {\r\n let j = braceIdx - 1;\r\n while (j >= 0 && /\\s/.test(code[j])) j--;\r\n // Nothing before the brace: happens for recursed `${{ a, name }}`\r\n // interpolation fragments, where the brace IS an object literal. (A whole\r\n // script starting with a bare block is vanishingly rare, and expanding\r\n // shorthand there still yields valid code — a labeled statement.)\r\n if (j < 0) return \"object\";\r\n\r\n const c = code[j];\r\n if (c === \")\") return \"none\"; // function/if/for/while/catch block\r\n if (c === \">\" && code[j - 1] === \"=\") return \"none\"; // arrow body `=> {`\r\n\r\n // Punctuation that puts the brace in expression position → object literal\r\n if (\"=([,:?!&|^~+-*/%<>\".includes(c)) return \"object\";\r\n\r\n if (/[A-Za-z0-9_$]/.test(c)) {\r\n let k = j;\r\n while (k >= 0 && /[A-Za-z0-9_$]/.test(code[k])) k--;\r\n const word = code.slice(k + 1, j + 1);\r\n if (word === \"let\" || word === \"const\" || word === \"var\") {\r\n return \"destructuring\";\r\n }\r\n if (OBJECT_POSITION_KEYWORDS.has(word)) return \"object\";\r\n return \"none\"; // else / try / finally / do / label… → statement block\r\n }\r\n\r\n return \"none\"; // `;`, `}`, `{`, start of code → statement block\r\n}\r\n\r\n/** Nearest unmatched opening bracket ( ( [ { ) scanning backwards from `from`. */\r\nfunction findEnclosingOpener(code: string, from: number): number {\r\n let depth = 0;\r\n for (let i = from - 1; i >= 0; i--) {\r\n const c = code[i];\r\n if (c === \")\" || c === \"]\" || c === \"}\") {\r\n depth++;\r\n } else if (c === \"(\" || c === \"[\" || c === \"{\") {\r\n if (depth === 0) return i;\r\n depth--;\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\nfunction lastNonSpaceChar(code: string, from: number): string {\r\n for (let i = from; i >= 0; i--) {\r\n if (!/\\s/.test(code[i])) return code[i];\r\n }\r\n return \"\";\r\n}\r\n\r\nfunction firstNonSpaceChar(code: string, from: number): string {\r\n for (let i = from; i < code.length; i++) {\r\n if (!/\\s/.test(code[i])) return code[i];\r\n }\r\n return \"\";\r\n}\r\n\r\nfunction escapeRegex(str: string): string {\r\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n}\r\n","/**\r\n * Developer-friendly warning and error utilities for LadrillosJS.\r\n *\r\n * - Consistent prefix for easy filtering\r\n * - Component name and file context\r\n * - Code frame generation for templates\r\n * - Console styling for better readability\r\n * - Error codes with documentation links\r\n *\r\n * Bundle size optimization:\r\n * The global `__DEV__` constant is replaced at build time by the bundler.\r\n * All dev-only code wrapped in `if (__DEV__)` is completely eliminated\r\n * from production builds via dead code elimination.\r\n */\r\n\r\n// Ensure __DEV__ is recognized by TypeScript\r\n// This is a compile-time constant defined by the bundler.\r\ndeclare const __DEV__: boolean;\r\n\r\n// Runtime-safe alias. When the bundler's `define` replaces `__DEV__` with a\r\n// literal, terser evaluates this expression to that literal and dead-code\r\n// eliminates every `if (!IS_DEV)` branch. When the module is consumed from a\r\n// build that did NOT substitute `__DEV__` (e.g. a raw `tsc` output), the\r\n// `typeof` guard prevents a `ReferenceError` and defaults to production mode.\r\nconst IS_DEV: boolean =\r\n typeof __DEV__ !== \"undefined\" ? __DEV__ : false;\r\n\r\n// ============================================================================\r\n// Configuration\r\n// ============================================================================\r\n\r\nconst PREFIX = \"[LadrillosJS]\";\r\nconst DOCS_BASE_URL =\r\n \"https://github.com/drubiodev/LadrillosJS/blob/main/docs/21-error-handling.md\";\r\n\r\n// ============================================================================\r\n// Console Styling\r\n// ============================================================================\r\n\r\n/**\r\n * CSS styles for console output (browser only)\r\n *\r\n * Color scheme optimized for readability:\r\n * - Orange prefix (brand identity)\r\n * - White/bright error text (high contrast)\r\n * - Cyan for component names (distinct, cool color)\r\n * - Green for file paths (easy to spot)\r\n * - Dim gray for less important info\r\n */\r\nconst styles = {\r\n prefix: \"color: #ff6b35; font-weight: bold\", // LadrillosJS orange, bold\r\n component: \"color: #4fc3f7; font-weight: bold\", // Light cyan, bold\r\n file: \"color: #81c784\", // Light green\r\n expression: \"color: #fff176; font-weight: bold\", // Yellow, bold (stands out)\r\n error: \"color: #ffffff; font-weight: bold\", // White, bold (high contrast)\r\n reset: \"color: inherit; font-weight: normal\",\r\n dim: \"color: #9e9e9e\", // Lighter gray for better visibility\r\n};\r\n\r\n/**\r\n * Check if we're in a browser environment with styled console support\r\n */\r\nconst supportsStyledConsole = (): boolean =>\r\n{\r\n return (\r\n typeof window !== \"undefined\" &&\r\n typeof console !== \"undefined\" &&\r\n typeof console.log === \"function\"\r\n );\r\n};\r\n\r\n// ============================================================================\r\n// Component Context Tracking\r\n// ============================================================================\r\n\r\n/**\r\n * Context information about the current component being processed.\r\n * This is set by the framework during component initialization.\r\n */\r\nexport interface ComponentContext\r\n{\r\n /** The component tag name (e.g., \"my-counter\") */\r\n tagName?: string;\r\n /** The source file path (e.g., \"components/counter.html\") */\r\n sourcePath?: string;\r\n /** The unique instance ID */\r\n instanceId?: string;\r\n}\r\n\r\n/**\r\n * Current component context - set during component processing\r\n */\r\nlet currentContext: ComponentContext | null = null;\r\n\r\n/**\r\n * Set the current component context for error reporting.\r\n * Call this at the start of component initialization.\r\n */\r\nexport function setComponentContext(context: ComponentContext | null): void\r\n{\r\n currentContext = context;\r\n}\r\n\r\n/**\r\n * Get the current component context.\r\n */\r\nexport function getComponentContext(): ComponentContext | null\r\n{\r\n return currentContext;\r\n}\r\n\r\n/**\r\n * Run a function with a specific component context.\r\n * Automatically restores previous context after execution.\r\n */\r\nexport function withComponentContext<T>(\r\n context: ComponentContext,\r\n fn: () => T,\r\n): T\r\n{\r\n const previousContext = currentContext;\r\n currentContext = context;\r\n try\r\n {\r\n return fn();\r\n } finally\r\n {\r\n currentContext = previousContext;\r\n }\r\n}\r\n\r\n/**\r\n * Async version of withComponentContext\r\n */\r\nexport async function withComponentContextAsync<T>(\r\n context: ComponentContext,\r\n fn: () => Promise<T>,\r\n): Promise<T>\r\n{\r\n const previousContext = currentContext;\r\n currentContext = context;\r\n try\r\n {\r\n return await fn();\r\n } finally\r\n {\r\n currentContext = previousContext;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Code Frame Generation\r\n// ============================================================================\r\n\r\n/**\r\n * Generate a code frame showing the error location in source code.\r\n *\r\n * @param source - The source code\r\n * @param start - Start position of the error\r\n * @param end - End position of the error\r\n * @returns Formatted code frame string\r\n */\r\nexport function generateCodeFrame(\r\n source: string,\r\n start: number = 0,\r\n end: number = source.length,\r\n): string\r\n{\r\n const lines = source.split(\"\\n\");\r\n let count = 0;\r\n const res: string[] = [];\r\n\r\n for (let i = 0; i < lines.length; i++)\r\n {\r\n const line = lines[i];\r\n const lineLength = line.length + 1; // +1 for newline\r\n const lineNumber = i + 1;\r\n\r\n if (count + lineLength >= start)\r\n {\r\n // Show 2 lines before and after\r\n for (\r\n let j = Math.max(0, i - 2);\r\n j <= Math.min(lines.length - 1, i + 2);\r\n j++\r\n )\r\n {\r\n const ln = j + 1;\r\n const lineContent = lines[j];\r\n const linePrefix = `${ln}`.padStart(4) + \" │ \";\r\n\r\n res.push(`${linePrefix}${lineContent}`);\r\n\r\n // Add underline for the error line\r\n if (j === i)\r\n {\r\n const pad = start - (count - lineLength);\r\n const length = Math.min(\r\n end > count ? end - start : lineLength - pad,\r\n lineContent.length - pad,\r\n );\r\n res.push(\r\n ` │ ${\"\".padStart(Math.max(0, pad))}${\"^\".repeat(\r\n Math.max(1, length),\r\n )}`,\r\n );\r\n }\r\n }\r\n break;\r\n }\r\n count += lineLength;\r\n }\r\n\r\n return res.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Find the position of an expression in template source.\r\n */\r\nexport function findExpressionPosition(\r\n template: string,\r\n expression: string,\r\n): { start: number; end: number } | null\r\n{\r\n // Look for {expression} pattern\r\n const searchPattern = `{${expression}}`;\r\n const index = template.indexOf(searchPattern);\r\n\r\n if (index !== -1)\r\n {\r\n return {\r\n start: index,\r\n end: index + searchPattern.length,\r\n };\r\n }\r\n\r\n // Also try without braces for attribute values\r\n const exprIndex = template.indexOf(expression);\r\n if (exprIndex !== -1)\r\n {\r\n return {\r\n start: exprIndex,\r\n end: exprIndex + expression.length,\r\n };\r\n }\r\n\r\n return null;\r\n}\r\n\r\n// ============================================================================\r\n// Error Formatting\r\n// ============================================================================\r\n\r\n/**\r\n * Format component info for error messages.\r\n * If context is explicitly passed (even null), uses that.\r\n * Only falls back to currentContext if context is undefined.\r\n */\r\nfunction formatComponentInfo(context?: ComponentContext | null): string\r\n{\r\n const ctx = context !== undefined ? context : currentContext;\r\n if (!ctx) return \"\";\r\n\r\n const parts: string[] = [];\r\n\r\n if (ctx.tagName)\r\n {\r\n parts.push(`<${ctx.tagName}>`);\r\n }\r\n\r\n if (ctx.sourcePath)\r\n {\r\n // Extract just the filename for brevity\r\n const fileName = ctx.sourcePath.split(\"/\").pop() || ctx.sourcePath;\r\n parts.push(`(${fileName})`);\r\n }\r\n\r\n return parts.length > 0 ? ` in ${parts.join(\" \")}` : \"\";\r\n}\r\n\r\n/**\r\n * Format error message with context\r\n */\r\nfunction formatMessage(\r\n message: string,\r\n context?: ComponentContext | null,\r\n): string\r\n{\r\n const componentInfo = formatComponentInfo(context);\r\n return `${message}${componentInfo}`;\r\n}\r\n\r\n// ============================================================================\r\n// Warning & Error Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Error codes for documentation linking\r\n */\r\nexport enum ErrorCode\r\n{\r\n // Expression evaluation errors (1xx)\r\n EXPRESSION_EVAL_FAILED = 101,\r\n EXPRESSION_SYNTAX_ERROR = 102,\r\n EXPRESSION_UNDEFINED_VAR = 103,\r\n EXPRESSION_NULL_ACCESS = 104,\r\n\r\n // Script errors (2xx)\r\n SCRIPT_EXTRACT_FAILED = 201,\r\n SCRIPT_EXECUTION_FAILED = 202,\r\n\r\n // Event handler errors (3xx)\r\n EVENT_HANDLER_FAILED = 301,\r\n\r\n // Directive errors (4xx)\r\n DIRECTIVE_ERROR = 401,\r\n LOOP_ERROR = 402,\r\n CONDITIONAL_ERROR = 403,\r\n\r\n // Component errors (5xx)\r\n COMPONENT_LOAD_FAILED = 501,\r\n COMPONENT_NOT_FOUND = 502,\r\n COMPONENT_ALREADY_REGISTERED = 503,\r\n INVALID_COMPONENT_PATH = 504,\r\n COMPONENT_REGISTRATION_FAILED = 505,\r\n INVALID_COMPONENT_NAME = 506,\r\n\r\n // Module errors (6xx)\r\n MODULE_LOAD_FAILED = 601,\r\n MODULE_EXECUTION_FAILED = 602,\r\n}\r\n\r\n/**\r\n * Get documentation URL for an error code\r\n */\r\nexport function getErrorDocsUrl(code: ErrorCode): string\r\n{\r\n return `${DOCS_BASE_URL}#ljs${code}`;\r\n}\r\n\r\nfunction formatErrorCode(code: ErrorCode): string\r\n{\r\n return `LJS${code}`;\r\n}\r\n\r\nexport interface DiagnosticDetails\r\n{\r\n /** Stable code that links this diagnostic to the error reference. */\r\n code: ErrorCode;\r\n /** A concise, concrete action the developer can take. */\r\n hint?: string;\r\n}\r\n\r\nexport class LadrillosError extends Error\r\n{\r\n readonly code: ErrorCode;\r\n readonly docsUrl: string;\r\n readonly componentContext: ComponentContext | null;\r\n readonly hint?: string;\r\n\r\n constructor(\r\n message: string,\r\n code: ErrorCode,\r\n options: {\r\n context?: ComponentContext | null;\r\n hint?: string;\r\n cause?: unknown;\r\n } = {},\r\n )\r\n {\r\n const docsUrl = getErrorDocsUrl(code);\r\n super(\r\n `[${formatErrorCode(code)}] ${formatMessage(message, options.context)} See ${docsUrl}`,\r\n options.cause !== undefined ? { cause: options.cause } : undefined,\r\n );\r\n this.name = \"LadrillosError\";\r\n this.code = code;\r\n this.docsUrl = docsUrl;\r\n this.componentContext = options.context ?? null;\r\n this.hint = options.hint;\r\n }\r\n}\r\n\r\nfunction formatDiagnostic(\r\n message: string,\r\n context: ComponentContext | null | undefined,\r\n details: DiagnosticDetails,\r\n): string\r\n{\r\n const lines = [\r\n `[${formatErrorCode(details.code)}] ${formatMessage(message, context)}`,\r\n ];\r\n\r\n if (details.hint)\r\n {\r\n lines.push(` How to fix: ${details.hint}`);\r\n }\r\n\r\n lines.push(` Learn more: ${getErrorDocsUrl(details.code)}`);\r\n return lines.join(\"\\n\");\r\n}\r\n\r\n// ============================================================================\r\n// Custom Error Handler\r\n// ============================================================================\r\n\r\n/**\r\n * Custom error handler signature. If registered via `configure({ onError })`,\r\n * framework errors are forwarded here in addition to being logged.\r\n */\r\nexport type LadrillosErrorHandler = (\r\n error: Error,\r\n context?: ComponentContext | null,\r\n) => void;\r\n\r\nlet customErrorHandler: LadrillosErrorHandler | null = null;\r\n\r\n/**\r\n * Register (or clear) a custom error handler. Called by `configure()`.\r\n * Pass `null` to remove.\r\n */\r\nexport function setErrorHandler(handler: LadrillosErrorHandler | null): void\r\n{\r\n customErrorHandler = handler;\r\n}\r\n\r\n/**\r\n * Dispatch an error through the custom handler (if registered). Swallows\r\n * handler errors to avoid recursive failures.\r\n */\r\nfunction dispatchError(err: unknown, context?: ComponentContext | null): void\r\n{\r\n if (!customErrorHandler) return;\r\n try\r\n {\r\n const errorObj = err instanceof Error ? err : new Error(String(err));\r\n customErrorHandler(errorObj, context ?? null);\r\n } catch\r\n {\r\n /* swallow */\r\n }\r\n}\r\n\r\n/**\r\n * Log a styled warning message (dev mode only).\r\n * Includes component context if available.\r\n */\r\nexport function warn(\r\n message: string,\r\n context?: ComponentContext | null,\r\n details?: DiagnosticDetails,\r\n): void\r\n{\r\n if (!IS_DEV) return;\r\n\r\n const fullMessage = details\r\n ? formatDiagnostic(message, context, details)\r\n : formatMessage(message, context);\r\n\r\n if (supportsStyledConsole())\r\n {\r\n console.warn(`%c${PREFIX}%c ${fullMessage}`, styles.prefix, styles.reset);\r\n } else\r\n {\r\n console.warn(`${PREFIX} ${fullMessage}`);\r\n }\r\n}\r\n\r\n/**\r\n * Log a styled error message.\r\n * Errors are always logged, even in production.\r\n *\r\n * If a custom error handler is registered via `configure({ onError })`, it is\r\n * also invoked so embedders can route framework errors to telemetry.\r\n */\r\nexport function error(\r\n message: string,\r\n context?: ComponentContext | null,\r\n cause?: unknown,\r\n details?: DiagnosticDetails,\r\n): void\r\n{\r\n const fullMessage = details\r\n ? IS_DEV\r\n ? formatDiagnostic(message, context, details)\r\n : `[${formatErrorCode(details.code)}] ${formatMessage(message, context)} See ${getErrorDocsUrl(details.code)}`\r\n : formatMessage(message, context);\r\n\r\n if (supportsStyledConsole())\r\n {\r\n console.error(`%c${PREFIX}%c ${fullMessage}`, styles.prefix, styles.reset);\r\n } else\r\n {\r\n console.error(`${PREFIX} ${fullMessage}`);\r\n }\r\n\r\n if (cause !== undefined && typeof console !== \"undefined\")\r\n {\r\n console.error(cause);\r\n }\r\n\r\n const errorObj = details\r\n ? new LadrillosError(message, details.code, {\r\n context,\r\n hint: details.hint,\r\n cause,\r\n })\r\n : cause instanceof Error\r\n ? cause\r\n : new Error(fullMessage, cause !== undefined ? { cause } : undefined);\r\n dispatchError(errorObj, context);\r\n}\r\n\r\n/**\r\n * Log an expression evaluation error with detailed context.\r\n *\r\n * This is the main function for reporting binding/expression errors.\r\n * It shows:\r\n * - The expression that failed\r\n * - The component where it occurred\r\n * - The actual JavaScript error\r\n * - A code frame if template source is available\r\n */\r\nexport function expressionError(\r\n expression: string,\r\n originalError: Error,\r\n options: {\r\n context?: ComponentContext | null;\r\n template?: string;\r\n errorCode?: ErrorCode;\r\n } = {},\r\n): void\r\n{\r\n const ctx =\r\n options.context !== undefined ? options.context : currentContext;\r\n const code = options.errorCode || inferErrorCode(originalError);\r\n\r\n // Determine error type for better messaging\r\n const errorType = getErrorType(originalError);\r\n\r\n if (!IS_DEV)\r\n {\r\n // Production: minimal output with docs link\r\n console.warn(`${PREFIX} Expression warning. See: ${getErrorDocsUrl(code)}`);\r\n dispatchError(\r\n new LadrillosError(errorType, code, { context: ctx, cause: originalError }),\r\n ctx,\r\n );\r\n return;\r\n }\r\n\r\n // Build the error message\r\n const componentInfo = formatComponentInfo(ctx);\r\n\r\n if (supportsStyledConsole())\r\n {\r\n // Styled browser output\r\n console.groupCollapsed(\r\n `%c${PREFIX}%c ${errorType}%c${componentInfo}`,\r\n styles.prefix,\r\n styles.error,\r\n styles.dim,\r\n );\r\n\r\n console.log(`%cExpression:%c ${expression}`, styles.dim, styles.expression);\r\n\r\n if (ctx?.tagName)\r\n {\r\n console.log(\r\n `%cComponent:%c <${ctx.tagName}>`,\r\n styles.dim,\r\n styles.component,\r\n );\r\n }\r\n\r\n if (ctx?.sourcePath)\r\n {\r\n console.log(`%cFile:%c ${ctx.sourcePath}`, styles.dim, styles.file);\r\n }\r\n\r\n // Show code frame if template is available\r\n if (options.template)\r\n {\r\n const position = findExpressionPosition(options.template, expression);\r\n if (position)\r\n {\r\n console.log(`%cLocation in template:%c`, styles.dim, styles.reset);\r\n console.log(\r\n generateCodeFrame(options.template, position.start, position.end),\r\n );\r\n }\r\n }\r\n\r\n console.log(\r\n `%cError:%c ${originalError.message}`,\r\n styles.dim,\r\n styles.reset,\r\n );\r\n console.log(`%cDocs:%c ${getErrorDocsUrl(code)}`, styles.dim, styles.file);\r\n\r\n console.groupEnd();\r\n } else\r\n {\r\n // Plain text output (Node.js or unstyled console)\r\n const lines = [\r\n `${PREFIX} ${errorType}${componentInfo}`,\r\n ` Expression: ${expression}`,\r\n ];\r\n\r\n if (ctx?.tagName)\r\n {\r\n lines.push(` Component: <${ctx.tagName}>`);\r\n }\r\n\r\n if (ctx?.sourcePath)\r\n {\r\n lines.push(` File: ${ctx.sourcePath}`);\r\n }\r\n\r\n if (options.template)\r\n {\r\n const position = findExpressionPosition(options.template, expression);\r\n if (position)\r\n {\r\n lines.push(` Location:`);\r\n lines.push(\r\n generateCodeFrame(options.template, position.start, position.end)\r\n .split(\"\\n\")\r\n .map((l) => ` ${l}`)\r\n .join(\"\\n\"),\r\n );\r\n }\r\n }\r\n\r\n lines.push(` Error: ${originalError.message}`);\r\n lines.push(` Docs: ${getErrorDocsUrl(code)}`);\r\n\r\n console.warn(lines.join(\"\\n\"));\r\n }\r\n\r\n dispatchError(\r\n new LadrillosError(errorType, code, { context: ctx, cause: originalError }),\r\n ctx,\r\n );\r\n}\r\n\r\n/**\r\n * Log a script extraction error with context.\r\n */\r\nexport function scriptError(\r\n message: string,\r\n originalError: Error,\r\n context?: ComponentContext | null,\r\n): void\r\n{\r\n const ctx = context !== undefined ? context : currentContext;\r\n const diagnostic = new LadrillosError(\r\n message,\r\n ErrorCode.SCRIPT_EXTRACT_FAILED,\r\n { context: ctx, cause: originalError },\r\n );\r\n\r\n if (!IS_DEV)\r\n {\r\n console.error(\r\n `${PREFIX} Script error. See: ${getErrorDocsUrl(\r\n ErrorCode.SCRIPT_EXTRACT_FAILED,\r\n )}`,\r\n );\r\n dispatchError(diagnostic, ctx);\r\n return;\r\n }\r\n\r\n const componentInfo = formatComponentInfo(ctx);\r\n\r\n if (supportsStyledConsole())\r\n {\r\n console.group(\r\n `%c${PREFIX}%c Script Error%c${componentInfo}`,\r\n styles.prefix,\r\n styles.error,\r\n styles.dim,\r\n );\r\n\r\n console.log(`%cMessage:%c ${message}`, styles.dim, styles.reset);\r\n\r\n if (ctx?.tagName)\r\n {\r\n console.log(\r\n `%cComponent:%c <${ctx.tagName}>`,\r\n styles.dim,\r\n styles.component,\r\n );\r\n }\r\n\r\n if (ctx?.sourcePath)\r\n {\r\n console.log(`%cFile:%c ${ctx.sourcePath}`, styles.dim, styles.file);\r\n }\r\n\r\n console.log(`%cError:%c`, styles.dim, styles.reset, originalError);\r\n\r\n console.groupEnd();\r\n } else\r\n {\r\n const lines = [\r\n `${PREFIX} Script Error${componentInfo}`,\r\n ` Message: ${message}`,\r\n ];\r\n\r\n if (ctx?.tagName)\r\n {\r\n lines.push(` Component: <${ctx.tagName}>`);\r\n }\r\n\r\n if (ctx?.sourcePath)\r\n {\r\n lines.push(` File: ${ctx.sourcePath}`);\r\n }\r\n\r\n lines.push(` Error: ${originalError.message}`);\r\n\r\n console.error(lines.join(\"\\n\"));\r\n }\r\n\r\n dispatchError(diagnostic, ctx);\r\n}\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Infer error code from the error type\r\n */\r\nfunction inferErrorCode(err: Error): ErrorCode\r\n{\r\n if (err instanceof SyntaxError)\r\n {\r\n return ErrorCode.EXPRESSION_SYNTAX_ERROR;\r\n }\r\n\r\n if (err instanceof ReferenceError)\r\n {\r\n return ErrorCode.EXPRESSION_UNDEFINED_VAR;\r\n }\r\n\r\n if (err instanceof TypeError)\r\n {\r\n // Check if it's a null/undefined property access\r\n if (\r\n err.message.includes(\"Cannot read properties of null\") ||\r\n err.message.includes(\"Cannot read properties of undefined\")\r\n )\r\n {\r\n return ErrorCode.EXPRESSION_NULL_ACCESS;\r\n }\r\n }\r\n\r\n return ErrorCode.EXPRESSION_EVAL_FAILED;\r\n}\r\n\r\n/**\r\n * Get a human-readable error type description\r\n */\r\nfunction getErrorType(err: Error): string\r\n{\r\n if (err instanceof SyntaxError)\r\n {\r\n return \"Invalid expression syntax\";\r\n }\r\n\r\n if (err instanceof ReferenceError)\r\n {\r\n // Extract the undefined variable name if possible\r\n const match = err.message.match(/(\\w+) is not defined/);\r\n if (match)\r\n {\r\n return `Undefined variable: \"${match[1]}\"`;\r\n }\r\n return \"Undefined variable\";\r\n }\r\n\r\n if (err instanceof TypeError)\r\n {\r\n if (err.message.includes(\"Cannot read properties of null\"))\r\n {\r\n return \"Cannot access property of null\";\r\n }\r\n if (err.message.includes(\"Cannot read properties of undefined\"))\r\n {\r\n return \"Cannot access property of undefined\";\r\n }\r\n return \"Type error\";\r\n }\r\n\r\n return \"Expression evaluation failed\";\r\n}\r\n\r\n/**\r\n * Create a formatted error for throwing with component context.\r\n */\r\nexport function createError(\r\n message: string,\r\n code: ErrorCode,\r\n context?: ComponentContext | null,\r\n hint?: string,\r\n cause?: unknown,\r\n): LadrillosError\r\n{\r\n const ctx = context !== undefined ? context : currentContext;\r\n return new LadrillosError(message, code, { context: ctx, hint, cause });\r\n}\r\n\r\n// ============================================================================\r\n// Deprecation Warnings\r\n// ============================================================================\r\n\r\nconst deprecationWarnings = new Set<string>();\r\n\r\n/**\r\n * Log a deprecation warning (only once per feature).\r\n */\r\nexport function deprecate(\r\n feature: string,\r\n replacement?: string,\r\n version?: string,\r\n): void\r\n{\r\n if (!IS_DEV) return;\r\n\r\n // Only warn once per feature\r\n if (deprecationWarnings.has(feature)) return;\r\n deprecationWarnings.add(feature);\r\n\r\n let message = `\"${feature}\" is deprecated`;\r\n\r\n if (version)\r\n {\r\n message += ` and will be removed in version ${version}`;\r\n }\r\n\r\n if (replacement)\r\n {\r\n message += `. Use \"${replacement}\" instead`;\r\n }\r\n\r\n message += \".\";\r\n\r\n if (supportsStyledConsole())\r\n {\r\n console.warn(\r\n `%c${PREFIX}%c ⚠️ Deprecation: ${message}`,\r\n styles.prefix,\r\n \"color: #ff9800\",\r\n );\r\n } else\r\n {\r\n console.warn(`${PREFIX} ⚠️ Deprecation: ${message}`);\r\n }\r\n}\r\n","import { ScriptElement, ExternalScriptElement } from \"../../types\";\r\nimport {\r\n frameworkHelperNames,\r\n createFrameworkHelpers,\r\n} from \"../helpers/frameworkHelpers\";\r\nimport { eventBusHelperNames, createEventBusHelpers } from \"../events/eventBus\";\r\nimport { createReactiveArray } from \"./reactivity\";\r\nimport { transformCodeToStateAccess } from \"../../utils/stateTransform\";\r\nimport {\r\n error,\r\n scriptError,\r\n getComponentContext,\r\n ErrorCode,\r\n} from \"../../utils/devWarnings\";\r\n\r\n/**\r\n * Executes module scripts at runtime with REACTIVITY support.\r\n *\r\n * Key features:\r\n * 1. Rewrites relative imports to absolute URLs\r\n * 2. Fetches and resolves ES module imports\r\n * 3. Extracts declared variables for reactive state integration\r\n * 4. Supports both side-effect execution AND variable extraction\r\n * 5. Wraps imported arrays in reactive proxies for automatic UI updates\r\n *\r\n * This allows <script type=\"module\"> in components to:\r\n * - Import from other files\r\n * - Declare reactive variables (let name = \"value\")\r\n * - Import arrays that automatically trigger UI updates on mutation\r\n * - Work the same as regular scripts for template bindings\r\n *\r\n * @example\r\n * ```html\r\n * <script type=\"module\">\r\n * import { links } from \"./links.js\";\r\n * let name = \"Header\"; // This becomes reactive state!\r\n * console.log(links);\r\n * </script>\r\n * ```\r\n */\r\n\r\n// Track created blob URLs for cleanup\r\nconst blobUrlRegistry = new Map<string, string[]>();\r\n\r\n// Cache for fetched modules to avoid duplicate requests\r\nconst moduleCache = new Map<string, Promise<Record<string, unknown>>>();\r\n\r\n/**\r\n * Regex patterns for import/export statements\r\n * Handles various forms:\r\n * import { x } from \"./file.js\"\r\n * import x from './file.js'\r\n * import \"./side-effect.js\"\r\n * export { x } from \"./file.js\"\r\n * const x = await import(\"./dynamic.js\")\r\n */\r\nconst STATIC_IMPORT_REGEX =\r\n /(?:import|export)\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\r\nconst DYNAMIC_IMPORT_REGEX = /import\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\r\n\r\n/**\r\n * TypeScript file extensions that need transpilation\r\n */\r\nconst TS_EXTENSIONS = [\".ts\", \".tsx\", \".mts\"];\r\n\r\n/**\r\n * Checks if a path is relative (starts with ./ or ../)\r\n */\r\nfunction isRelativePath(path: string): boolean {\r\n return path.startsWith(\"./\") || path.startsWith(\"../\");\r\n}\r\n\r\n/**\r\n * Checks if a path points to a TypeScript file\r\n */\r\nfunction isTypeScriptFile(path: string): boolean {\r\n return TS_EXTENSIONS.some((ext) => path.endsWith(ext));\r\n}\r\n\r\n/**\r\n * Checks if a path is a bare specifier (npm package)\r\n * These need special handling - they won't work without a bundler or import map\r\n */\r\nfunction isBareSpecifier(path: string): boolean {\r\n return (\r\n !path.startsWith(\"/\") &&\r\n !path.startsWith(\"./\") &&\r\n !path.startsWith(\"../\") &&\r\n !path.startsWith(\"http://\") &&\r\n !path.startsWith(\"https://\") &&\r\n !path.startsWith(\"data:\") &&\r\n !path.startsWith(\"blob:\")\r\n );\r\n}\r\n\r\n/**\r\n * Rewrites relative imports in module code to absolute URLs.\r\n *\r\n * NOTE: When using a dev server like Vite, TypeScript imports work because\r\n * the server transpiles .ts files on-the-fly. Without a dev server, you need\r\n * to use .js files or pre-compile your TypeScript.\r\n *\r\n * @param code - The module script content\r\n * @param baseUrl - The URL to resolve relative paths against (component's URL)\r\n * @returns The code with rewritten imports\r\n */\r\nexport function rewriteImports(code: string, baseUrl: string): string {\r\n let result = code;\r\n\r\n // Track issues for warnings\r\n const bareSpecifiers: string[] = [];\r\n const tsImports: string[] = [];\r\n\r\n // Rewrite static imports/exports\r\n result = result.replace(STATIC_IMPORT_REGEX, (match, importPath) => {\r\n if (isRelativePath(importPath)) {\r\n const absoluteUrl = new URL(importPath, baseUrl).href;\r\n if (isTypeScriptFile(importPath)) {\r\n tsImports.push(importPath);\r\n }\r\n return match.replace(importPath, absoluteUrl);\r\n }\r\n if (isBareSpecifier(importPath)) {\r\n bareSpecifiers.push(importPath);\r\n }\r\n return match;\r\n });\r\n\r\n // Rewrite dynamic imports\r\n result = result.replace(DYNAMIC_IMPORT_REGEX, (match, importPath) => {\r\n if (isRelativePath(importPath)) {\r\n const absoluteUrl = new URL(importPath, baseUrl).href;\r\n if (isTypeScriptFile(importPath)) {\r\n tsImports.push(importPath);\r\n }\r\n return `import(\"${absoluteUrl}\")`;\r\n }\r\n if (isBareSpecifier(importPath)) {\r\n bareSpecifiers.push(importPath);\r\n }\r\n return match;\r\n });\r\n\r\n // Warn about TypeScript imports (they work with dev servers like Vite, but not in plain browser)\r\n if (tsImports.length > 0) {\r\n console.info(\r\n `[LadrillosJS] TypeScript imports detected: ${tsImports.join(\", \")}. ` +\r\n `These work with dev servers (Vite, etc.) that transpile on-the-fly. ` +\r\n `For production without a bundler, use .js files.`,\r\n );\r\n }\r\n\r\n // Warn about bare specifiers\r\n if (bareSpecifiers.length > 0) {\r\n console.warn(\r\n `[LadrillosJS] Bare import specifiers found: ${bareSpecifiers.join(\r\n \", \",\r\n )}. ` +\r\n `These require an import map, bundler, or CDN URL to work at runtime.`,\r\n );\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Creates a blob URL from module code.\r\n * The blob URL can be dynamically imported.\r\n */\r\nfunction createModuleBlobUrl(code: string): string {\r\n const blob = new Blob([code], { type: \"text/javascript\" });\r\n return URL.createObjectURL(blob);\r\n}\r\n\r\n/**\r\n * Executes a single inline module script.\r\n *\r\n * @param script - The script element containing module code\r\n * @param componentUrl - The component's URL for resolving relative imports\r\n * @param componentId - Unique ID for tracking blob URLs\r\n * @returns Promise that resolves when the module has executed\r\n */\r\nexport async function executeModuleScript(\r\n script: ScriptElement,\r\n componentUrl: string,\r\n componentId?: string,\r\n): Promise<unknown> {\r\n if (script.type !== \"module\") {\r\n throw new Error('executeModuleScript only handles type=\"module\" scripts');\r\n }\r\n\r\n // Rewrite relative imports to absolute URLs\r\n const rewrittenCode = rewriteImports(script.content, componentUrl);\r\n\r\n // Create a blob URL for the rewritten module\r\n const blobUrl = createModuleBlobUrl(rewrittenCode);\r\n\r\n // Track for cleanup\r\n if (componentId) {\r\n const urls = blobUrlRegistry.get(componentId) || [];\r\n urls.push(blobUrl);\r\n blobUrlRegistry.set(componentId, urls);\r\n }\r\n\r\n try {\r\n // Dynamically import the module\r\n // Using a comment to prevent bundlers from trying to resolve this\r\n const moduleExports = await (0, eval)(`import(\"${blobUrl}\")`);\r\n return moduleExports;\r\n } catch (err) {\r\n scriptError(\r\n \"Failed to execute module script\",\r\n err as Error,\r\n getComponentContext() || { sourcePath: componentUrl },\r\n );\r\n throw err;\r\n }\r\n}\r\n\r\n/**\r\n * Regex to extract top-level variable declarations from module code.\r\n * Matches: let x, const y, var z (with optional = assignment)\r\n * Does NOT match declarations inside functions/blocks.\r\n */\r\nconst TOP_LEVEL_VAR_REGEX =\r\n /^(?:export\\s+)?(?:let|const|var)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/gm;\r\n\r\n/**\r\n * Extracts top-level variable names from module code.\r\n * Used to auto-export all declarations\r\n */\r\nfunction extractTopLevelVariables(code: string): string[] {\r\n const variables: string[] = [];\r\n let match;\r\n\r\n // Reset regex state\r\n TOP_LEVEL_VAR_REGEX.lastIndex = 0;\r\n\r\n while ((match = TOP_LEVEL_VAR_REGEX.exec(code)) !== null) {\r\n variables.push(match[1]);\r\n }\r\n\r\n // Also extract function declarations: function foo() {}\r\n const funcRegex = /^(?:export\\s+)?function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/gm;\r\n while ((match = funcRegex.exec(code)) !== null) {\r\n if (!variables.includes(match[1])) {\r\n variables.push(match[1]);\r\n }\r\n }\r\n\r\n return variables;\r\n}\r\n\r\n/**\r\n * Transforms module code to export all top-level declarations.\r\n * This enable \"no export needed\" behavior.\r\n *\r\n * Example:\r\n * const suggestionItems = ['a', 'b'];\r\n * Becomes:\r\n * const suggestionItems = ['a', 'b'];\r\n * export { suggestionItems }; // Auto-added\r\n */\r\nfunction autoExportAllDeclarations(code: string): string {\r\n const variables = extractTopLevelVariables(code);\r\n\r\n // Filter out variables that are already exported\r\n const alreadyExported = new Set<string>();\r\n const exportRegex =\r\n /export\\s+(?:let|const|var|function)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;\r\n let match;\r\n while ((match = exportRegex.exec(code)) !== null) {\r\n alreadyExported.add(match[1]);\r\n }\r\n\r\n // Also check for `export { x, y }` style exports\r\n const namedExportRegex = /export\\s*\\{([^}]+)\\}/g;\r\n while ((match = namedExportRegex.exec(code)) !== null) {\r\n const names = match[1].split(\",\").map((n) =>\r\n n\r\n .trim()\r\n .split(/\\s+as\\s+/)[0]\r\n .trim(),\r\n );\r\n names.forEach((n) => alreadyExported.add(n));\r\n }\r\n\r\n const toExport = variables.filter((v) => !alreadyExported.has(v));\r\n\r\n if (toExport.length === 0) {\r\n return code;\r\n }\r\n\r\n // Add export statement at the end\r\n return `${code}\\nexport { ${toExport.join(\", \")} };`;\r\n}\r\n\r\n/**\r\n * Transforms import statements to wrap imported values in reactive proxies.\r\n * This enables imported arrays to trigger UI updates when mutated.\r\n *\r\n * Transforms:\r\n * import { foo, bar } from \"./module.js\";\r\n *\r\n * Into:\r\n * import { foo as __raw_foo, bar as __raw_bar } from \"./module.js\";\r\n * const foo = __wrapReactiveArray(__raw_foo, __ladrillos_componentId, \"foo\");\r\n * const bar = __wrapReactiveArray(__raw_bar, __ladrillos_componentId, \"bar\");\r\n *\r\n * @param code - The module code with imports\r\n * @returns Transformed code with reactive import wrapping\r\n *\r\n * Exported for tests (the blob-URL execution path can't run under Node).\r\n */\r\nexport function transformImportsForReactivity(code: string): string {\r\n // Match named imports: import { a, b as c } from \"...\"\r\n const namedImportRegex =\r\n /import\\s*\\{([^}]+)\\}\\s*from\\s*(['\"][^'\"]+['\"])\\s*;?/g;\r\n\r\n const wrapperStatements: string[] = [];\r\n let transformedCode = code;\r\n\r\n transformedCode = transformedCode.replace(\r\n namedImportRegex,\r\n (match, imports: string, specifier: string) => {\r\n const importList = imports.split(\",\").map((s) => s.trim());\r\n const newImports: string[] = [];\r\n\r\n for (const imp of importList) {\r\n if (!imp) continue;\r\n\r\n // Handle \"foo as bar\" syntax\r\n const asMatch = imp.match(/^(\\w+)\\s+as\\s+(\\w+)$/);\r\n if (asMatch) {\r\n const [, imported, local] = asMatch;\r\n const rawName = `__raw_${local}`;\r\n newImports.push(`${imported} as ${rawName}`);\r\n wrapperStatements.push(\r\n `const ${local} = __wrapReactiveArray(${rawName}, __ladrillos_componentId, \"${local}\");`,\r\n );\r\n } else {\r\n // Simple import \"foo\"\r\n const rawName = `__raw_${imp}`;\r\n newImports.push(`${imp} as ${rawName}`);\r\n wrapperStatements.push(\r\n `const ${imp} = __wrapReactiveArray(${rawName}, __ladrillos_componentId, \"${imp}\");`,\r\n );\r\n }\r\n }\r\n\r\n return `import { ${newImports.join(\", \")} } from ${specifier};`;\r\n },\r\n );\r\n\r\n // Insert wrapper statements after imports but before other code\r\n if (wrapperStatements.length > 0) {\r\n // Find the end of import statements\r\n const lines = transformedCode.split(\"\\n\");\r\n let lastImportIndex = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i].trim();\r\n if (line.startsWith(\"import \") || line.startsWith(\"import{\")) {\r\n lastImportIndex = i;\r\n }\r\n }\r\n\r\n if (lastImportIndex >= 0) {\r\n lines.splice(\r\n lastImportIndex + 1,\r\n 0,\r\n \"\",\r\n \"// === Reactive Import Wrappers ===\",\r\n ...wrapperStatements,\r\n \"// === End Reactive Import Wrappers ===\",\r\n \"\",\r\n );\r\n transformedCode = lines.join(\"\\n\");\r\n }\r\n }\r\n\r\n return transformedCode;\r\n}\r\n\r\n/**\r\n * Generates JavaScript code that defines the framework helpers ($emit, $listen, etc.)\r\n * as module-level constants. This code is prepended to external module scripts\r\n * so they have access to the same helpers as inline scripts.\r\n *\r\n * @param componentId - Component ID for event bus cleanup\r\n * @param componentUrl - Component URL for path resolution\r\n * @returns JavaScript code string to prepend\r\n */\r\nconst INJECTABLE_HELPER_NAMES = [\r\n \"$emit\",\r\n \"$listen\",\r\n \"$refs\",\r\n \"registerComponent\",\r\n \"registerComponents\",\r\n \"$use\",\r\n] as const;\r\n\r\n/**\r\n * Scans module code for top-level declarations or imports whose names would\r\n * collide with framework helpers we plan to inject. Returns the set of\r\n * colliding names so the caller can skip those injected declarations.\r\n */\r\nfunction detectHelperCollisions(code: string): Set<string> {\r\n const found = new Set<string>();\r\n for (const name of INJECTABLE_HELPER_NAMES) {\r\n // Match: import { name } / import { name as x } / import name from\r\n // let/const/var name / function name(\r\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n const pattern = new RegExp(\r\n `(?:^|[\\\\s,{])${escaped}(?:\\\\s+as\\\\b|[\\\\s,}=;(])|` +\r\n `\\\\b(?:let|const|var|function)\\\\s+${escaped}\\\\b`,\r\n \"m\",\r\n );\r\n if (pattern.test(code)) found.add(name);\r\n }\r\n return found;\r\n}\r\n\r\n// Exported for tests (the blob-URL execution path can't run under Node).\r\nexport function generateHelperInjectionCode(\r\n componentId?: string,\r\n componentUrl?: string,\r\n exclude: ReadonlySet<string> = new Set(),\r\n): string {\r\n const id = componentId || \"anonymous\";\r\n const url = componentUrl || \"unknown\";\r\n\r\n // Helper to conditionally include a `const NAME = ...;` declaration only\r\n // when the surrounding module hasn't already declared/imported NAME.\r\n const decl = (name: string, source: string) =>\r\n exclude.has(name) ? \"\" : source; // We need to inline the event bus logic since external modules can't access our closures.\r\n // This creates standalone $emit and $listen functions that use a global event bus.\r\n // Also includes reactive array wrapping for imported arrays.\r\n return `\r\n// === LadrillosJS Framework Helpers (auto-injected) ===\r\nconst __ladrillos_componentId = \"${id}\";\r\nconst __ladrillos_componentUrl = \"${url}\";\r\n\r\n// Global event bus (shared across all components)\r\nif (!globalThis.__ladrillosEventBus) {\r\n globalThis.__ladrillosEventBus = {\r\n listeners: new Map(),\r\n componentListeners: new Map()\r\n };\r\n}\r\n\r\n// Global state change callbacks (for reactive array updates)\r\nif (!globalThis.__ladrillosStateCallbacks) {\r\n globalThis.__ladrillosStateCallbacks = new Map();\r\n}\r\n\r\n// Reactive array symbol\r\nconst __REACTIVE_ARRAY = Symbol.for(\"ladrillos-reactive-array\");\r\n\r\n// Array mutation methods to intercept\r\nconst __ARRAY_METHODS = [\"push\", \"pop\", \"shift\", \"unshift\", \"splice\", \"sort\", \"reverse\", \"fill\", \"copyWithin\"];\r\n\r\n// Wrap an array in a reactive proxy. stateKey is the local binding name the\r\n// array is exported/merged into component state under; passing it to the\r\n// component's callback lets mutations refresh the text/attribute bindings\r\n// that depend on that key (not just directives).\r\nconst __wrapReactiveArray = (arr, componentId, stateKey) => {\r\n if (!Array.isArray(arr) || arr[__REACTIVE_ARRAY]) return arr;\r\n\r\n const onMutate = () => {\r\n const callback = globalThis.__ladrillosStateCallbacks?.get(componentId);\r\n if (callback) callback(stateKey);\r\n };\r\n\r\n return new Proxy(arr, {\r\n get(target, key) {\r\n if (key === __REACTIVE_ARRAY) return true;\r\n const value = target[key];\r\n if (typeof key === \"string\" && __ARRAY_METHODS.includes(key) && typeof value === \"function\") {\r\n return (...args) => {\r\n const result = value.apply(target, args);\r\n onMutate();\r\n return result;\r\n };\r\n }\r\n if (Array.isArray(value)) return __wrapReactiveArray(value, componentId, stateKey);\r\n return value;\r\n },\r\n set(target, key, value) {\r\n const index = parseInt(key, 10);\r\n const isIndex = !isNaN(index);\r\n const isLength = key === \"length\";\r\n target[key] = Array.isArray(value) ? __wrapReactiveArray(value, componentId, stateKey) : value;\r\n if (isIndex || isLength) onMutate();\r\n return true;\r\n }\r\n });\r\n};\r\n\r\nconst __ladrillos_emit = (eventName, data) => {\r\n const listeners = globalThis.__ladrillosEventBus.listeners.get(eventName);\r\n if (!listeners || listeners.size === 0) return;\r\n for (const registration of listeners) {\r\n try {\r\n registration.callback(data);\r\n } catch (error) {\r\n console.error(\\`[LadrillosJS] Error in event listener for \"\\${eventName}\":\\`, error);\r\n }\r\n }\r\n};\r\n${decl(\"$emit\", \"const $emit = __ladrillos_emit;\")}\r\n\r\nconst __ladrillos_listen = (eventName, callback) => {\r\n const bus = globalThis.__ladrillosEventBus;\r\n let listeners = bus.listeners.get(eventName);\r\n if (!listeners) {\r\n listeners = new Set();\r\n bus.listeners.set(eventName, listeners);\r\n }\r\n const registration = { callback, componentId: __ladrillos_componentId };\r\n listeners.add(registration);\r\n\r\n // Track by component ID for cleanup\r\n let componentRegs = bus.componentListeners.get(__ladrillos_componentId);\r\n if (!componentRegs) {\r\n componentRegs = new Set();\r\n bus.componentListeners.set(__ladrillos_componentId, componentRegs);\r\n }\r\n componentRegs.add({ event: eventName, registration });\r\n\r\n // Return unsubscribe function\r\n return () => {\r\n listeners?.delete(registration);\r\n if (listeners?.size === 0) bus.listeners.delete(eventName);\r\n const compRegs = bus.componentListeners.get(__ladrillos_componentId);\r\n if (compRegs) {\r\n for (const reg of compRegs) {\r\n if (reg.registration === registration) {\r\n compRegs.delete(reg);\r\n break;\r\n }\r\n }\r\n if (compRegs.size === 0) bus.componentListeners.delete(__ladrillos_componentId);\r\n }\r\n };\r\n};\r\n${decl(\"$listen\", \"const $listen = __ladrillos_listen;\")}\r\n\r\n// Global refs registry (shared across all components)\r\n// Each component gets its own Map, keyed by component ID\r\nif (!globalThis.__ladrillosRefs) {\r\n globalThis.__ladrillosRefs = new Map();\r\n}\r\n\r\n// Helper to wrap refs Map in Proxy for cleaner dot notation access\r\nconst __createRefsProxy = (map) => new Proxy(map, {\r\n get(target, prop, receiver) {\r\n if (prop in target) {\r\n const value = Reflect.get(target, prop, receiver);\r\n return typeof value === \"function\" ? value.bind(target) : value;\r\n }\r\n if (typeof prop === \"string\") return target.get(prop);\r\n return undefined;\r\n },\r\n set(target, prop, value) {\r\n if (typeof prop === \"string\") { target.set(prop, value); return true; }\r\n return false;\r\n },\r\n has(target, prop) {\r\n return typeof prop === \"string\" ? target.has(prop) || prop in target : prop in target;\r\n }\r\n});\r\n\r\n// Get or create refs Map for this component (wrapped in Proxy)\r\nif (!globalThis.__ladrillosRefs.has(__ladrillos_componentId)) {\r\n globalThis.__ladrillosRefs.set(__ladrillos_componentId, __createRefsProxy(new Map()));\r\n}\r\n\r\n// $refs for this component - supports both $refs.inputEl and $refs.get(\"inputEl\")\r\nconst __ladrillos_refs = globalThis.__ladrillosRefs.get(__ladrillos_componentId);\r\n${decl(\"$refs\", \"const $refs = __ladrillos_refs;\")}\r\n\r\n// Helper to resolve relative paths against component URL\r\nconst __resolvePath = (path) => {\r\n if (path.startsWith(\"http://\") || path.startsWith(\"https://\") || path.startsWith(\"/\")) {\r\n return path.startsWith(\"/\") ? new URL(path, window.location.origin).href : path;\r\n }\r\n return new URL(path, __ladrillos_componentUrl).href;\r\n};\r\n\r\n// Helper to convert filename to tag name\r\nconst __filenameToTagName = (path) => {\r\n const filename = path.split(\"/\").pop()?.replace(/\\\\.[^.]+$/, \"\") || path;\r\n return filename.replace(/([a-z])([A-Z])/g, \"$1-$2\").replace(/[_\\\\s]+/g, \"-\").toLowerCase();\r\n};\r\n\r\n// registerComponent - Register a child component\r\nconst __ladrillos_registerComponent = async (name, path, useShadowDOM = true) => {\r\n const resolvedPath = __resolvePath(path);\r\n return globalThis.ladrillosjs.registerComponent({ name, path: resolvedPath, useShadowDOM });\r\n};\r\n${decl(\"registerComponent\", \"const registerComponent = __ladrillos_registerComponent;\")}\r\n\r\n// registerComponents - Register multiple components at once\r\nconst __ladrillos_registerComponents = async (configs) => {\r\n const resolvedConfigs = configs.map(config => ({\r\n ...config,\r\n path: __resolvePath(config.path)\r\n }));\r\n return globalThis.ladrillosjs.registerComponents(resolvedConfigs);\r\n};\r\n${decl(\"registerComponents\", \"const registerComponents = __ladrillos_registerComponents;\")}\r\n\r\n// $use - Shorthand for registerComponent with auto-derived tag name\r\nconst __ladrillos_use = async (path, useShadowDOM = true) => {\r\n const tagName = __filenameToTagName(path);\r\n return __ladrillos_registerComponent(tagName, path, useShadowDOM);\r\n};\r\n${decl(\"$use\", \"const $use = __ladrillos_use;\")}\r\n\r\n// === End Framework Helpers ===\r\n\r\n`;\r\n}\r\n\r\n/**\r\n * Executes an external module script.\r\n * For external scripts, we fetch the content, auto-export all declarations,\r\n * and execute it via blob URL with injected framework helpers.\r\n *\r\n * If the script has the 'external' attribute, it's loaded as a plain\r\n * external script without any framework processing (no helpers, no auto-exports).\r\n *\r\n * @param script - The external script element\r\n * @param componentId - Optional component ID for event bus cleanup\r\n * @param componentUrl - Optional component URL for path resolution\r\n * @returns Promise that resolves with the module exports\r\n */\r\nexport async function executeExternalScript(\r\n script: ExternalScriptElement,\r\n componentId?: string,\r\n componentUrl?: string,\r\n): Promise<unknown> {\r\n // Scripts with 'external' attribute are loaded as plain scripts\r\n // without any framework processing (no helpers, no auto-exports, no reactivity)\r\n // This is useful for loading third-party libraries like highlight.js\r\n if (script.external) {\r\n // Check if this script is already loaded\r\n const existing = document.querySelector(`script[src=\"${script.src}\"]`);\r\n if (existing) return Promise.resolve(undefined);\r\n\r\n return new Promise((resolve, reject) => {\r\n const scriptEl = document.createElement(\"script\");\r\n scriptEl.src = script.src;\r\n if (script.type) {\r\n scriptEl.type = script.type;\r\n }\r\n scriptEl.onload = () => resolve(undefined);\r\n scriptEl.onerror = (e) =>\r\n reject(new Error(`Failed to load external script: ${script.src}`));\r\n document.head.appendChild(scriptEl);\r\n });\r\n }\r\n\r\n if (script.type !== \"module\") {\r\n // For non-module external scripts, create a script tag\r\n // Check if this script is already loaded\r\n const existing = document.querySelector(`script[src=\"${script.src}\"]`);\r\n if (existing) return Promise.resolve(undefined);\r\n\r\n return new Promise((resolve, reject) => {\r\n const scriptEl = document.createElement(\"script\");\r\n scriptEl.src = script.src;\r\n if (script.type) {\r\n scriptEl.type = script.type;\r\n }\r\n scriptEl.onload = () => resolve(undefined);\r\n scriptEl.onerror = (e) =>\r\n reject(new Error(`Failed to load script: ${script.src}`));\r\n document.head.appendChild(scriptEl);\r\n });\r\n }\r\n\r\n try {\r\n // Fetch the module content\r\n const response = await fetch(script.src);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch module: ${script.src}`);\r\n }\r\n const code = await response.text();\r\n\r\n // Rewrite relative imports to absolute URLs (based on script's location)\r\n const rewrittenCode = rewriteImports(code, script.src);\r\n\r\n // Transform imports to wrap values in reactive proxies\r\n const reactiveCode = transformImportsForReactivity(rewrittenCode);\r\n\r\n // Auto-export all top-level declarations\r\n const exportedCode = autoExportAllDeclarations(reactiveCode);\r\n\r\n // Inject framework helpers at the top of the module.\r\n // If the fetched module already declares (e.g. via import) any of the\r\n // helper names we plan to inject, skip injecting those names to avoid\r\n // \"Identifier 'X' has already been declared\" SyntaxErrors.\r\n const collisions = detectHelperCollisions(rewrittenCode);\r\n const helpersCode = generateHelperInjectionCode(\r\n componentId,\r\n componentUrl || script.src,\r\n collisions,\r\n );\r\n const finalCode = helpersCode + exportedCode;\r\n\r\n // Create blob URL and import\r\n const blob = new Blob([finalCode], { type: \"text/javascript\" });\r\n const blobUrl = URL.createObjectURL(blob);\r\n\r\n try {\r\n const moduleExports = await (0, eval)(`import(\"${blobUrl}\")`);\r\n return moduleExports;\r\n } finally {\r\n // Clean up blob URL\r\n URL.revokeObjectURL(blobUrl);\r\n }\r\n } catch (error) {\r\n console.error(\r\n `[LadrillosJS] Failed to load external module: ${script.src}`,\r\n error,\r\n );\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Loads external scripts marked with the 'external' attribute.\r\n * These are third-party libraries (like highlight.js) that need to be loaded\r\n * BEFORE the component's inline scripts run, since they may depend on globals\r\n * provided by these libraries.\r\n *\r\n * @param externalScripts - External scripts from the component\r\n * @returns Promise that resolves when all external scripts are loaded\r\n */\r\nexport async function loadPlainExternalScripts(\r\n externalScripts: ExternalScriptElement[],\r\n): Promise<void> {\r\n // Filter to only scripts with the 'external' attribute\r\n const plainExternalScripts = externalScripts.filter((s) => s.external);\r\n\r\n // Load them sequentially to maintain order (some may depend on others)\r\n for (const script of plainExternalScripts) {\r\n try {\r\n await executeExternalScript(script);\r\n } catch (error) {\r\n console.error(\r\n `[LadrillosJS] Failed to load external script: ${script.src}`,\r\n error,\r\n );\r\n }\r\n }\r\n}\r\n\r\n// Cache for fetched external CSS (shared across all component instances)\r\nconst externalCssCache = new Map<string, string>();\r\n\r\n/**\r\n * Loads external stylesheets (<link rel=\"stylesheet\">) into the component.\r\n * For Shadow DOM components, fetches CSS content and injects directly into shadow root.\r\n * For light DOM components, adds <link> to document head.\r\n *\r\n * @param externalStyles - External stylesheets from the component\r\n * @param root - The component's root (shadow root or element itself)\r\n * @param useShadowDOM - Whether the component uses Shadow DOM\r\n * @returns Promise that resolves when all stylesheets are loaded\r\n */\r\nexport async function loadExternalStyles(\r\n externalStyles: Array<{ href: string; rel: string }>,\r\n root?: ShadowRoot | HTMLElement,\r\n useShadowDOM?: boolean,\r\n): Promise<void> {\r\n for (const style of externalStyles) {\r\n if (useShadowDOM && root) {\r\n // For Shadow DOM: fetch CSS and inject as <style> element\r\n // This ensures styles penetrate the shadow boundary\r\n try {\r\n let cssText = externalCssCache.get(style.href);\r\n\r\n if (!cssText) {\r\n const response = await fetch(style.href);\r\n if (!response.ok) {\r\n console.error(\r\n `[LadrillosJS] Failed to load stylesheet: ${style.href}`,\r\n );\r\n continue;\r\n }\r\n cssText = await response.text();\r\n externalCssCache.set(style.href, cssText);\r\n }\r\n\r\n const styleEl = document.createElement(\"style\");\r\n styleEl.textContent = cssText;\r\n styleEl.setAttribute(\"data-external-href\", style.href);\r\n // Insert at the beginning so component styles can override if needed\r\n root.insertBefore(styleEl, root.firstChild);\r\n } catch (error) {\r\n console.error(\r\n `[LadrillosJS] Failed to load stylesheet: ${style.href}`,\r\n error,\r\n );\r\n }\r\n } else {\r\n // For light DOM: add <link> to document head (if not already present)\r\n const existing = document.querySelector(`link[href=\"${style.href}\"]`);\r\n if (existing) continue;\r\n\r\n await new Promise<void>((resolve) => {\r\n const link = document.createElement(\"link\");\r\n link.rel = style.rel || \"stylesheet\";\r\n link.href = style.href;\r\n link.onload = () => resolve();\r\n link.onerror = () => {\r\n console.error(\r\n `[LadrillosJS] Failed to load stylesheet: ${style.href}`,\r\n );\r\n resolve(); // Don't block on CSS errors\r\n };\r\n document.head.appendChild(link);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Executes all module scripts for a component.\r\n * Handles both inline and external scripts (module and non-module).\r\n *\r\n * @param scripts - Inline scripts from the component\r\n * @param externalScripts - External scripts from the component\r\n * @param componentUrl - The component's URL for resolving imports\r\n * @param componentId - Unique ID for cleanup tracking\r\n * @returns Promise that resolves when all modules have executed\r\n */\r\nexport async function executeAllModuleScripts(\r\n scripts: ScriptElement[],\r\n externalScripts: ExternalScriptElement[],\r\n componentUrl: string,\r\n componentId?: string,\r\n): Promise<Map<number, unknown>> {\r\n const results = new Map<number, unknown>();\r\n\r\n // Separate module scripts from regular scripts\r\n const moduleScripts = scripts.filter((s) => s.type === \"module\");\r\n const externalModuleScripts = externalScripts.filter(\r\n (s) => s.type === \"module\",\r\n );\r\n const externalRegularScripts = externalScripts.filter(\r\n (s) => s.type !== \"module\",\r\n );\r\n\r\n // Execute external NON-module scripts first (they may set up globals)\r\n for (const script of externalRegularScripts) {\r\n try {\r\n await executeExternalScript(script, componentId, componentUrl);\r\n } catch (error) {\r\n console.error(`[LadrillosJS] External script failed:`, script.src, error);\r\n }\r\n }\r\n\r\n // Execute external module scripts (they may export things inline scripts need)\r\n for (const script of externalModuleScripts) {\r\n try {\r\n await executeExternalScript(script, componentId, componentUrl);\r\n } catch (error) {\r\n console.error(\r\n `[LadrillosJS] External module script failed:`,\r\n script.src,\r\n error,\r\n );\r\n }\r\n }\r\n\r\n // Execute inline module scripts\r\n for (let i = 0; i < moduleScripts.length; i++) {\r\n try {\r\n const exports = await executeModuleScript(\r\n moduleScripts[i],\r\n componentUrl,\r\n componentId,\r\n );\r\n results.set(i, exports);\r\n } catch (error) {\r\n console.error(`[LadrillosJS] Module script ${i} failed:`, error);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Cleans up blob URLs created for a component.\r\n * Call this when a component is disconnected to prevent memory leaks.\r\n *\r\n * @param componentId - The component's unique ID\r\n */\r\nexport function cleanupModuleScripts(componentId: string): void {\r\n const urls = blobUrlRegistry.get(componentId);\r\n if (urls) {\r\n for (const url of urls) {\r\n URL.revokeObjectURL(url);\r\n }\r\n blobUrlRegistry.delete(componentId);\r\n }\r\n}\r\n\r\n/**\r\n * Extracts import specifiers from module code.\r\n * Useful for debugging or pre-fetching dependencies.\r\n *\r\n * @param code - The module script content\r\n * @returns Array of import specifiers found in the code\r\n */\r\nexport function extractImportSpecifiers(code: string): string[] {\r\n const specifiers: string[] = [];\r\n\r\n // Static imports\r\n let match;\r\n const staticRegex =\r\n /(?:import|export)\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\r\n while ((match = staticRegex.exec(code)) !== null) {\r\n specifiers.push(match[1]);\r\n }\r\n\r\n // Dynamic imports\r\n const dynamicRegex = /import\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\r\n while ((match = dynamicRegex.exec(code)) !== null) {\r\n specifiers.push(match[1]);\r\n }\r\n\r\n return specifiers;\r\n}\r\n\r\n// ============================================================================\r\n// Reactive Module Execution\r\n// ============================================================================\r\n\r\n/**\r\n * Represents a parsed import statement\r\n */\r\ninterface ParsedImport {\r\n statement: string; // Full import statement\r\n specifier: string; // Module specifier (path)\r\n imports: ImportBinding[]; // What's being imported\r\n isDefault: boolean; // Is this a default import?\r\n isNamespace: boolean; // Is this import * as X?\r\n isSideEffect: boolean; // Is this just import \"module\"?\r\n}\r\n\r\ninterface ImportBinding {\r\n imported: string; // Name in the source module\r\n local: string; // Name in the importing module\r\n}\r\n\r\n/**\r\n * Parses import statements from module code.\r\n * Returns structured info about each import.\r\n */\r\nfunction parseImports(code: string): ParsedImport[] {\r\n const imports: ParsedImport[] = [];\r\n\r\n // Match various import forms\r\n const importRegex =\r\n /import\\s+(?:(\\{[^}]+\\})|(\\*\\s+as\\s+\\w+)|(\\w+)(?:\\s*,\\s*(\\{[^}]+\\}))?)?\\s*(?:from\\s+)?['\"]([^'\"]+)['\"]/g;\r\n\r\n let match;\r\n while ((match = importRegex.exec(code)) !== null) {\r\n const [\r\n statement,\r\n namedImports,\r\n namespaceImport,\r\n defaultImport,\r\n additionalNamed,\r\n specifier,\r\n ] = match;\r\n\r\n const parsed: ParsedImport = {\r\n statement,\r\n specifier,\r\n imports: [],\r\n isDefault: false,\r\n isNamespace: false,\r\n isSideEffect: false,\r\n };\r\n\r\n // Side effect import: import \"module\"\r\n if (!namedImports && !namespaceImport && !defaultImport) {\r\n parsed.isSideEffect = true;\r\n }\r\n\r\n // Default import: import X from \"module\"\r\n if (defaultImport) {\r\n parsed.isDefault = true;\r\n parsed.imports.push({ imported: \"default\", local: defaultImport });\r\n }\r\n\r\n // Namespace import: import * as X from \"module\"\r\n if (namespaceImport) {\r\n parsed.isNamespace = true;\r\n const localName = namespaceImport.replace(/\\*\\s+as\\s+/, \"\").trim();\r\n parsed.imports.push({ imported: \"*\", local: localName });\r\n }\r\n\r\n // Named imports: import { a, b as c } from \"module\"\r\n const namedPart = namedImports || additionalNamed;\r\n if (namedPart) {\r\n const inner = namedPart.slice(1, -1); // Remove { }\r\n const parts = inner\r\n .split(\",\")\r\n .map((p) => p.trim())\r\n .filter(Boolean);\r\n for (const part of parts) {\r\n const asMatch = part.match(/(\\w+)\\s+as\\s+(\\w+)/);\r\n if (asMatch) {\r\n parsed.imports.push({ imported: asMatch[1], local: asMatch[2] });\r\n } else {\r\n parsed.imports.push({ imported: part, local: part });\r\n }\r\n }\r\n }\r\n\r\n imports.push(parsed);\r\n }\r\n\r\n return imports;\r\n}\r\n\r\n/**\r\n * Fetches a module and returns its exports.\r\n * Uses dynamic import() for proper ES module loading.\r\n */\r\nasync function fetchModule(url: string): Promise<Record<string, unknown>> {\r\n // Check cache first\r\n if (moduleCache.has(url)) {\r\n return moduleCache.get(url)!;\r\n }\r\n\r\n const promise = (async () => {\r\n try {\r\n // Use dynamic import to load the module\r\n const module = await (0, eval)(`import(\"${url}\")`);\r\n return module as Record<string, unknown>;\r\n } catch (error) {\r\n console.error(`[LadrillosJS] Failed to fetch module: ${url}`, error);\r\n throw error;\r\n }\r\n })();\r\n\r\n moduleCache.set(url, promise);\r\n return promise;\r\n}\r\n\r\n/**\r\n * Recursively wraps arrays in an object with reactive proxies.\r\n * This ensures imported arrays trigger reactivity updates when mutated.\r\n *\r\n * @param value - The value to potentially wrap\r\n * @param onMutate - Callback when any array is mutated\r\n * @returns The value with arrays wrapped in reactive proxies\r\n */\r\nfunction wrapImportedValue(value: unknown, onMutate?: () => void): unknown {\r\n if (!onMutate) return value;\r\n\r\n if (Array.isArray(value)) {\r\n return createReactiveArray(value, onMutate);\r\n }\r\n\r\n // Don't deeply wrap objects - just arrays at the top level\r\n // This avoids issues with complex imported objects\r\n return value;\r\n}\r\n\r\n/**\r\n * Resolves all imports in a module script and returns the imported values.\r\n * If onMutate is provided, imported arrays will be wrapped in reactive proxies.\r\n *\r\n * @param code - The module script code containing imports\r\n * @param baseUrl - Base URL for resolving relative imports\r\n * @param onMutate - Optional callback to trigger when imported arrays are mutated\r\n */\r\nasync function resolveImports(\r\n code: string,\r\n baseUrl: string,\r\n onMutate?: () => void,\r\n): Promise<Record<string, unknown>> {\r\n const imports = parseImports(code);\r\n const resolved: Record<string, unknown> = {};\r\n\r\n for (const imp of imports) {\r\n if (imp.isSideEffect) {\r\n // Just execute the side effect\r\n const url = isRelativePath(imp.specifier)\r\n ? new URL(imp.specifier, baseUrl).href\r\n : imp.specifier;\r\n await fetchModule(url);\r\n continue;\r\n }\r\n\r\n // Resolve the URL\r\n const url = isRelativePath(imp.specifier)\r\n ? new URL(imp.specifier, baseUrl).href\r\n : imp.specifier;\r\n\r\n try {\r\n const moduleExports = await fetchModule(url);\r\n\r\n for (const binding of imp.imports) {\r\n let importedValue: unknown;\r\n\r\n if (binding.imported === \"*\") {\r\n // Namespace import\r\n importedValue = moduleExports;\r\n } else if (binding.imported === \"default\") {\r\n // Default import\r\n importedValue = moduleExports.default;\r\n } else {\r\n // Named import\r\n importedValue = moduleExports[binding.imported];\r\n }\r\n\r\n // Wrap arrays in reactive proxies if onMutate is provided\r\n resolved[binding.local] = wrapImportedValue(importedValue, onMutate);\r\n }\r\n } catch (error) {\r\n console.warn(\r\n `[LadrillosJS] Could not resolve import \"${imp.specifier}\":`,\r\n error,\r\n );\r\n }\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\n/**\r\n * Removes import statements from code, leaving just the executable code.\r\n */\r\nfunction stripImports(code: string): string {\r\n // Remove all import statements\r\n return code\r\n .replace(\r\n /import\\s+(?:(?:\\{[^}]+\\}|\\*\\s+as\\s+\\w+|\\w+)(?:\\s*,\\s*\\{[^}]+\\})?\\s+from\\s+)?['\"][^'\"]+['\"]\\s*;?/g,\r\n \"\",\r\n )\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts ONLY top-level variable and function names from code.\r\n *\r\n * This is critical for reactive state - we must NOT extract variables\r\n * declared inside functions (like `const myCanvas = refs.get(...)`).\r\n *\r\n * The approach: Track brace depth and only extract declarations at depth 0.\r\n */\r\nfunction extractDeclaredNames(code: string): {\r\n variables: string[];\r\n functions: string[];\r\n} {\r\n const variables: string[] = [];\r\n const functions: string[] = [];\r\n\r\n // Remove string literals and comments to avoid false matches\r\n // Replace them with spaces to preserve positions\r\n const cleanedCode = code\r\n // Remove template literals (backticks)\r\n .replace(/`[^`]*`/g, (m) => \" \".repeat(m.length))\r\n // Remove double-quoted strings\r\n .replace(/\"(?:[^\"\\\\]|\\\\.)*\"/g, (m) => \" \".repeat(m.length))\r\n // Remove single-quoted strings\r\n .replace(/'(?:[^'\\\\]|\\\\.)*'/g, (m) => \" \".repeat(m.length))\r\n // Remove multi-line comments\r\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, (m) => \" \".repeat(m.length))\r\n // Remove single-line comments\r\n .replace(/\\/\\/[^\\n]*/g, (m) => \" \".repeat(m.length));\r\n\r\n // Track brace depth: only extract at depth 0 (top level)\r\n let braceDepth = 0;\r\n let i = 0;\r\n\r\n while (i < cleanedCode.length) {\r\n const char = cleanedCode[i];\r\n\r\n // Track brace depth\r\n if (char === \"{\") {\r\n braceDepth++;\r\n i++;\r\n continue;\r\n }\r\n if (char === \"}\") {\r\n braceDepth--;\r\n i++;\r\n continue;\r\n }\r\n\r\n // Only extract at top level (braceDepth === 0)\r\n if (braceDepth === 0) {\r\n // Check for function declarations: function name( or async function name(\r\n const funcMatch = cleanedCode\r\n .slice(i)\r\n .match(/^(?:async\\s+)?function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/);\r\n if (funcMatch) {\r\n functions.push(funcMatch[1]);\r\n i += funcMatch[0].length;\r\n continue;\r\n }\r\n\r\n // Check for variable declarations: let/const/var name =\r\n const varMatch = cleanedCode\r\n .slice(i)\r\n .match(/^(?:let|const|var)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=/);\r\n if (varMatch) {\r\n variables.push(varMatch[1]);\r\n i += varMatch[0].length;\r\n continue;\r\n }\r\n }\r\n\r\n i++;\r\n }\r\n\r\n return { variables, functions };\r\n}\r\n\r\n/**\r\n * Executes a module script and extracts declared variables for reactive state.\r\n *\r\n * This is the KEY function for reactivity support in module scripts.\r\n * It:\r\n * 1. Resolves all imports (wrapping arrays in reactive proxies)\r\n * 2. Strips import statements from the code\r\n * 3. Transforms variable access to go through the reactive state object\r\n * 4. Executes the remaining code in a sandbox with imports available\r\n * 5. Functions read/write directly to the reactive state for full reactivity\r\n *\r\n * The transformation ensures that functions declared in module scripts\r\n * read/write from the reactive state, not from local closure variables.\r\n * This makes `let x = 0; function inc() { x++; }` work reactively.\r\n *\r\n * @param reactiveState - The component's reactive state object. Module script\r\n * functions will read/write directly to this object.\r\n * @param onStateChange - Optional callback when imported arrays are mutated.\r\n * This triggers directive updates (like $for loops).\r\n */\r\nexport async function executeModuleScriptWithReactivity(\r\n script: ScriptElement,\r\n componentUrl: string,\r\n componentId?: string,\r\n refs?: Map<string, HTMLElement>,\r\n reactiveState?: Record<string, unknown>,\r\n onStateChange?: () => void,\r\n hostElement?: HTMLElement,\r\n): Promise<Record<string, unknown>> {\r\n if (script.type !== \"module\") {\r\n throw new Error(\r\n 'executeModuleScriptWithReactivity only handles type=\"module\" scripts',\r\n );\r\n }\r\n\r\n const code = script.content;\r\n\r\n // 1. Resolve all imports (wrap arrays in reactive proxies for automatic UI updates)\r\n const importedValues = await resolveImports(\r\n code,\r\n componentUrl,\r\n onStateChange,\r\n );\r\n\r\n // Merge imports into reactive state so they're accessible from template\r\n // bindings (e.g. {getName()} when getName is an imported function).\r\n // Don't overwrite values that are already on state (attribute overrides win),\r\n // and skip framework helper names so they don't collide with the helpers\r\n // injected as function parameters when building event handlers.\r\n if (reactiveState) {\r\n const reservedNames = new Set<string>([\r\n ...frameworkHelperNames,\r\n ...eventBusHelperNames,\r\n \"ladrillosjs\",\r\n \"$host\",\r\n \"$refs\",\r\n \"event\",\r\n \"state\",\r\n ]);\r\n for (const [key, value] of Object.entries(importedValues)) {\r\n if (reservedNames.has(key)) continue;\r\n if (!(key in reactiveState)) {\r\n reactiveState[key] = value;\r\n }\r\n }\r\n }\r\n\r\n // 2. Strip import statements from the code\r\n const executableCode = stripImports(code);\r\n\r\n // 3. Extract names of declared variables/functions\r\n const { variables, functions } = extractDeclaredNames(executableCode);\r\n\r\n // 4. Transform code so variable access goes through __state__ object\r\n // This is the key to making module scripts reactive like regular scripts\r\n const transformedCode = transformCodeToStateAccess(executableCode, variables);\r\n\r\n // 5. Build and execute the sandboxed function\r\n const importNames = Object.keys(importedValues);\r\n const importValues = Object.values(importedValues);\r\n\r\n // Return all functions (they have closure over __state__ which is the reactive state)\r\n const returnStatement =\r\n functions.length > 0 ? `return { ${functions.join(\", \")} };` : `return {};`;\r\n\r\n // Wrap in an async IIFE to support top-level await in module scripts\r\n // This allows users to write: await ladrillosjs.registerComponents([...])\r\n // without needing to wrap it in an async function themselves\r\n const wrappedCode = `\r\n \"use strict\";\r\n return (async () => {\r\n ${transformedCode}\r\n ${returnStatement}\r\n })();\r\n `;\r\n\r\n try {\r\n // Include console, alert, etc. as safe globals\r\n const safeGlobals = [\r\n \"console\",\r\n \"alert\",\r\n \"Math\",\r\n \"JSON\",\r\n \"Date\",\r\n \"Array\",\r\n \"Object\",\r\n \"String\",\r\n \"Number\",\r\n \"Boolean\",\r\n \"Promise\",\r\n \"setTimeout\",\r\n \"setInterval\",\r\n \"clearTimeout\",\r\n \"clearInterval\",\r\n ];\r\n const safeGlobalValues = safeGlobals.map(\r\n (name) => (globalThis as any)[name],\r\n );\r\n\r\n // Inject $refs Map so functions can access element references\r\n // The $refs Map is populated later by scanDirectives, but the\r\n // reference is captured by functions defined in the module\r\n //\r\n // __state__ is the reactive state object - functions write directly to it\r\n // for full reactivity support\r\n const injectedVars = [\"$refs\", \"__state__\", \"$host\"];\r\n const injectedValues = [refs || new Map(), reactiveState || {}, hostElement];\r\n\r\n // Create framework helpers bound to component's URL for correct path resolution\r\n // This ensures registerComponent(\"./child.html\") resolves relative to THIS component\r\n const helpers = createFrameworkHelpers(componentUrl);\r\n const frameworkHelperValues = [\r\n helpers.registerComponent,\r\n helpers.registerComponents,\r\n helpers.$use,\r\n ];\r\n\r\n // Create event bus helpers bound to component ID for automatic cleanup\r\n const eventBusHelpers = createEventBusHelpers(componentId || \"anonymous\");\r\n const eventBusHelperValues = [\r\n eventBusHelpers.$emit,\r\n eventBusHelpers.$listen,\r\n ];\r\n\r\n // Create a context-aware ladrillosjs object that resolves paths relative to this component\r\n // This allows users to use either ladrillosjs.registerComponents() or registerComponents()\r\n // We spread the global object FIRST, then override with context-aware versions\r\n const globalLadrillos = (globalThis as any).ladrillosjs || {};\r\n const contextAwareLadrillosjs = {\r\n ...globalLadrillos,\r\n // Override with context-aware versions that resolve paths relative to THIS component\r\n registerComponent: helpers.registerComponent,\r\n registerComponents: helpers.registerComponents,\r\n };\r\n\r\n // Add framework helpers (registerComponent, $use, $emit, $listen, etc.)\r\n // Deduplicate: if the user explicitly imported a name that collides with a\r\n // framework-injected name (e.g. `import { registerComponent } from \"ladrillosjs\"`),\r\n // the user's import wins and we skip the injected version to avoid\r\n // \"Duplicate parameter name\" errors when building the Function.\r\n //\r\n // BUT: For framework helpers specifically, the imported value resolves\r\n // relative paths against window.location, not the component URL. So we\r\n // override the user's imported value with the context-aware version,\r\n // making `import { registerComponent } from \"ladrillosjs\"` behave the\r\n // same as the auto-injected `registerComponent`.\r\n const helperOverrides: Record<string, unknown> = {\r\n registerComponent: helpers.registerComponent,\r\n registerComponents: helpers.registerComponents,\r\n $use: helpers.$use,\r\n $emit: eventBusHelpers.$emit,\r\n $listen: eventBusHelpers.$listen,\r\n ladrillosjs: contextAwareLadrillosjs,\r\n };\r\n\r\n const importNameSet = new Set(importNames);\r\n const allParamNames: string[] = [...importNames];\r\n const allParamValues: unknown[] = importNames.map((name, i) =>\r\n name in helperOverrides ? helperOverrides[name] : importValues[i],\r\n );\r\n\r\n const appendUnique = (names: readonly string[], values: readonly unknown[]) => {\r\n for (let i = 0; i < names.length; i++) {\r\n const name = names[i];\r\n if (importNameSet.has(name)) continue;\r\n importNameSet.add(name);\r\n allParamNames.push(name);\r\n allParamValues.push(values[i]);\r\n }\r\n };\r\n\r\n appendUnique(safeGlobals, safeGlobalValues);\r\n appendUnique(frameworkHelperNames, frameworkHelperValues);\r\n appendUnique(eventBusHelperNames, eventBusHelperValues);\r\n appendUnique(injectedVars, injectedValues);\r\n appendUnique([\"ladrillosjs\"], [contextAwareLadrillosjs]);\r\n\r\n const fn = new Function(...allParamNames, wrappedCode);\r\n\r\n // The function now returns a Promise due to the async IIFE wrapper\r\n const result = await fn(...allParamValues);\r\n\r\n // Return both the initial values (from __state__) and functions\r\n // The reactiveState object now contains all variables set by the module script\r\n return { ...(reactiveState || {}), ...(result || {}) };\r\n } catch (error) {\r\n console.error(`[LadrillosJS] Failed to execute module script:`, error);\r\n console.error(\"Original code:\", executableCode);\r\n console.error(\"Transformed code:\", transformedCode);\r\n console.error(\"Imports:\", importedValues);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Executes all module scripts with reactivity support.\r\n * Returns merged state from all module scripts.\r\n * @param refs - Optional refs Map that will be populated by scanDirectives later.\r\n * Functions in module scripts can capture this reference.\r\n * @param reactiveState - The component's reactive state object. Module script\r\n * functions will read/write directly to this object.\r\n * @param onStateChange - Optional callback when imported arrays are mutated.\r\n * This triggers directive updates (like $for loops).\r\n */\r\nexport async function executeModuleScriptsWithReactivity(\r\n scripts: ScriptElement[],\r\n externalScripts: ExternalScriptElement[],\r\n componentUrl: string,\r\n componentId?: string,\r\n refs?: Map<string, HTMLElement>,\r\n reactiveState?: Record<string, unknown>,\r\n onStateChange?: () => void,\r\n hostElement?: HTMLElement,\r\n): Promise<Record<string, unknown>> {\r\n const mergedState: Record<string, unknown> = {};\r\n\r\n // Filter to only module scripts (inline)\r\n const moduleScripts = scripts.filter((s) => s.type === \"module\");\r\n\r\n // Separate external scripts by type\r\n const externalModuleScripts = externalScripts.filter(\r\n (s) => s.type === \"module\",\r\n );\r\n const externalRegularScripts = externalScripts.filter(\r\n (s) => s.type !== \"module\",\r\n );\r\n\r\n // Execute external NON-module scripts first (they may set up globals needed by modules)\r\n for (const script of externalRegularScripts) {\r\n try {\r\n await executeExternalScript(script, componentId, componentUrl);\r\n } catch (error) {\r\n console.error(`[LadrillosJS] External script failed:`, script.src, error);\r\n }\r\n }\r\n\r\n // Execute external module scripts and merge their exports into state\r\n for (const script of externalModuleScripts) {\r\n try {\r\n const moduleExports = await executeExternalScript(\r\n script,\r\n componentId,\r\n componentUrl,\r\n );\r\n // Merge module exports into state (functions, variables, etc.)\r\n if (moduleExports && typeof moduleExports === \"object\") {\r\n for (const [key, value] of Object.entries(\r\n moduleExports as Record<string, unknown>,\r\n )) {\r\n // Skip default export key, merge named exports\r\n if (key !== \"default\") {\r\n mergedState[key] = value;\r\n // Also write to reactive state if provided\r\n if (reactiveState) {\r\n reactiveState[key] = value;\r\n }\r\n }\r\n }\r\n }\r\n } catch (error) {\r\n console.error(\r\n `[LadrillosJS] External module script failed:`,\r\n script.src,\r\n error,\r\n );\r\n }\r\n }\r\n\r\n // Execute inline module scripts and collect their state\r\n for (const script of moduleScripts) {\r\n try {\r\n const state = await executeModuleScriptWithReactivity(\r\n script,\r\n componentUrl,\r\n componentId,\r\n refs,\r\n reactiveState,\r\n onStateChange,\r\n hostElement,\r\n );\r\n Object.assign(mergedState, state);\r\n } catch (error) {\r\n console.error(`[LadrillosJS] Module script failed:`, error);\r\n }\r\n }\r\n\r\n return mergedState;\r\n}\r\n","/**\n * Table-safe parsing for built-in control elements.\n *\n * The HTML parser's table insertion modes foster-parent anything that is\n * not valid table content out of `<table>`/`<thead>`/`<tbody>`/`<tr>`.\n * Built-in control elements (`<for>`, `<if>`, `<else-if>`, `<else>`,\n * `<show>`) are unknown to the parser, so markup like\n *\n * <table><tbody>\n * <for each=\"row in rows\" key=\"row.id\">\n * <tr><td>{row.id}</td></tr>\n * </for>\n * </tbody></table>\n *\n * gets mangled BEFORE the framework ever sees the tree: `<for>` is\n * hoisted out of the table and the raw `<tr>` template is left behind,\n * un-bound. This applies to every parse entry point — `DOMParser` and\n * `template.innerHTML` alike.\n *\n * `<template>` elements, however, ARE valid anywhere inside a table, and\n * their content model is parsed leniently (a bare `<tr>` or `<td>` inside\n * template content survives). So before parsing we rewrite control tags to\n * `<template data-l-ctrl=\"…\">` placeholders at the string level, and after\n * parsing we rebuild the real control elements with DOM APIs — which the\n * parser's content rules cannot touch.\n */\n\nconst ESCAPE_ATTR = \"data-l-ctrl\";\n\nconst CONTROL_TAG_NAMES = new Set([\"FOR\", \"IF\", \"ELSE-IF\", \"ELSE\", \"SHOW\"]);\n\n/**\n * Open tags of control elements. Attribute scanning skips over quoted\n * values so expressions like condition=\"i > 0\" don't truncate the match.\n * `else-if` must precede `else`/`if` in the alternation.\n */\nconst OPEN_TAG = /<(for|else-if|if|else|show)\\b((?:[^>\"']|\"[^\"]*\"|'[^']*')*)>/gi;\n\nconst CLOSE_TAG = /<\\/(for|else-if|if|else|show)\\s*>/gi;\n\n/**\n * Segments whose text content must never be rewritten: script bodies,\n * style bodies, and HTML comments. A `<for …>` appearing inside a JS\n * string or a commented-out block is not markup.\n */\nconst OPAQUE_SEGMENTS =\n /(<script\\b[\\s\\S]*?<\\/script\\s*>|<style\\b[\\s\\S]*?<\\/style\\s*>|<!--[\\s\\S]*?-->)/gi;\n\n/** Cheap pre-check so templates without control tags skip the rewrite. */\nconst HAS_CONTROL_TAG = /<\\/?(?:for|if|else|show)\\b/i;\n\n/**\n * Rewrites control-element tags to `<template data-l-ctrl=\"…\">`\n * placeholders so the HTML parser cannot foster-parent them out of table\n * contexts. Must be paired with {@link restoreControlTags} on the parsed\n * tree.\n */\nexport function escapeControlTags(html: string): string\n{\n if (!HAS_CONTROL_TAG.test(html))\n {\n return html;\n }\n\n return html\n .split(OPAQUE_SEGMENTS)\n .map((segment, i) =>\n {\n // Odd indices are the captured opaque segments — pass through.\n if (i % 2 === 1)\n {\n return segment;\n }\n return segment\n .replace(\n OPEN_TAG,\n (_m, name: string, attrs: string) =>\n `<template ${ESCAPE_ATTR}=\"${name.toLowerCase()}\"${attrs}>`\n )\n .replace(CLOSE_TAG, \"</template>\");\n })\n .join(\"\");\n}\n\n/**\n * Rebuilds real control elements from the placeholders produced by\n * {@link escapeControlTags}. Runs until no placeholder remains: restoring\n * an outer placeholder moves its (previously inert) template content into\n * the live tree, exposing any nested placeholders to the next iteration.\n * User-authored `<template>` elements are recursed into so control tags\n * inside their inert content are restored as well.\n */\nexport function restoreControlTags(root: ParentNode): void\n{\n let placeholder: HTMLTemplateElement | null;\n while (\n (placeholder = root.querySelector<HTMLTemplateElement>(\n `template[${ESCAPE_ATTR}]`\n ))\n )\n {\n const doc = placeholder.ownerDocument;\n const el = doc.createElement(placeholder.getAttribute(ESCAPE_ATTR)!);\n for (const attr of Array.from(placeholder.attributes))\n {\n if (attr.name !== ESCAPE_ATTR)\n {\n el.setAttribute(attr.name, attr.value);\n }\n }\n // Appending the content fragment MOVES its children into the element.\n el.appendChild(placeholder.content);\n placeholder.replaceWith(el);\n }\n\n for (const tpl of Array.from(root.querySelectorAll(\"template\")))\n {\n restoreControlTags((tpl as HTMLTemplateElement).content);\n }\n}\n\n/**\n * Returns true when the element is a restored control element\n * (`<for>`, `<if>`, `<else-if>`, `<else>`, `<show>`).\n */\nexport function isControlElement(el: Element): boolean\n{\n return CONTROL_TAG_NAMES.has(el.tagName);\n}\n","import { LadrillosComponent } from \"../../types\";\r\nimport { REGEX_PATTERNS } from \"../../utils/regex\";\r\nimport { rewriteImports } from \"../js/moduleExecutor\";\r\nimport {\r\n escapeControlTags,\r\n restoreControlTags,\r\n isControlElement,\r\n} from \"../html/controlTagEscape\";\r\n\r\nconst parser = new DOMParser();\r\n\r\n/**\r\n * Signatures of scripts injected by dev servers / live-reload tooling.\r\n *\r\n * When a component's `.html` partial is fetched through a dev server (VS Code\r\n * Live Preview, Live Server, BrowserSync, webpack-dev-server, …), that server\r\n * injects its own live-reload / HMR client script into the served HTML. Those\r\n * scripts are NOT part of the authored component, so they must never be treated\r\n * as component script content — otherwise the framework tries to inline them and\r\n * re-execute their code inside the reactive-state sandbox and event-handler\r\n * builder, which corrupts state extraction and silently breaks every inline /\r\n * `$on:` handler in the component.\r\n *\r\n * `@vite/client` and Vite `html-proxy` scripts are handled separately (Vite\r\n * proxy scripts are intentionally fetched), so they are not listed here.\r\n */\r\nconst INJECTED_SCRIPT_SRC_MARKERS = [\r\n \"___vscode_livepreview_injected_script\", // VS Code Live Preview\r\n \"/livereload.js\", // LiveReload / VS Code Live Server\r\n \"browser-sync-client\", // BrowserSync\r\n \"browser-sync/dist\", // BrowserSync\r\n \"webpack-dev-server\", // webpack-dev-server client\r\n \"sockjs-node\", // webpack-dev-server / sockjs transport\r\n \"__webpack_hmr\", // webpack hot middleware\r\n];\r\n\r\nconst INJECTED_SCRIPT_CONTENT_MARKERS = [\r\n \"aka.ms/live-preview\", // VS Code Live Preview banner\r\n \"Live Preview Extension\", // VS Code Live Preview banner\r\n \"___vscode_livepreview\", // VS Code Live Preview globals\r\n \"__bs_script__\", // BrowserSync\r\n \"browser-sync\", // BrowserSync client\r\n \"Browsersync\", // BrowserSync client banner\r\n \"browserSync\", // BrowserSync client\r\n \"LiveReload\", // LiveReload client\r\n \"webpackHotUpdate\", // webpack HMR runtime\r\n \"__webpack_hmr\", // webpack hot middleware\r\n];\r\n\r\n/**\r\n * `id` attribute values used by dev-server injected scripts.\r\n */\r\nconst INJECTED_SCRIPT_ID_MARKERS = [\r\n \"__bs_script__\", // BrowserSync\r\n];\r\n\r\n/**\r\n * Returns true when a `<script>` element was injected by a dev server /\r\n * live-reload tool rather than authored as part of the component.\r\n * Checks the external `src` URL, the `id` attribute, and inline content\r\n * against known markers.\r\n */\r\nfunction isDevServerInjectedScript(el: Element): boolean\r\n{\r\n const src = el.getAttribute(\"src\") || \"\";\r\n if (src && INJECTED_SCRIPT_SRC_MARKERS.some((m) => src.includes(m)))\r\n {\r\n return true;\r\n }\r\n\r\n const id = el.getAttribute(\"id\") || \"\";\r\n if (id && INJECTED_SCRIPT_ID_MARKERS.includes(id))\r\n {\r\n return true;\r\n }\r\n\r\n const content = el.textContent || \"\";\r\n if (\r\n content &&\r\n INJECTED_SCRIPT_CONTENT_MARKERS.some((m) => content.includes(m))\r\n )\r\n {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Extracts loop variable names from <for each=\"...\"> built-in elements.\r\n * These are locally scoped variables that should NOT be treated as state variables.\r\n *\r\n * Examples:\r\n * <for each=\"item in items\"> → [\"item\"]\r\n * <for each=\"(item, index) in items\"> → [\"item\", \"index\"]\r\n * <for each=\"(user, i) in users\"> → [\"user\", \"i\"]\r\n */\r\nfunction extractLoopVariables(template: string): Set<string>\r\n{\r\n const loopVars = new Set<string>();\r\n\r\n // Match the `each=\"...\"` attribute on <for> elements.\r\n const forRegex = /<for\\b[^>]*?\\beach\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\r\n\r\n let match;\r\n while ((match = forRegex.exec(template)) !== null)\r\n {\r\n const forExpr = match[1].trim();\r\n\r\n // Check for destructured form: (item, index) in array\r\n const destructuredMatch = forExpr.match(\r\n /^\\(\\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*,\\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\)\\s+in\\s+/\r\n );\r\n if (destructuredMatch)\r\n {\r\n loopVars.add(destructuredMatch[1]); // item variable\r\n loopVars.add(destructuredMatch[2]); // index variable\r\n continue;\r\n }\r\n\r\n // Check for simple form: item in array\r\n const simpleMatch = forExpr.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)\\s+in\\s+/);\r\n if (simpleMatch)\r\n {\r\n loopVars.add(simpleMatch[1]); // item variable\r\n }\r\n }\r\n\r\n return loopVars;\r\n}\r\n\r\n/**\r\n * Extracts the SOURCE collection variable from <for each=\"... in source\">.\r\n * Unlike the loop item variable (which is locally scoped), the source is a\r\n * state/prop reference and MUST be registered as an observed prop so a parent\r\n * can pass it down (e.g. <l-list postList=\"{postList}\">). Without this, a\r\n * variable used ONLY inside a loop has no accessor and the prop is dropped.\r\n *\r\n * Examples:\r\n * <for each=\"post in postList\"> → [\"postList\"]\r\n * <for each=\"(u, i) in users\"> → [\"users\"]\r\n * <for each=\"item in data.items\"> → [\"data\"] (root identifier)\r\n */\r\nfunction extractLoopSourceVariables(template: string): Set<string>\r\n{\r\n const sources = new Set<string>();\r\n const forRegex = /<for\\b[^>]*?\\beach\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\r\n\r\n let match;\r\n while ((match = forRegex.exec(template)) !== null)\r\n {\r\n const forExpr = match[1].trim();\r\n // Take everything after the first \" in \" — that's the source expression.\r\n const inMatch = forExpr.match(/\\bin\\b\\s+(.+)$/);\r\n if (!inMatch) continue;\r\n // Root identifier of the source expression (data.items -> data).\r\n const rootMatch = inMatch[1].trim().match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);\r\n if (rootMatch)\r\n {\r\n sources.add(rootMatch[1]);\r\n }\r\n }\r\n\r\n return sources;\r\n}\r\n\r\n/**\r\n * Extracts simple variable names from template bindings.\r\n * Only extracts top-level identifiers (e.g., 'title' from {title}, 'name' from {name.first}).\r\n * Ignores complex expressions, function calls, and literals.\r\n *\r\n * IMPORTANT: Excludes loop variables from $for directives, as those are locally\r\n * scoped and should not be transformed to __state__ access.\r\n */\r\nfunction extractTemplateBindingVariables(template: string): string[]\r\n{\r\n const variables = new Set<string>();\r\n const loopVariables = extractLoopVariables(template);\r\n const matches = template.matchAll(REGEX_PATTERNS.bindings);\r\n\r\n for (const match of matches)\r\n {\r\n const expression = match[1].trim();\r\n // Extract the first identifier (handles both 'title' and 'user.name' -> 'user')\r\n const identifierMatch = expression.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);\r\n if (identifierMatch)\r\n {\r\n const varName = identifierMatch[1];\r\n // Skip JavaScript keywords, literals, and common globals\r\n const skipList = [\r\n \"true\",\r\n \"false\",\r\n \"null\",\r\n \"undefined\",\r\n \"new\",\r\n \"this\",\r\n \"typeof\",\r\n \"instanceof\",\r\n \"void\",\r\n \"delete\",\r\n \"in\",\r\n \"of\",\r\n \"if\",\r\n \"else\",\r\n \"for\",\r\n \"while\",\r\n \"do\",\r\n \"switch\",\r\n \"case\",\r\n \"break\",\r\n \"continue\",\r\n \"return\",\r\n \"throw\",\r\n \"try\",\r\n \"catch\",\r\n \"finally\",\r\n \"function\",\r\n \"class\",\r\n \"const\",\r\n \"let\",\r\n \"var\",\r\n \"Math\",\r\n \"Date\",\r\n \"JSON\",\r\n \"Array\",\r\n \"Object\",\r\n \"String\",\r\n \"Number\",\r\n \"Boolean\",\r\n \"console\",\r\n \"window\",\r\n \"document\",\r\n ];\r\n // Skip loop variables (from $for directives) - they are locally scoped\r\n if (!skipList.includes(varName) && !loopVariables.has(varName))\r\n {\r\n variables.add(varName);\r\n }\r\n }\r\n }\r\n\r\n // Include loop SOURCE variables (the collection after `in`) so they are\r\n // registered as observed props and can be received from a parent component.\r\n for (const source of extractLoopSourceVariables(template))\r\n {\r\n if (!loopVariables.has(source))\r\n {\r\n variables.add(source);\r\n }\r\n }\r\n\r\n return Array.from(variables);\r\n}\r\n\r\nexport async function parseComponent(\r\n source: string,\r\n name: string,\r\n componentUrl?: string\r\n): Promise<LadrillosComponent>\r\n{\r\n const doc = parseHTML(source);\r\n\r\n // get scripts\r\n const scriptEls = Array.from(doc.querySelectorAll(\"script\"));\r\n\r\n // Drop scripts injected by dev servers / live-reload tooling (VS Code Live\r\n // Preview, Live Server, BrowserSync, webpack-dev-server, …). These are added\r\n // to the served HTML by the dev server and are not part of the authored\r\n // component; ingesting them corrupts reactive-state extraction and silently\r\n // breaks every inline / $on: event handler in the component.\r\n const authoredScriptEls = scriptEls.filter(\r\n (s) => !isDevServerInjectedScript(s)\r\n );\r\n\r\n // Collect inline scripts (with content)\r\n const inlineScripts = authoredScriptEls\r\n .filter((s) => !s.src)\r\n .map((s) =>\r\n {\r\n const content = (s.textContent ?? \"\").trim();\r\n const type = s.getAttribute(\"type\");\r\n return { content, type };\r\n })\r\n .filter((s) => s.content.length > 0);\r\n\r\n // Detect Vite-transformed module scripts (html-proxy)\r\n // These are inline scripts that Vite extracted to external files\r\n const viteProxyScripts = authoredScriptEls.filter((s) =>\r\n {\r\n const src = s.getAttribute(\"src\") || \"\";\r\n return src.includes(\"html-proxy\") && s.getAttribute(\"type\") === \"module\";\r\n });\r\n\r\n // Fetch content from Vite proxy scripts\r\n const fetchedScripts = await Promise.all(\r\n viteProxyScripts.map(async (s) =>\r\n {\r\n const src = s.getAttribute(\"src\") || \"\";\r\n try\r\n {\r\n const response = await fetch(src);\r\n if (response.ok)\r\n {\r\n const content = await response.text();\r\n return { content: content.trim(), type: \"module\" };\r\n }\r\n } catch (e)\r\n {\r\n // Silently fail - script will be skipped\r\n }\r\n return null;\r\n })\r\n );\r\n\r\n // Combine inline scripts with fetched Vite proxy scripts\r\n const scripts = [\r\n ...inlineScripts,\r\n ...fetchedScripts.filter(\r\n (s): s is { content: string; type: string } =>\r\n s !== null && s.content.length > 0\r\n ),\r\n ];\r\n\r\n // Filter out Vite-injected scripts and proxy scripts for external scripts list\r\n const allExternalScripts = authoredScriptEls\r\n .filter((s) =>\r\n {\r\n if (!s.src) return false;\r\n const src = s.getAttribute(\"src\") || \"\";\r\n // Skip Vite client and proxy scripts\r\n if (src.includes(\"@vite/client\")) return false;\r\n if (src.includes(\"html-proxy\")) return false;\r\n return true;\r\n })\r\n .map((s) =>\r\n {\r\n const type = s.getAttribute(\"type\");\r\n let src = s.src;\r\n\r\n // If the parser keeps a relative src, resolve it against the component URL.\r\n if (componentUrl)\r\n {\r\n try\r\n {\r\n src = new URL(\r\n s.getAttribute(\"src\") ?? s.src,\r\n componentUrl\r\n ).toString();\r\n } catch\r\n {\r\n // ignore resolution errors; keep original\r\n }\r\n }\r\n\r\n // Check if the script has the 'external' attribute\r\n // These scripts should be loaded as-is without framework processing\r\n const external = s.hasAttribute(\"external\");\r\n\r\n return { src, type, external };\r\n })\r\n .filter((s) => s.src.length > 0);\r\n\r\n // Plain external scripts (without the `external` attribute) are fetched\r\n // and inlined so their declarations participate in the component's reactive\r\n // state — same as if the user had pasted the code into a <script> tag.\r\n // This applies to both regular scripts AND `type=\"module\"` scripts; the\r\n // only practical reason to keep an external file is when you need import\r\n // statements (which require type=\"module\"). Both kinds end up reactive.\r\n // Scripts marked with the `external` attribute are left alone and loaded\r\n // as raw third-party scripts.\r\n const inlineableExternals = allExternalScripts.filter((s) => !s.external);\r\n const externalScripts = allExternalScripts.filter((s) => s.external);\r\n\r\n const fetchedInlineExternals = await Promise.all(\r\n inlineableExternals.map(async (s) =>\r\n {\r\n try\r\n {\r\n const response = await fetch(s.src);\r\n if (response.ok)\r\n {\r\n let content = (await response.text()).trim();\r\n if (content.length > 0)\r\n {\r\n // For module scripts, rewrite relative imports against the\r\n // ORIGINAL script URL so they still resolve correctly after\r\n // the content is inlined into the component.\r\n if (s.type === \"module\")\r\n {\r\n content = rewriteImports(content, s.src);\r\n }\r\n return { content, type: s.type };\r\n }\r\n }\r\n } catch\r\n {\r\n // Silently fail - script will be skipped\r\n }\r\n return null;\r\n })\r\n );\r\n\r\n for (const s of fetchedInlineExternals)\r\n {\r\n if (s) scripts.push(s);\r\n }\r\n\r\n scriptEls.forEach((s) => s.remove());\r\n\r\n // get external stylesheets (<link rel=\"stylesheet\">)\r\n const linkEls = Array.from(doc.querySelectorAll('link[rel=\"stylesheet\"]'));\r\n const externalStyles = linkEls\r\n .map((l) =>\r\n {\r\n let href = l.getAttribute(\"href\") || \"\";\r\n const rel = l.getAttribute(\"rel\") || \"stylesheet\";\r\n\r\n // Resolve relative URLs against component URL\r\n if (componentUrl && href && !href.startsWith(\"http\"))\r\n {\r\n try\r\n {\r\n href = new URL(href, componentUrl).toString();\r\n } catch\r\n {\r\n // ignore resolution errors; keep original\r\n }\r\n }\r\n\r\n return { href, rel };\r\n })\r\n .filter((l) => l.href.length > 0);\r\n linkEls.forEach((l) => l.remove());\r\n\r\n // get styles\r\n const styleEls = Array.from(doc.querySelectorAll(\"style\"));\r\n const styles = styleEls\r\n .map((s) => s.textContent ?? \"\")\r\n .join(\"\\n\")\r\n .trim();\r\n styleEls.forEach((s) => s.remove());\r\n\r\n // Get template content\r\n // <template> elements have special handling - content is in .content property\r\n //\r\n // Only a `<template>` that is a DIRECT child of <body> or <head> counts as\r\n // the component's root template. A plain `doc.querySelector(\"template\")`\r\n // would match nested <template> elements inside child custom elements\r\n // (e.g. a <code-block> that wraps a <template> of source code to display),\r\n // causing the framework to mistakenly treat that nested template as the\r\n // component's root and drop everything else.\r\n //\r\n // We must also check <head>: when a component file begins with a\r\n // <template>/<script>/<style> (with no prior flow content), the HTML\r\n // parser places those elements in <head>. This also happens in dev when\r\n // Vite injects its client <script> at the top of fetched HTML.\r\n const findTopLevelTemplate = (parent: Element | null) =>\r\n parent\r\n ? (Array.from(parent.children).find(\r\n (el) => el.tagName === \"TEMPLATE\"\r\n ) as HTMLTemplateElement | undefined)\r\n : undefined;\r\n const templateEl =\r\n findTopLevelTemplate(doc.body) ?? findTopLevelTemplate(doc.head);\r\n let html: string;\r\n\r\n if (templateEl)\r\n {\r\n // Clone the template content and serialize it\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.appendChild(templateEl.content.cloneNode(true));\r\n html = tempDiv.innerHTML.trim();\r\n } else\r\n {\r\n // Fallback to body innerHTML\r\n html = doc.body.innerHTML.trim();\r\n }\r\n\r\n // Extract variable names from template bindings for auto-attribute observation\r\n const templateBindings = extractTemplateBindingVariables(html);\r\n\r\n return {\r\n tagName: name,\r\n template: html,\r\n scripts,\r\n externalScripts,\r\n externalStyles,\r\n styles: styles,\r\n sourcePath: componentUrl,\r\n lazy: false,\r\n templateBindings,\r\n };\r\n}\r\n\r\nfunction parseHTML(source: string): Document\r\n{\r\n // Control elements (<for>, <if>, …) are escaped to <template>\r\n // placeholders before parsing so the HTML parser's table insertion\r\n // modes cannot foster-parent them out of <table>/<tbody>/<tr>, then\r\n // restored with DOM APIs — which parser content rules cannot touch.\r\n const doc = parser.parseFromString(escapeControlTags(source), \"text/html\");\r\n restoreControlTags(doc.head);\r\n restoreControlTags(doc.body);\r\n\r\n // A component that STARTS with a control element gets its placeholder\r\n // parsed into <head> (templates are metadata content), whereas the raw\r\n // tag would have opened <body>. Move restored control elements back to\r\n // the front of <body>, preserving their order.\r\n const strays = Array.from(doc.head.children).filter(isControlElement);\r\n const anchor = doc.body.firstChild;\r\n for (const el of strays)\r\n {\r\n doc.body.insertBefore(el, anchor);\r\n }\r\n\r\n return doc;\r\n}\r\n","const cache = new Map<string, string>();\r\nlet maxCacheSize = 25;\r\n\r\n/**\r\n * Set the maximum number of component sources retained in the LRU cache.\r\n * When the new size is smaller than the current cache, the least-recently\r\n * used entries are evicted until the limit is satisfied.\r\n */\r\nexport const setCacheSize = (size: number): void => {\r\n if (!Number.isFinite(size) || size < 1) {\r\n throw new Error(\r\n `[LadrillosJS] configure({ cacheSize }) requires a positive integer, got ${size}`,\r\n );\r\n }\r\n maxCacheSize = Math.floor(size);\r\n // Evict to respect new limit\r\n while (cache.size > maxCacheSize) {\r\n const firstKey = cache.keys().next().value;\r\n if (!firstKey) break;\r\n cache.delete(firstKey);\r\n }\r\n};\r\n\r\n/**\r\n * LRU Cache: Gets cached content and marks it as recently used\r\n * Moves the accessed item to the end of the Map (most recently used position)\r\n * This ensures frequently accessed components stay in cache longer\r\n * @param path - The file path to retrieve from cache\r\n * @returns The cached content or undefined if not found\r\n */\r\nexport const getCachedComponentSource = (path: string): string | undefined => {\r\n const cached = cache.get(path);\r\n\r\n if (cached) {\r\n // Move to end to mark as recently used\r\n cache.delete(path);\r\n cache.set(path, cached);\r\n }\r\n\r\n return cached;\r\n};\r\n\r\n/**\r\n * LRU Cache: Stores content with automatic eviction of least recently used items\r\n * Maintains cache size limit by removing oldest items when full\r\n * Updates existing items without affecting cache size\r\n * @param path - The file path to cache\r\n * @param content - The content to store\r\n */\r\nexport const setCachedComponentSource = (\r\n path: string,\r\n content: string,\r\n): void => {\r\n if (cache.has(path)) {\r\n // Update existing: remove and re-add to mark as most recent\r\n cache.delete(path);\r\n } else if (cache.size >= maxCacheSize) {\r\n // Cache full: remove least recently used (first item in Map)\r\n const firstKey = cache.keys().next().value;\r\n if (firstKey) {\r\n cache.delete(firstKey);\r\n }\r\n }\r\n // Add/update as most recently used\r\n cache.set(path, content);\r\n};\r\n","import { getCachedComponentSource, setCachedComponentSource } from \"./cache\";\r\nimport { createError, ErrorCode } from \"../../utils/devWarnings\";\r\n\r\n/**\r\n * Resolves a component path, supporting folder-as-component pattern.\r\n * If the path doesn't end with .html, tries to resolve as:\r\n * 1. path/index.html (folder-as-component convention) - tried first to avoid 404 console noise\r\n * 2. Direct path (in case it's a file without extension configured by server)\r\n *\r\n * @example\r\n * // These are equivalent:\r\n * './components/header' -> './components/header/index.html'\r\n * './components/header/' -> './components/header/index.html'\r\n * './components/counter.html' -> './components/counter.html' (unchanged)\r\n */\r\nasync function resolveComponentPath(\r\n basePath: string\r\n): Promise<{ path: string; response: Response } | null>\r\n{\r\n // If path already has .html extension, use it directly\r\n if (basePath.endsWith(\".html\"))\r\n {\r\n const response = await fetch(basePath);\r\n if (response.ok)\r\n {\r\n return { path: basePath, response };\r\n }\r\n return null;\r\n }\r\n\r\n // Normalize path (remove trailing slash for consistent handling)\r\n const normalizedPath = basePath.endsWith(\"/\")\r\n ? basePath.slice(0, -1)\r\n : basePath;\r\n\r\n // Try folder/index.html pattern FIRST (folder-as-component convention)\r\n // This avoids 404 console errors from trying the direct path first\r\n const indexPath = `${normalizedPath}/index.html`;\r\n try\r\n {\r\n const indexResponse = await fetch(indexPath);\r\n if (indexResponse.ok)\r\n {\r\n return { path: indexPath, response: indexResponse };\r\n }\r\n } catch\r\n {\r\n // Ignore and try next resolution\r\n }\r\n\r\n // Fallback: Try direct path (some servers might serve HTML without extension)\r\n try\r\n {\r\n const directResponse = await fetch(normalizedPath);\r\n if (directResponse.ok)\r\n {\r\n const contentType = directResponse.headers.get(\"content-type\") || \"\";\r\n // Only accept if it's actually HTML\r\n if (contentType.includes(\"text/html\"))\r\n {\r\n return { path: normalizedPath, response: directResponse };\r\n }\r\n }\r\n } catch\r\n {\r\n // Ignore\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Result of fetching a component source\r\n */\r\nexport interface FetchComponentResult\r\n{\r\n /** The HTML source content */\r\n source: string;\r\n /** The actual resolved path (may differ from input for folder-as-component) */\r\n resolvedPath: string;\r\n}\r\n\r\nexport async function fetchComponentSource(\r\n path: string\r\n): Promise<FetchComponentResult>\r\n{\r\n if (!path?.trim())\r\n {\r\n throw createError(\r\n \"A component path is required.\",\r\n ErrorCode.INVALID_COMPONENT_PATH,\r\n null,\r\n \"Pass a URL or relative .html path to registerComponent().\",\r\n );\r\n }\r\n\r\n // check cache for component source\r\n const cachedSource = getCachedComponentSource(path);\r\n if (cachedSource)\r\n {\r\n // Return cached source with the original path\r\n // (we can't know the resolved path from cache alone, but the caller\r\n // should use the resolvedPath from the first fetch)\r\n return { source: cachedSource, resolvedPath: path };\r\n }\r\n\r\n const resolved = await resolveComponentPath(path);\r\n\r\n if (!resolved)\r\n {\r\n const attemptedPaths = path.endsWith(\".html\")\r\n ? path\r\n : `${path}/index.html and ${path}`;\r\n throw createError(\r\n `Could not load the component file. Tried ${attemptedPaths}.`,\r\n ErrorCode.COMPONENT_LOAD_FAILED,\r\n { sourcePath: path },\r\n \"Check the path, serve the app over HTTP, and make sure the server returns an HTML response.\",\r\n );\r\n }\r\n\r\n const text = await resolved.response.text();\r\n\r\n // Cache with both the original path and resolved path\r\n setCachedComponentSource(path, text);\r\n if (resolved.path !== path)\r\n {\r\n setCachedComponentSource(resolved.path, text);\r\n }\r\n\r\n return { source: text, resolvedPath: resolved.path };\r\n}\r\n","type StyleTarget = HTMLElement | ShadowRoot;\r\n\r\nexport const loadStyles = (\r\n target: StyleTarget,\r\n cssText: string | undefined,\r\n useShadowDOM: boolean\r\n): void => {\r\n if (!cssText) return;\r\n\r\n const styleEl = document.createElement(\"style\");\r\n styleEl.textContent = cssText;\r\n\r\n if (useShadowDOM) {\r\n target.appendChild(styleEl);\r\n } else {\r\n document.head.appendChild(styleEl);\r\n }\r\n};\r\n","import { BindingDescriptor } from \"../../types\";\r\n\r\nexport function analyzeBinding(\r\n raw: string\r\n): BindingDescriptor[\"bindings\"][number] {\r\n const trimmed = raw.trim();\r\n\r\n // Try to detect a top-level call expression: <callee>(<args>)\r\n const call = tryParseTopLevelCall(trimmed);\r\n if (call) {\r\n return {\r\n raw: trimmed,\r\n path: call.calleePath,\r\n isFunction: true,\r\n isExpression: true,\r\n functionArgs: call.args,\r\n };\r\n }\r\n\r\n // Try to detect a simple dotted path: foo.bar.baz\r\n const path = tryParsePath(trimmed);\r\n if (path) {\r\n return {\r\n raw: trimmed,\r\n path,\r\n isFunction: false,\r\n isExpression: false,\r\n };\r\n }\r\n\r\n // Otherwise, treat as an expression (ternaries, arithmetic, method chains, etc.)\r\n // For expressions we can't safely extract a single \"path\".\r\n return {\r\n raw: trimmed,\r\n path: [],\r\n isExpression: true,\r\n };\r\n}\r\n\r\nfunction tryParsePath(raw: string): string[] | null {\r\n // Allow identifiers like foo, $foo, _foo, foo123, and dotted paths.\r\n const re = /^[$A-Z_][0-9A-Z_$]*(?:\\s*\\.\\s*[$A-Z_][0-9A-Z_$]*)*$/i;\r\n if (!re.test(raw)) return null;\r\n return raw\r\n .split(\".\")\r\n .map((p) => p.trim())\r\n .filter((p) => p.length > 0);\r\n}\r\n\r\nfunction tryParseTopLevelCall(\r\n raw: string\r\n): { calleePath: string[]; args: string[] } | null {\r\n // Find the first \"(\" at top-level (not in quotes / nested structures)\r\n const openIndex = findFirstTopLevelChar(raw, \"(\");\r\n if (openIndex < 0) return null;\r\n\r\n // Ensure the raw ends with a matching \")\" at top-level\r\n const closeIndex = findMatchingParenIndex(raw, openIndex);\r\n if (closeIndex < 0) return null;\r\n if (raw.slice(closeIndex + 1).trim().length !== 0) return null;\r\n\r\n const calleeRaw = raw.slice(0, openIndex).trim();\r\n const calleePath = tryParsePath(calleeRaw);\r\n if (!calleePath) return null;\r\n\r\n const argsRaw = raw.slice(openIndex + 1, closeIndex);\r\n const args = splitTopLevelArgs(argsRaw);\r\n\r\n return { calleePath, args };\r\n}\r\n\r\nfunction splitTopLevelArgs(argsRaw: string): string[] {\r\n const args: string[] = [];\r\n let current = \"\";\r\n\r\n let parenDepth = 0;\r\n let bracketDepth = 0;\r\n let braceDepth = 0;\r\n\r\n let inSingle = false;\r\n let inDouble = false;\r\n let inTemplate = false;\r\n let escape = false;\r\n\r\n for (let i = 0; i < argsRaw.length; i++) {\r\n const ch = argsRaw[i];\r\n\r\n if (escape) {\r\n current += ch;\r\n escape = false;\r\n continue;\r\n }\r\n\r\n if (ch === \"\\\\\") {\r\n current += ch;\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (!inDouble && !inTemplate && ch === \"'\") {\r\n inSingle = !inSingle;\r\n current += ch;\r\n continue;\r\n }\r\n\r\n if (!inSingle && !inTemplate && ch === '\"') {\r\n inDouble = !inDouble;\r\n current += ch;\r\n continue;\r\n }\r\n\r\n // Template literals can contain commas in ${...}; we treat backticks as string boundaries.\r\n if (!inSingle && !inDouble && ch === \"`\") {\r\n inTemplate = !inTemplate;\r\n current += ch;\r\n continue;\r\n }\r\n\r\n if (!inSingle && !inDouble && !inTemplate) {\r\n if (ch === \"(\") parenDepth++;\r\n else if (ch === \")\") parenDepth = Math.max(0, parenDepth - 1);\r\n else if (ch === \"[\") bracketDepth++;\r\n else if (ch === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\r\n else if (ch === \"{\") braceDepth++;\r\n else if (ch === \"}\") braceDepth = Math.max(0, braceDepth - 1);\r\n\r\n // Split only on commas at top-level.\r\n if (\r\n ch === \",\" &&\r\n parenDepth === 0 &&\r\n bracketDepth === 0 &&\r\n braceDepth === 0\r\n ) {\r\n const value = current.trim();\r\n if (value.length > 0) args.push(value);\r\n current = \"\";\r\n continue;\r\n }\r\n }\r\n\r\n current += ch;\r\n }\r\n\r\n const last = current.trim();\r\n if (last.length > 0) args.push(last);\r\n\r\n return args;\r\n}\r\n\r\nfunction findFirstTopLevelChar(source: string, target: string): number {\r\n let parenDepth = 0;\r\n let bracketDepth = 0;\r\n let braceDepth = 0;\r\n\r\n let inSingle = false;\r\n let inDouble = false;\r\n let inTemplate = false;\r\n let escape = false;\r\n\r\n for (let i = 0; i < source.length; i++) {\r\n const ch = source[i];\r\n\r\n if (escape) {\r\n escape = false;\r\n continue;\r\n }\r\n if (ch === \"\\\\\") {\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (!inDouble && !inTemplate && ch === \"'\") {\r\n inSingle = !inSingle;\r\n continue;\r\n }\r\n if (!inSingle && !inTemplate && ch === '\"') {\r\n inDouble = !inDouble;\r\n continue;\r\n }\r\n if (!inSingle && !inDouble && ch === \"`\") {\r\n inTemplate = !inTemplate;\r\n continue;\r\n }\r\n\r\n if (inSingle || inDouble || inTemplate) continue;\r\n\r\n if (ch === \"(\") parenDepth++;\r\n else if (ch === \")\") parenDepth = Math.max(0, parenDepth - 1);\r\n else if (ch === \"[\") bracketDepth++;\r\n else if (ch === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\r\n else if (ch === \"{\") braceDepth++;\r\n else if (ch === \"}\") braceDepth = Math.max(0, braceDepth - 1);\r\n\r\n if (\r\n ch === target &&\r\n parenDepth === 0 &&\r\n bracketDepth === 0 &&\r\n braceDepth === 0\r\n ) {\r\n return i;\r\n }\r\n }\r\n\r\n return -1;\r\n}\r\n\r\nfunction findMatchingParenIndex(source: string, openIndex: number): number {\r\n // Assumes source[openIndex] === '(' and that it's top-level.\r\n let depth = 0;\r\n let inSingle = false;\r\n let inDouble = false;\r\n let inTemplate = false;\r\n let escape = false;\r\n\r\n for (let i = openIndex; i < source.length; i++) {\r\n const ch = source[i];\r\n\r\n if (escape) {\r\n escape = false;\r\n continue;\r\n }\r\n if (ch === \"\\\\\") {\r\n escape = true;\r\n continue;\r\n }\r\n\r\n if (!inDouble && !inTemplate && ch === \"'\") {\r\n inSingle = !inSingle;\r\n continue;\r\n }\r\n if (!inSingle && !inTemplate && ch === '\"') {\r\n inDouble = !inDouble;\r\n continue;\r\n }\r\n if (!inSingle && !inDouble && ch === \"`\") {\r\n inTemplate = !inTemplate;\r\n continue;\r\n }\r\n if (inSingle || inDouble || inTemplate) continue;\r\n\r\n if (ch === \"(\") depth++;\r\n else if (ch === \")\") {\r\n depth--;\r\n if (depth === 0) return i;\r\n if (depth < 0) return -1;\r\n }\r\n }\r\n\r\n return -1;\r\n}\r\n","/**\r\n * Lazy Loading Strategies for LadrillosJS\r\n *\r\n * control over when lazy components are loaded.\r\n */\r\n\r\n/**\r\n * A lazy loading strategy function.\r\n * @param load - Call this to trigger component loading\r\n * @param element - The placeholder element being observed\r\n * @returns Optional teardown function for cleanup\r\n */\r\nexport type LazyStrategy = (\r\n load: () => void,\r\n element: Element,\r\n) => (() => void) | void;\r\n\r\n/**\r\n * Factory function that creates a LazyStrategy with options\r\n */\r\nexport type LazyStrategyFactory<T = undefined> = T extends undefined\r\n ? () => LazyStrategy\r\n : (options?: T) => LazyStrategy;\r\n\r\n// Polyfills for Safari support\r\nconst requestIdleCallback: Window[\"requestIdleCallback\"] =\r\n (globalThis as any).requestIdleCallback ||\r\n ((cb: IdleRequestCallback) => setTimeout(cb, 1));\r\n\r\nconst cancelIdleCallback: Window[\"cancelIdleCallback\"] =\r\n (globalThis as any).cancelIdleCallback || ((id: number) => clearTimeout(id));\r\n\r\n/**\r\n * Load when the browser is idle.\r\n * Uses requestIdleCallback with a timeout fallback.\r\n *\r\n * @param timeout - Max wait time in ms before forcing load (default: 10000)\r\n *\r\n * @example\r\n * { name: 'analytics', path: './analytics.html', lazy: lazyOnIdle(5000) }\r\n */\r\nexport const lazyOnIdle: LazyStrategyFactory<number> =\r\n (timeout = 10000) =>\r\n (load) => {\r\n const id = requestIdleCallback(load, { timeout });\r\n return () => cancelIdleCallback(id);\r\n };\r\n\r\n/**\r\n * Load when element becomes visible in viewport.\r\n * Uses IntersectionObserver for efficient visibility detection.\r\n *\r\n * @param options - IntersectionObserver options (rootMargin, threshold, etc.)\r\n *\r\n * @example\r\n * // Load when 100px before entering viewport\r\n * { name: 'footer', path: './footer.html', lazy: lazyOnVisible({ rootMargin: '100px' }) }\r\n */\r\nexport const lazyOnVisible: LazyStrategyFactory<IntersectionObserverInit> =\r\n (options) => (load, element) => {\r\n // Check if already visible (handles edge case of element in viewport on mount)\r\n if (elementIsVisibleInViewport(element)) {\r\n load();\r\n return;\r\n }\r\n\r\n const observer = new IntersectionObserver((entries) => {\r\n for (const entry of entries) {\r\n if (entry.isIntersecting) {\r\n observer.disconnect();\r\n load();\r\n break;\r\n }\r\n }\r\n }, options);\r\n\r\n observer.observe(element);\r\n return () => observer.disconnect();\r\n };\r\n\r\n/**\r\n * Load when specified media query matches.\r\n * Useful for mobile-only or desktop-only components.\r\n *\r\n * @param query - CSS media query string\r\n *\r\n * @example\r\n * { name: 'mobile-nav', path: './mobile-nav.html', lazy: lazyOnMedia('(max-width: 768px)') }\r\n */\r\nexport const lazyOnMedia: LazyStrategyFactory<string> = (query) => (load) => {\r\n if (!query) {\r\n load();\r\n return;\r\n }\r\n\r\n const mql = matchMedia(query);\r\n if (mql.matches) {\r\n load();\r\n return;\r\n }\r\n const handler = () => load();\r\n mql.addEventListener(\"change\", handler, { once: true });\r\n return () => mql.removeEventListener(\"change\", handler);\r\n};\r\n\r\n/**\r\n * Load when user interacts with the element.\r\n * Replays the triggering event after component loads for seamless UX.\r\n *\r\n * @param events - Event type(s) to listen for (default: ['click', 'focusin'])\r\n *\r\n * @example\r\n * { name: 'modal', path: './modal.html', lazy: lazyOnInteraction('click') }\r\n * { name: 'form', path: './form.html', lazy: lazyOnInteraction(['focus', 'click']) }\r\n */\r\nexport const lazyOnInteraction: LazyStrategyFactory<string | string[]> = (\r\n events = [\"click\", \"focusin\"],\r\n) => {\r\n const eventList = typeof events === \"string\" ? [events] : events;\r\n\r\n return (load: () => void, element: Element) => {\r\n let hasLoaded = false;\r\n\r\n const handler = (e: Event) => {\r\n if (hasLoaded) return;\r\n hasLoaded = true;\r\n teardown();\r\n load();\r\n\r\n // Replay the event after a microtask (allows component to mount)\r\n queueMicrotask(() => {\r\n if (e.target && e.target instanceof Element) {\r\n e.target.dispatchEvent(new (e.constructor as any)(e.type, e));\r\n }\r\n });\r\n };\r\n\r\n const teardown = () => {\r\n for (const evt of eventList) {\r\n element.removeEventListener(evt, handler);\r\n }\r\n };\r\n\r\n for (const evt of eventList) {\r\n element.addEventListener(evt, handler, { once: true, passive: true });\r\n }\r\n\r\n return teardown;\r\n };\r\n};\r\n\r\n/**\r\n * Load after a specified delay.\r\n * Simple time-based loading for non-critical components.\r\n *\r\n * @param ms - Delay in milliseconds\r\n *\r\n * @example\r\n * { name: 'chat-widget', path: './chat.html', lazy: lazyOnDelay(3000) }\r\n */\r\nexport const lazyOnDelay: LazyStrategyFactory<number> =\r\n (ms = 0) =>\r\n (load) => {\r\n const id = setTimeout(load, ms);\r\n return () => clearTimeout(id);\r\n };\r\n\r\n// Helper to check if element is in viewport\r\nfunction elementIsVisibleInViewport(el: Element): boolean {\r\n const { top, left, bottom, right } = el.getBoundingClientRect();\r\n const { innerHeight, innerWidth } = window;\r\n return (\r\n ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&\r\n ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))\r\n );\r\n}\r\n\r\n/**\r\n * Default lazy strategy - loads when visible with 100px root margin\r\n * for smooth loading before element enters viewport\r\n */\r\nexport const defaultLazyStrategy = lazyOnVisible({ rootMargin: \"100px\" });\r\n","/**\n * <lazy> built-in element handler.\n *\n * Two modes:\n * 1. Inline content: <lazy margin=\"100px\"><heavy /></lazy>\n * Children are detached and re-inserted when the strategy fires.\n * 2. Component source: <lazy src=\"./chart.html\" component=\"my-chart\" idle></lazy>\n * Registers the component lazily and replaces the placeholder with it.\n *\n * Strategy props (resolved in priority order):\n * eager > interaction > media > delay > idle/idle-timeout > visible/margin/threshold\n *\n * A nested <template slot=\"placeholder\"> can supply hold-while-loading content.\n *\n * Performance notes:\n * - Children are moved to a detached DocumentFragment in one DOM op.\n * - Strategy listeners only attach when the element is connected to the DOM.\n * - Each <lazy> uses exactly one comment placeholder; no per-iteration cost.\n */\n\nimport {\n LazyStrategy,\n lazyOnVisible,\n lazyOnIdle,\n lazyOnDelay,\n lazyOnInteraction,\n lazyOnMedia,\n defaultLazyStrategy,\n} from \"../lazy/lazyStrategies\";\nimport { warn } from \"../../utils/devWarnings\";\n\n/**\n * Lazily import the framework's component registrar to avoid a circular\n * dependency: directiveProcessor → builtins/lazyElement → ladrillos →\n * component/webcomponent → directiveProcessor.\n */\nasync function registerComponentLazily(\n name: string,\n path: string,\n): Promise<void> {\n const mod = await import(\"../ladrillos\");\n return mod.ladrillos.registerComponent(name, path, true, false);\n}\n\n/**\n * Pick a LazyStrategy from the attributes on a <lazy> element.\n * Returns `null` for `eager` (= load immediately, no observation needed).\n */\nexport function resolveLazyStrategy(el: Element): LazyStrategy | null {\n if (el.hasAttribute(\"eager\")) return null;\n\n // 1. interaction\n if (el.hasAttribute(\"interaction\")) {\n const raw = (el.getAttribute(\"interaction\") || \"\").trim();\n if (!raw) return lazyOnInteraction();\n const events = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n // Cast: lazyOnInteraction's typed signature collapses to `string & string[]`\n // due to distributive conditional types. Both `string` and `string[]` are\n // valid runtime arguments per the implementation.\n const li = lazyOnInteraction as unknown as (\n events?: string | string[],\n ) => LazyStrategy;\n if (events.length === 1) return li(events[0]);\n return li(events);\n }\n\n // 2. media\n if (el.hasAttribute(\"media\")) {\n const q = el.getAttribute(\"media\") || \"\";\n return lazyOnMedia(q);\n }\n\n // 3. delay\n if (el.hasAttribute(\"delay\")) {\n const ms = Number(el.getAttribute(\"delay\")) || 0;\n return lazyOnDelay(ms);\n }\n\n // 4. idle / idle-timeout\n if (el.hasAttribute(\"idle\") || el.hasAttribute(\"idle-timeout\")) {\n const t = el.getAttribute(\"idle-timeout\");\n return t ? lazyOnIdle(Number(t) || 10000) : lazyOnIdle();\n }\n\n // 5. visible / margin / threshold (default)\n const opts: IntersectionObserverInit = {};\n const margin = el.getAttribute(\"margin\");\n if (margin) opts.rootMargin = margin;\n const threshold = el.getAttribute(\"threshold\");\n if (threshold !== null) {\n const n = Number(threshold);\n if (!Number.isNaN(n)) opts.threshold = n;\n }\n if (Object.keys(opts).length > 0) return lazyOnVisible(opts);\n // Plain <lazy> with nothing → default visible strategy.\n return defaultLazyStrategy;\n}\n\n/**\n * Convert a path like \"./components/heavy-chart.html\" → \"heavy-chart\".\n */\nfunction tagFromPath(path: string): string {\n const file =\n path\n .split(/[?#]/)[0]\n .split(\"/\")\n .pop()\n ?.replace(/\\.[^.]+$/, \"\") || path;\n return file\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[_\\s]+/g, \"-\")\n .toLowerCase();\n}\n\n/** Pull a `<template slot=\"placeholder\">` out of `<lazy>` if present. */\nfunction extractPlaceholder(lazyEl: Element): DocumentFragment | null {\n const tpl = lazyEl.querySelector(\n ':scope > template[slot=\"placeholder\"]',\n ) as HTMLTemplateElement | null;\n if (!tpl) return null;\n tpl.remove();\n return tpl.content.cloneNode(true) as DocumentFragment;\n}\n\n/**\n * Process a single <lazy> element. Removes it from the DOM and replaces it\n * with a comment placeholder + (optional) placeholder content. Schedules the\n * actual content to swap in when the chosen strategy fires.\n */\nexport function processLazyElement(lazyEl: Element): void {\n const parent = lazyEl.parentNode;\n if (!parent) return;\n\n const strategy = resolveLazyStrategy(lazyEl);\n const src = lazyEl.getAttribute(\"src\");\n const componentAttr = lazyEl.getAttribute(\"component\");\n\n // Carry over attributes to the loaded element (excluding strategy props).\n const STRATEGY_ATTRS = new Set([\n \"eager\",\n \"visible\",\n \"margin\",\n \"threshold\",\n \"idle\",\n \"idle-timeout\",\n \"delay\",\n \"interaction\",\n \"media\",\n \"src\",\n \"component\",\n ]);\n\n // Anchor for re-insertion. Using a Comment lets us insert in O(1).\n const anchor = document.createComment(\n src ? ` <lazy src=\"${src}\"> ` : ` <lazy> `,\n );\n parent.insertBefore(anchor, lazyEl);\n lazyEl.remove();\n\n // -------------------------------------------------------------------------\n // MODE A: src — register a component lazily and swap to <tag-name>\n // -------------------------------------------------------------------------\n if (src) {\n const tagName = (componentAttr || tagFromPath(src)).trim();\n if (!tagName.includes(\"-\")) {\n warn(\n `<lazy src=\"${src}\">: derived tag name \"${tagName}\" must contain a hyphen. ` +\n `Provide a 'component' attribute, e.g. <lazy src=\"${src}\" component=\"my-thing\">.`,\n );\n return;\n }\n\n const placeholder = extractPlaceholder(lazyEl);\n\n const swap = () => {\n const real = document.createElement(tagName);\n // Forward non-strategy attributes onto the loaded element.\n for (const attr of Array.from(lazyEl.attributes)) {\n if (!STRATEGY_ATTRS.has(attr.name)) {\n real.setAttribute(attr.name, attr.value);\n }\n }\n anchor.parentNode?.replaceChild(real, anchor);\n // Anything we showed as placeholder is removed automatically because\n // we hold it in a fragment that's attached only between anchor and...\n // (see below: we track the placeholder nodes explicitly).\n };\n\n // Render placeholder content (if any) between anchor and a sentinel.\n let placeholderEnd: Comment | null = null;\n if (placeholder) {\n placeholderEnd = document.createComment(\" /lazy-placeholder \");\n anchor.parentNode?.insertBefore(placeholderEnd, anchor.nextSibling);\n anchor.parentNode?.insertBefore(placeholder, placeholderEnd);\n }\n\n const trigger = async () => {\n try {\n // Register if not already registered (idempotent at app level).\n if (!customElements.get(tagName)) {\n await registerComponentLazily(tagName, src);\n }\n // Remove placeholder nodes between anchor and placeholderEnd.\n if (placeholderEnd) {\n let n = anchor.nextSibling;\n while (n && n !== placeholderEnd) {\n const next = n.nextSibling;\n n.parentNode?.removeChild(n);\n n = next;\n }\n placeholderEnd.parentNode?.removeChild(placeholderEnd);\n }\n swap();\n } catch (e) {\n warn(\n `<lazy src=\"${src}\"> failed to load: ${(e as Error).message}`,\n );\n }\n };\n\n if (!strategy) {\n // eager\n void trigger();\n return;\n }\n\n // Use anchor (a Comment) as the observable target — but observers need an\n // Element. Insert a zero-size sentinel for IntersectionObserver /\n // interaction listeners to attach to. Note: we cannot use\n // `display:contents` here because such elements have no layout box and\n // IntersectionObserver will never report them as intersecting.\n const sentinel = document.createElement(\"span\");\n sentinel.setAttribute(\"data-lazy-sentinel\", \"\");\n sentinel.style.cssText =\n \"display:inline-block;width:0;height:0;padding:0;margin:0;border:0;\";\n anchor.parentNode?.insertBefore(sentinel, anchor.nextSibling);\n\n let teardown: (() => void) | void;\n const fire = () => {\n teardown?.();\n sentinel.remove();\n void trigger();\n };\n teardown = strategy(fire, sentinel);\n return;\n }\n\n // -------------------------------------------------------------------------\n // MODE B: inline content — show children when strategy fires\n // -------------------------------------------------------------------------\n const placeholder = extractPlaceholder(lazyEl);\n\n // Detach inline children into a fragment in one shot.\n const content = document.createDocumentFragment();\n while (lazyEl.firstChild) content.appendChild(lazyEl.firstChild);\n\n // Insert placeholder content between anchor and end-sentinel so we can\n // remove it cleanly when content swaps in.\n const end = document.createComment(\" /lazy \");\n anchor.parentNode?.insertBefore(end, anchor.nextSibling);\n if (placeholder) {\n anchor.parentNode?.insertBefore(placeholder, end);\n }\n\n const reveal = () => {\n // Remove placeholder content (everything between anchor and end).\n let n = anchor.nextSibling;\n while (n && n !== end) {\n const next = n.nextSibling;\n n.parentNode?.removeChild(n);\n n = next;\n }\n // Insert real content in one DOM op.\n end.parentNode?.insertBefore(content, end);\n };\n\n if (!strategy) {\n reveal();\n return;\n }\n\n // Note: cannot use `display:contents` — such elements have no layout box\n // and IntersectionObserver will never report them as intersecting.\n const sentinel = document.createElement(\"span\");\n sentinel.setAttribute(\"data-lazy-sentinel\", \"\");\n sentinel.style.cssText =\n \"display:inline-block;width:0;height:0;padding:0;margin:0;border:0;\";\n anchor.parentNode?.insertBefore(sentinel, anchor.nextSibling);\n\n // Stash the detached content fragment on the sentinel so other scanners\n // (binding scanner, inline-event-handler transformer, directive scanner)\n // can recurse into it via `getPendingLazyContent(host)`. Wiring inside the\n // detached fragment is preserved when reveal moves the same nodes into\n // the host tree, so `<lazy>`-wrapped content behaves exactly like inline\n // content for bindings, listeners, refs, $for, $if, etc.\n (sentinel as any).__lazyContent = content;\n\n let teardown: (() => void) | void;\n const fire = () => {\n teardown?.();\n sentinel.remove();\n reveal();\n };\n teardown = strategy(fire, sentinel);\n}\n\n/**\n * Find and process all top-level <lazy> elements in `host`. <lazy> elements\n * inside <for> templates are skipped; they get processed when the loop\n * renders each iteration via processLazyElement on the cloned content.\n *\n * Accepts a connected host OR a detached DocumentFragment — the latter is\n * used by `loadTemplate` to preprocess <lazy> before any custom-element\n * children get a chance to fire connectedCallback (and drain their light\n * DOM into __originalChildren). Without this preprocessing, lazy's\n * detach-then-reattach cycle would re-run children's connectedCallback with\n * an empty innerHTML, breaking components that read $host.__originalHTML.\n */\nexport function scanLazyElements(\n host: HTMLElement | ShadowRoot | DocumentFragment,\n): void {\n // Snapshot once — processing mutates the DOM.\n const lazyEls = Array.from(host.querySelectorAll(\"lazy\"));\n for (const el of lazyEls) {\n if (isInsideForElement(el)) continue;\n processLazyElement(el);\n }\n}\n\nfunction isInsideForElement(el: Element): boolean {\n let p: Element | null = el.parentElement;\n while (p) {\n if (p.tagName === \"FOR\") return true;\n p = p.parentElement;\n }\n return false;\n}\n\n/**\n * Returns all detached DocumentFragments held by pending `<lazy>` placeholders\n * inside `host`. Used by binding/event-handler/directive scanners to wire up\n * the children of `<lazy>` elements while they are still detached from the\n * document. Wiring done on these fragments survives the later move into the\n * host tree when the lazy strategy fires.\n *\n * Returns an empty array for hosts that contain no pending lazy fragments.\n */\nexport function getPendingLazyContent(\n host: HTMLElement | ShadowRoot | DocumentFragment,\n): DocumentFragment[] {\n const out: DocumentFragment[] = [];\n const sentinels = host.querySelectorAll(\"[data-lazy-sentinel]\");\n for (const s of Array.from(sentinels)) {\n const frag = (s as any).__lazyContent as DocumentFragment | undefined;\n if (frag) out.push(frag);\n }\n return out;\n}\n","import { BindingDescriptor } from \"../../types\";\r\nimport { REGEX_PATTERNS } from \"../../utils/regex\";\r\nimport { analyzeBinding } from \"../component/bindingParser\";\r\nimport {\r\n scanLazyElements,\r\n getPendingLazyContent,\r\n} from \"../builtins/lazyElement\";\r\nimport {\r\n escapeControlTags,\r\n restoreControlTags,\r\n} from \"./controlTagEscape\";\r\n\r\ntype TemplateLoadResult = {\r\n bindings: BindingDescriptor[];\r\n};\r\n\r\n/**\r\n * Injects the template HTML into the host element and scans for data bindings.\r\n * Returns a list of all bindings found in text nodes and attributes.\r\n *\r\n * Directive scanning ($for / $if / $show / $bind) is performed separately\r\n * by `scanDirectivesWithRefs` in the web component lifecycle.\r\n *\r\n * <lazy> elements are preprocessed here in a detached <template> fragment so\r\n * their children never get connected (and thus never fire connectedCallback /\r\n * drain their light DOM) before lazy detaches them. Without this, components\r\n * inside <lazy> that read `$host.__originalHTML` would see an empty string on\r\n * the second connect after lazy reveals them.\r\n */\r\nexport const loadTemplate = (\r\n host: HTMLElement | ShadowRoot,\r\n template: string,\r\n): TemplateLoadResult => {\r\n // Parse into a detached <template> first. Its .content is a DocumentFragment\r\n // that is NOT connected to the document, so custom-element connectedCallback\r\n // will not fire for any children inside.\r\n //\r\n // <lazy> is processed here while children are still detached: it moves its\r\n // children into a closure-held DocumentFragment (also detached) so inner\r\n // custom elements never fire connectedCallback prematurely. The fragment is\r\n // stashed on a sentinel inside `tpl.content` so subsequent scanners can\r\n // still find and wire its contents (bindings, listeners, directives).\r\n const tpl = document.createElement(\"template\");\r\n // Escape control elements (<for>, <if>, …) to <template> placeholders\r\n // before parsing so table insertion modes cannot foster-parent them out\r\n // of <table>/<tbody>/<tr>, then rebuild them with DOM APIs.\r\n tpl.innerHTML = escapeControlTags(template);\r\n restoreControlTags(tpl.content);\r\n scanLazyElements(tpl.content);\r\n host.innerHTML = \"\";\r\n host.appendChild(tpl.content);\r\n\r\n // Scan bindings on host AND on each pending <lazy> content fragment.\r\n // Lazy-content fragments are detached, but binding descriptors hold direct\r\n // node references that survive the later DOM move into the host tree, so\r\n // {} text and attribute bindings inside <lazy> work the same as inline.\r\n const bindings = getBindings(host);\r\n for (const frag of getPendingLazyContent(host)) {\r\n bindings.push(...getBindings(frag));\r\n }\r\n return { bindings };\r\n};\r\n\r\nfunction getBindings(host: HTMLElement | ShadowRoot | DocumentFragment) {\r\n const bindings: BindingDescriptor[] = [];\r\n\r\n // 1. Find text nodes with {} bindings\r\n const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, null);\r\n let node: Text | null;\r\n\r\n while ((node = walker.nextNode() as Text | null)) {\r\n // Skip nodes that are inside loop elements or $no:bind elements\r\n if (isInsideLoopElement(node) || isInsideNoBind(node)) {\r\n continue;\r\n }\r\n\r\n const textContent = node.textContent;\r\n if (!textContent) continue;\r\n const matches = [...textContent.matchAll(REGEX_PATTERNS.bindings)];\r\n\r\n if (matches.length > 0) {\r\n const original = textContent;\r\n\r\n const nodeBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n return analyzeBinding(raw);\r\n });\r\n\r\n bindings.push({\r\n node,\r\n bindings: nodeBindings,\r\n original,\r\n });\r\n }\r\n }\r\n\r\n // 2. Find attribute bindings\r\n const attrBindings = getAttributeBindings(host);\r\n bindings.push(...attrBindings);\r\n\r\n return bindings;\r\n}\r\n\r\n/**\r\n * Scan all elements for attributes containing {} bindings\r\n */\r\nfunction getAttributeBindings(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n): BindingDescriptor[] {\r\n const bindings: BindingDescriptor[] = [];\r\n\r\n // Directive attributes that should NOT be treated as regular bindings\r\n // These are handled by the directive processor, not the binding system.\r\n // Built-in elements (<if>, <else-if>, <for>, <show>, <lazy>) are handled\r\n // separately at the element level (see scanLoops/scanConditionals/etc.).\r\n const directiveAttributes = [\r\n \"$bind\",\r\n \"$ref\",\r\n \"$no:bind\",\r\n \"condition\", // <if condition=\"…\">, <show condition=\"…\">\r\n \"each\", // <for each=\"…\">\r\n \"key\", // <for key=\"…\">\r\n \"track-by\", // <for track-by=\"…\">\r\n ];\r\n\r\n // Get all elements in the host\r\n const elements = Array.from(host.querySelectorAll(\"*\"));\r\n\r\n for (const element of elements) {\r\n // Skip elements inside <for> templates – the loop renderer handles their\r\n // bindings per-iteration.\r\n if (element.tagName === \"FOR\" || isInsideLoopElement(element)) {\r\n continue;\r\n }\r\n\r\n // Skip elements with $no:bind or inside $no:bind elements\r\n if (element.hasAttribute(\"$no:bind\") || isInsideNoBind(element)) {\r\n continue;\r\n }\r\n\r\n // Check each attribute\r\n for (const attr of Array.from(element.attributes) as Attr[]) {\r\n // Skip directive attributes - they're handled separately\r\n if (directiveAttributes.includes(attr.name)) {\r\n continue;\r\n }\r\n\r\n const matches = [...attr.value.matchAll(REGEX_PATTERNS.bindings)];\r\n\r\n if (matches.length > 0) {\r\n // Create a placeholder text node to store binding info\r\n // (We need a Text node for the BindingDescriptor structure)\r\n const placeholderNode = document.createTextNode(attr.value);\r\n\r\n const attrBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n return analyzeBinding(raw);\r\n });\r\n\r\n bindings.push({\r\n node: placeholderNode,\r\n bindings: attrBindings,\r\n original: attr.value,\r\n isAttribute: true,\r\n attributeName: attr.name,\r\n // Store reference to the element for attribute updates\r\n element: element as HTMLElement,\r\n } as BindingDescriptor & { element: HTMLElement });\r\n }\r\n }\r\n }\r\n\r\n return bindings;\r\n}\r\n\r\nfunction isInsideLoopElement(node: Node): boolean {\r\n let current: Element | null =\r\n node.nodeType === Node.ELEMENT_NODE\r\n ? (node as Element).parentElement\r\n : node.parentElement;\r\n while (current) {\r\n if (current.tagName === \"FOR\") {\r\n return true;\r\n }\r\n current = current.parentElement;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if a node is inside an element with $no:bind attribute.\r\n * Elements with $no:bind skip all binding processing - useful for\r\n * displaying literal template syntax like {name} in documentation.\r\n *\r\n * @example\r\n * <code $no:bind>{name}</code> <!-- Renders literally as \"{name}\" -->\r\n */\r\nfunction isInsideNoBind(node: Node): boolean {\r\n let current = node.parentElement;\r\n while (current) {\r\n if (current.hasAttribute && current.hasAttribute(\"$no:bind\")) {\r\n return true;\r\n }\r\n current = current.parentElement;\r\n }\r\n return false;\r\n}\r\n","/**\r\n * List of inline event handler attributes to transform\r\n */\r\nexport const EVENT_ATTRIBUTES = [\r\n 'onclick', 'ondblclick', 'onmousedown', 'onmouseup', 'onmouseover',\r\n 'onmouseout', 'onmousemove', 'onmouseenter', 'onmouseleave',\r\n 'onkeydown', 'onkeyup', 'onkeypress',\r\n 'onfocus', 'onblur', 'onchange', 'oninput', 'onsubmit', 'onreset',\r\n 'onscroll', 'onload', 'onerror',\r\n 'ontouchstart', 'ontouchmove', 'ontouchend', 'ontouchcancel',\r\n 'ondragstart', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave',\r\n 'ondragover', 'ondrop'\r\n];\r\n\r\n/**\r\n * Set form for O(1) membership checks on hot paths (per-attribute checks\r\n * while rendering loop rows).\r\n */\r\nexport const EVENT_ATTRIBUTE_SET = new Set(EVENT_ATTRIBUTES);\r\n","/**\r\n * LadrillosJS Directives\r\n *\r\n * Directives are special attributes that provide reactive behavior to elements.\r\n * Unlike interpolation which uses curly braces {value}, directives receive raw expressions.\r\n *\r\n * Syntax Pattern:\r\n * - Directives: $directive=\"expression\"\r\n * - Interpolation: {expression}\r\n */\r\n\r\n/**\r\n * $for - Loop Directive\r\n *\r\n * Repeats an element for each item in an iterable.\r\n *\r\n * Syntax:\r\n * $for=\"item in items\"\r\n * $for=\"item of items\"\r\n * $for=\"(item, index) in items\"\r\n * $for=\"(value, key, index) in object\"\r\n *\r\n * Examples:\r\n * <li $for=\"item in items\">{item.name}</li>\r\n * <li $for=\"(item, index) in items\">{index}: {item.name}</li>\r\n * <option $for=\"(value, key) in options\" value=\"{key}\">{value}</option>\r\n *\r\n * Destructuring:\r\n * <div $for=\"{ id, name } in users\">{id}: {name}</div>\r\n * <div $for=\"[first, second] in pairs\">{first} - {second}</div>\r\n */\r\nexport const FOR_DIRECTIVE = \"$for\";\r\n\r\n/**\r\n * $if - Conditional Directive\r\n *\r\n * Conditionally renders an element based on a truthy expression.\r\n *\r\n * Syntax:\r\n * $if=\"condition\"\r\n *\r\n * Examples:\r\n * <div $if=\"isVisible\">Visible content</div>\r\n * <div $if=\"user.isAdmin\">Admin panel</div>\r\n * <div $if=\"items.length > 0\">Has items</div>\r\n */\r\nexport const IF_DIRECTIVE = \"$if\";\r\n\r\n/**\r\n * $else - Else Directive\r\n *\r\n * Renders when the preceding $if condition is falsy.\r\n * Must immediately follow an element with $if.\r\n *\r\n * Syntax:\r\n * $else\r\n *\r\n * Examples:\r\n * <div $if=\"isLoggedIn\">Welcome back!</div>\r\n * <div $else>Please log in</div>\r\n */\r\nexport const ELSE_DIRECTIVE = \"$else\";\r\n\r\n/**\r\n * $else-if - Else If Directive\r\n *\r\n * Conditional fallback when preceding $if is falsy.\r\n * Must immediately follow an element with $if or $else-if.\r\n *\r\n * Syntax:\r\n * $else-if=\"condition\"\r\n *\r\n * Examples:\r\n * <div $if=\"status === 'loading'\">Loading...</div>\r\n * <div $else-if=\"status === 'error'\">Error occurred</div>\r\n * <div $else>Content loaded</div>\r\n */\r\nexport const ELSE_IF_DIRECTIVE = \"$else-if\";\r\n\r\n/**\r\n * $show - Show/Hide Directive\r\n *\r\n * Toggles element visibility using CSS display property.\r\n * Unlike $if, the element remains in the DOM.\r\n *\r\n * Syntax:\r\n * $show=\"condition\"\r\n *\r\n * Examples:\r\n * <div $show=\"isExpanded\">Expandable content</div>\r\n * <span $show=\"hasNotifications\">🔔</span>\r\n */\r\nexport const SHOW_DIRECTIVE = \"$show\";\r\n\r\n/**\r\n * $bind - Two-way Binding Directive\r\n *\r\n * Creates a two-way binding between an input and a reactive value.\r\n *\r\n * Syntax:\r\n * $bind=\"variableName\"\r\n *\r\n * Examples:\r\n * <input type=\"text\" $bind=\"username\">\r\n * <textarea $bind=\"message\"></textarea>\r\n * <select $bind=\"selectedOption\">...</select>\r\n */\r\nexport const BIND_DIRECTIVE = \"$bind\";\r\n\r\n/**\r\n * Ensures a $bind element's value is synced to state before a user event\r\n * handler for the same event runs.\r\n *\r\n * Inline handlers (onchange, oninput, $on:) are registered before $bind's\r\n * own listener, so without this the handler would read the previous value\r\n * from state. setupTwoWayBinding stores the sync function on the element;\r\n * handler wrappers call this first so user code always sees fresh state.\r\n */\r\nexport function syncBindBeforeHandler(event: Event): void\r\n{\r\n const bindSync = (event.currentTarget as any)?.__ladrillosBindSync;\r\n if (bindSync && bindSync.eventType === event.type)\r\n {\r\n bindSync.sync();\r\n }\r\n}\r\n\r\n/**\r\n * $ref - Reference Directive\r\n *\r\n * Creates a reference to the DOM element.\r\n *\r\n * Syntax:\r\n * $ref=\"referenceName\"\r\n *\r\n * Examples:\r\n * <input $ref=\"inputElement\">\r\n * <canvas $ref=\"canvasRef\"></canvas>\r\n */\r\nexport const REF_DIRECTIVE = \"$ref\";\r\n\r\n// Directive parsing patterns\r\nexport const DIRECTIVE_PATTERNS = {\r\n /**\r\n * Matches for/of loop expressions:\r\n * - \"item in items\"\r\n * - \"(item, index) in items\"\r\n * - \"{ id, name } of users\"\r\n */\r\n forAlias: /([\\s\\S]*?)\\s+(?:in|of)\\s+([\\s\\S]+)$/,\r\n\r\n /**\r\n * Matches iterator with optional key/index:\r\n * - \"item\" -> [item]\r\n * - \"item, index\" -> [item, index]\r\n * - \"value, key, index\" -> [value, key, index]\r\n */\r\n forIterator: /,([^,\\}\\]]*)(?:,([^,\\}\\]]*))?$/,\r\n\r\n /**\r\n * Strips parentheses from iterator expression:\r\n * \"(item, index)\" -> \"item, index\"\r\n */\r\n stripParens: /^\\(|\\)$/g,\r\n} as const;\r\n\r\n// List of all supported directives\r\nexport const SUPPORTED_DIRECTIVES = [\r\n FOR_DIRECTIVE,\r\n IF_DIRECTIVE,\r\n ELSE_DIRECTIVE,\r\n ELSE_IF_DIRECTIVE,\r\n SHOW_DIRECTIVE,\r\n BIND_DIRECTIVE,\r\n REF_DIRECTIVE,\r\n] as const;\r\n\r\nexport type DirectiveName = (typeof SUPPORTED_DIRECTIVES)[number];\r\n\r\n/**\r\n * Escapes a directive name for use in CSS selectors.\r\n * The $ character is not valid in CSS selectors and must be escaped.\r\n *\r\n * Example: \"$for\" -> \"\\\\$for\"\r\n */\r\nexport function escapeCssSelector(directive: string): string {\r\n return directive.replace(/\\$/g, \"\\\\$\");\r\n}\r\n\r\n/**\r\n * Check if an attribute name is a directive\r\n */\r\nexport function isDirective(attrName: string): boolean {\r\n return (\r\n attrName.startsWith(\"$\") ||\r\n SUPPORTED_DIRECTIVES.includes(attrName as DirectiveName)\r\n );\r\n}\r\n","/**\r\n * NOT A SECURITY SANDBOX.\r\n *\r\n * Despite the filename, this module does not sandbox untrusted code. Component\r\n * scripts run with full access to the page (window, document, fetch, …) — see\r\n * the \"Security & Trust Model\" section of the README. Component HTML is trusted\r\n * code, exactly like a `.js` file you import. The lists below are a *scoping\r\n * convenience* (which names are injected as parameters so component code reads\r\n * like plain JS), not a trust boundary. Do not rely on them to run untrusted\r\n * component files.\r\n */\r\n\r\n/**\r\n * Globals that are explicitly injected into the scope.\r\n * These are passed as function parameters with their actual values.\r\n *\r\n * Note: With BLOCKED_GLOBALS now empty, most browser APIs are accessible\r\n * directly through the global scope (window). This list is for convenience\r\n * to ensure common APIs work without window. prefix.\r\n */\r\nexport const ALLOWED_GLOBALS = Object.freeze([\r\n // User dialogs\r\n \"alert\",\r\n \"confirm\",\r\n \"prompt\",\r\n // Debugging\r\n \"console\",\r\n // Data & Types\r\n \"JSON\",\r\n \"Math\",\r\n \"Date\",\r\n \"Array\",\r\n \"Object\",\r\n \"String\",\r\n \"Number\",\r\n \"Boolean\",\r\n \"Map\",\r\n \"Set\",\r\n \"WeakMap\",\r\n \"WeakSet\",\r\n \"Symbol\",\r\n \"BigInt\",\r\n \"Promise\",\r\n \"Proxy\",\r\n \"Reflect\",\r\n // Number utilities\r\n \"parseInt\",\r\n \"parseFloat\",\r\n \"isNaN\",\r\n \"isFinite\",\r\n \"Infinity\",\r\n \"NaN\",\r\n // URL encoding\r\n \"encodeURIComponent\",\r\n \"decodeURIComponent\",\r\n \"encodeURI\",\r\n \"decodeURI\",\r\n // Timers\r\n \"setTimeout\",\r\n \"clearTimeout\",\r\n \"setInterval\",\r\n \"clearInterval\",\r\n \"requestAnimationFrame\",\r\n \"cancelAnimationFrame\",\r\n \"requestIdleCallback\",\r\n \"cancelIdleCallback\",\r\n \"queueMicrotask\",\r\n // Network\r\n \"fetch\",\r\n \"AbortController\",\r\n \"AbortSignal\",\r\n \"Headers\",\r\n \"Request\",\r\n \"Response\",\r\n \"URL\",\r\n \"URLSearchParams\",\r\n // Browser APIs\r\n \"navigator\",\r\n \"location\",\r\n \"history\",\r\n \"localStorage\",\r\n \"sessionStorage\",\r\n \"crypto\",\r\n // DOM\r\n \"document\",\r\n \"window\",\r\n \"globalThis\",\r\n \"Element\",\r\n \"HTMLElement\",\r\n \"Event\",\r\n \"CustomEvent\",\r\n \"EventTarget\",\r\n // Text\r\n \"TextEncoder\",\r\n \"TextDecoder\",\r\n \"Blob\",\r\n \"File\",\r\n \"FileReader\",\r\n \"FormData\",\r\n // Error types\r\n \"Error\",\r\n \"TypeError\",\r\n \"RangeError\",\r\n \"SyntaxError\",\r\n \"ReferenceError\",\r\n // Other utilities\r\n \"atob\",\r\n \"btoa\",\r\n \"structuredClone\",\r\n]);\r\n\r\n/**\r\n * Blocked globals that are shadowed with undefined.\r\n *\r\n * Previously this list blocked many browser APIs (fetch, setTimeout, etc.)\r\n * but this was too restrictive. Developers should have full access to JS.\r\n *\r\n * Only truly dangerous APIs that could break the framework should be blocked.\r\n * Currently empty - we trust developers to write safe code.\r\n */\r\nexport const BLOCKED_GLOBALS = Object.freeze([\r\n // Currently no blocked globals - developers have full JS access\r\n // If you need to block something dangerous in the future, add it here\r\n]);\r\n\r\n// Reserved words and keywords that cannot be used as parameter names\r\n// These are blocked via strict mode instead\r\nexport const RESERVED_WORDS = new Set([\r\n \"with\",\r\n \"eval\",\r\n \"arguments\",\r\n \"constructor\",\r\n \"prototype\",\r\n \"break\",\r\n \"case\",\r\n \"catch\",\r\n \"continue\",\r\n \"debugger\",\r\n \"default\",\r\n \"delete\",\r\n \"do\",\r\n \"else\",\r\n \"finally\",\r\n \"for\",\r\n \"function\",\r\n \"if\",\r\n \"in\",\r\n \"instanceof\",\r\n \"new\",\r\n \"return\",\r\n \"switch\",\r\n \"this\",\r\n \"throw\",\r\n \"try\",\r\n \"typeof\",\r\n \"var\",\r\n \"void\",\r\n \"while\",\r\n \"class\",\r\n \"const\",\r\n \"enum\",\r\n \"export\",\r\n \"extends\",\r\n \"import\",\r\n \"super\",\r\n \"implements\",\r\n \"interface\",\r\n \"let\",\r\n \"package\",\r\n \"private\",\r\n \"protected\",\r\n \"public\",\r\n \"static\",\r\n \"yield\",\r\n \"null\",\r\n \"true\",\r\n \"false\",\r\n]);\r\n\r\n// ============================================================================\r\n// Framework Helpers ($ prefixed)\r\n// ============================================================================\r\n\r\n/**\r\n * Framework helper names that are injected into component scripts.\r\n * These use the $ prefix convention\r\n */\r\nexport const FRAMEWORK_HELPERS = Object.freeze([\r\n \"registerComponent\",\r\n \"$use\", // Alias for registerComponent with auto-derived tag name\r\n]);\r\n","/**\r\n * LadrillosJS Key Modifiers\r\n *\r\n * Supports keyboard keys, mouse modifiers, and event behavior modifiers.\r\n *\r\n * Syntax: $on:event.modifier1.modifier2=\"handler()\"\r\n *\r\n * Examples:\r\n * $on:keyup.enter=\"submit()\"\r\n * $on:keydown.escape=\"closeModal()\"\r\n * $on:click.ctrl=\"selectMultiple()\"\r\n * $on:keydown.ctrl.s=\"save()\"\r\n * $on:submit.prevent=\"handleSubmit()\"\r\n * $on:click.stop=\"handleClick()\"\r\n */\r\n\r\n// ============================================================================\r\n// Key Aliases\r\n// ============================================================================\r\n\r\n/**\r\n * Common key aliases for better DX.\r\n * Maps short names to KeyboardEvent.key values.\r\n */\r\nexport const KEY_ALIASES: Record<string, string> = {\r\n // Navigation\r\n enter: \"Enter\",\r\n tab: \"Tab\",\r\n esc: \"Escape\",\r\n escape: \"Escape\",\r\n space: \" \",\r\n\r\n // Arrow keys\r\n up: \"ArrowUp\",\r\n down: \"ArrowDown\",\r\n left: \"ArrowLeft\",\r\n right: \"ArrowRight\",\r\n\r\n // Editing\r\n delete: \"Delete\",\r\n backspace: \"Backspace\",\r\n insert: \"Insert\",\r\n\r\n // Function keys\r\n f1: \"F1\",\r\n f2: \"F2\",\r\n f3: \"F3\",\r\n f4: \"F4\",\r\n f5: \"F5\",\r\n f6: \"F6\",\r\n f7: \"F7\",\r\n f8: \"F8\",\r\n f9: \"F9\",\r\n f10: \"F10\",\r\n f11: \"F11\",\r\n f12: \"F12\",\r\n\r\n // Other common keys\r\n home: \"Home\",\r\n end: \"End\",\r\n pageup: \"PageUp\",\r\n pagedown: \"PageDown\",\r\n};\r\n\r\n// ============================================================================\r\n// System Modifier Keys\r\n// ============================================================================\r\n\r\n/**\r\n * System modifier keys that check event properties.\r\n */\r\nexport const SYSTEM_MODIFIERS = [\"ctrl\", \"alt\", \"shift\", \"meta\"] as const;\r\n\r\nexport type SystemModifier = (typeof SYSTEM_MODIFIERS)[number];\r\n\r\n/**\r\n * Maps modifier names to event property names.\r\n */\r\nexport const MODIFIER_PROPERTIES: Record<\r\n SystemModifier,\r\n keyof KeyboardEvent | keyof MouseEvent\r\n> = {\r\n ctrl: \"ctrlKey\",\r\n alt: \"altKey\",\r\n shift: \"shiftKey\",\r\n meta: \"metaKey\",\r\n};\r\n\r\n// ============================================================================\r\n// Event Modifiers\r\n// ============================================================================\r\n\r\n/**\r\n * Event behavior modifiers.\r\n */\r\nexport const EVENT_MODIFIERS = [\r\n \"prevent\", // event.preventDefault()\r\n \"stop\", // event.stopPropagation()\r\n \"self\", // Only trigger if event.target === event.currentTarget\r\n \"once\", // Remove listener after first invocation\r\n \"passive\", // Passive event listener\r\n \"capture\", // Use capture phase\r\n] as const;\r\n\r\nexport type EventModifier = (typeof EVENT_MODIFIERS)[number];\r\n\r\n// ============================================================================\r\n// Mouse Button Modifiers\r\n// ============================================================================\r\n\r\n/**\r\n * Mouse button modifiers for click events.\r\n */\r\nexport const MOUSE_MODIFIERS = {\r\n left: 0,\r\n middle: 1,\r\n right: 2,\r\n} as const;\r\n\r\nexport type MouseModifier = keyof typeof MOUSE_MODIFIERS;\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface ParsedEventDirective {\r\n /** The base event name (e.g., \"keyup\", \"click\") */\r\n eventName: string;\r\n /** Key modifiers (e.g., [\"enter\", \"shift\"]) */\r\n keyModifiers: string[];\r\n /** System modifiers (e.g., [\"ctrl\", \"alt\"]) */\r\n systemModifiers: SystemModifier[];\r\n /** Event behavior modifiers (e.g., [\"prevent\", \"stop\"]) */\r\n eventModifiers: EventModifier[];\r\n /** Mouse button modifier (e.g., \"left\") */\r\n mouseModifier: MouseModifier | null;\r\n /** Whether to use exact modifier matching */\r\n exact: boolean;\r\n}\r\n\r\n// ============================================================================\r\n// Parsing Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Parses a $on: directive attribute into its components.\r\n *\r\n * Examples:\r\n * \"$on:keyup.enter\" → { eventName: \"keyup\", keyModifiers: [\"enter\"], ... }\r\n * \"$on:click.ctrl.prevent\" → { eventName: \"click\", systemModifiers: [\"ctrl\"], eventModifiers: [\"prevent\"], ... }\r\n */\r\nexport function parseEventDirective(\r\n attrName: string\r\n): ParsedEventDirective | null {\r\n // Must start with $on:\r\n if (!attrName.startsWith(\"$on:\")) {\r\n return null;\r\n }\r\n\r\n // Remove the $on: prefix and split by dots\r\n const rest = attrName.slice(4); // Remove \"$on:\"\r\n const parts = rest.split(\".\");\r\n\r\n if (parts.length === 0 || !parts[0]) {\r\n return null;\r\n }\r\n\r\n const eventName = parts[0];\r\n const modifiers = parts.slice(1);\r\n\r\n const result: ParsedEventDirective = {\r\n eventName,\r\n keyModifiers: [],\r\n systemModifiers: [],\r\n eventModifiers: [],\r\n mouseModifier: null,\r\n exact: false,\r\n };\r\n\r\n for (const mod of modifiers) {\r\n const lowerMod = mod.toLowerCase();\r\n\r\n // Check for exact modifier\r\n if (lowerMod === \"exact\") {\r\n result.exact = true;\r\n continue;\r\n }\r\n\r\n // Check for event modifiers (prevent, stop, etc.)\r\n if (EVENT_MODIFIERS.includes(lowerMod as EventModifier)) {\r\n result.eventModifiers.push(lowerMod as EventModifier);\r\n continue;\r\n }\r\n\r\n // Check for system modifiers (ctrl, alt, shift, meta)\r\n if (SYSTEM_MODIFIERS.includes(lowerMod as SystemModifier)) {\r\n result.systemModifiers.push(lowerMod as SystemModifier);\r\n continue;\r\n }\r\n\r\n // Check for mouse modifiers (left, middle, right)\r\n if (lowerMod in MOUSE_MODIFIERS) {\r\n result.mouseModifier = lowerMod as MouseModifier;\r\n continue;\r\n }\r\n\r\n // Otherwise, it's a key modifier\r\n result.keyModifiers.push(lowerMod);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Checks if a KeyboardEvent matches the specified key modifier.\r\n *\r\n * @param event The keyboard event\r\n * @param keyModifier The key modifier to check (e.g., \"enter\", \"a\", \"escape\")\r\n * @returns True if the key matches\r\n */\r\nexport function matchesKey(event: KeyboardEvent, keyModifier: string): boolean {\r\n const lowerMod = keyModifier.toLowerCase();\r\n\r\n // Check aliases first\r\n const aliasedKey = KEY_ALIASES[lowerMod];\r\n if (aliasedKey) {\r\n return event.key === aliasedKey;\r\n }\r\n\r\n // For single characters (a-z, 0-9), compare case-insensitively\r\n if (lowerMod.length === 1) {\r\n return event.key.toLowerCase() === lowerMod;\r\n }\r\n\r\n // For other keys, try to match by converting kebab-case to the key name\r\n // e.g., \"page-down\" → \"PageDown\"\r\n const camelCaseKey = lowerMod\r\n .split(\"-\")\r\n .map((part, i) =>\r\n i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)\r\n )\r\n .join(\"\");\r\n\r\n // Try both the original key and the camelCase version\r\n return (\r\n event.key.toLowerCase() === lowerMod ||\r\n event.key.toLowerCase() === camelCaseKey.toLowerCase()\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a keyboard/mouse event matches all system modifiers.\r\n *\r\n * @param event The event to check\r\n * @param modifiers The system modifiers required\r\n * @param exact If true, no other modifiers should be pressed\r\n * @returns True if all required modifiers are pressed (and only those if exact)\r\n */\r\nexport function matchesSystemModifiers(\r\n event: KeyboardEvent | MouseEvent,\r\n modifiers: SystemModifier[],\r\n exact: boolean\r\n): boolean {\r\n const modifierState = {\r\n ctrl: event.ctrlKey,\r\n alt: event.altKey,\r\n shift: event.shiftKey,\r\n meta: event.metaKey,\r\n };\r\n\r\n // Check that all required modifiers are pressed\r\n for (const mod of modifiers) {\r\n if (!modifierState[mod]) {\r\n return false;\r\n }\r\n }\r\n\r\n // If exact mode, ensure no extra modifiers are pressed\r\n if (exact) {\r\n for (const mod of SYSTEM_MODIFIERS) {\r\n if (!modifiers.includes(mod) && modifierState[mod]) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Checks if a MouseEvent matches the specified mouse button.\r\n *\r\n * @param event The mouse event\r\n * @param mouseModifier The mouse button modifier\r\n * @returns True if the button matches\r\n */\r\nexport function matchesMouseButton(\r\n event: MouseEvent,\r\n mouseModifier: MouseModifier\r\n): boolean {\r\n return event.button === MOUSE_MODIFIERS[mouseModifier];\r\n}\r\n\r\n/**\r\n * Creates an event listener options object from event modifiers.\r\n */\r\nexport function getListenerOptions(\r\n modifiers: EventModifier[]\r\n): AddEventListenerOptions {\r\n const options: AddEventListenerOptions = {};\r\n\r\n if (modifiers.includes(\"passive\")) {\r\n options.passive = true;\r\n }\r\n if (modifiers.includes(\"capture\")) {\r\n options.capture = true;\r\n }\r\n if (modifiers.includes(\"once\")) {\r\n options.once = true;\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Creates a wrapped event handler that applies all modifiers.\r\n *\r\n * @param originalHandler The original event handler function\r\n * @param parsed The parsed event directive\r\n * @returns A wrapped handler that checks modifiers before calling the original\r\n */\r\nexport function createModifiedHandler(\r\n originalHandler: (event: Event) => void,\r\n parsed: ParsedEventDirective\r\n): (event: Event) => void {\r\n return function modifiedHandler(event: Event) {\r\n // Check \"self\" modifier - event must originate from the element itself\r\n if (parsed.eventModifiers.includes(\"self\")) {\r\n if (event.target !== event.currentTarget) {\r\n return;\r\n }\r\n }\r\n\r\n // Check mouse button modifier\r\n if (parsed.mouseModifier && event instanceof MouseEvent) {\r\n if (!matchesMouseButton(event, parsed.mouseModifier)) {\r\n return;\r\n }\r\n }\r\n\r\n // Check system modifiers (ctrl, alt, shift, meta)\r\n if (parsed.systemModifiers.length > 0 || parsed.exact) {\r\n if (event instanceof KeyboardEvent || event instanceof MouseEvent) {\r\n if (\r\n !matchesSystemModifiers(event, parsed.systemModifiers, parsed.exact)\r\n ) {\r\n return;\r\n }\r\n }\r\n }\r\n\r\n // Check key modifiers for keyboard events\r\n if (parsed.keyModifiers.length > 0 && event instanceof KeyboardEvent) {\r\n const matchesAnyKey = parsed.keyModifiers.some((key) =>\r\n matchesKey(event, key)\r\n );\r\n if (!matchesAnyKey) {\r\n return;\r\n }\r\n }\r\n\r\n // Apply \"prevent\" modifier\r\n if (parsed.eventModifiers.includes(\"prevent\")) {\r\n event.preventDefault();\r\n }\r\n\r\n // Apply \"stop\" modifier\r\n if (parsed.eventModifiers.includes(\"stop\")) {\r\n event.stopPropagation();\r\n }\r\n\r\n // Call the original handler\r\n originalHandler(event);\r\n };\r\n}\r\n\r\n/**\r\n * Checks if an attribute is a $on: event directive.\r\n */\r\nexport function isEventDirective(attrName: string): boolean {\r\n return attrName.startsWith(\"$on:\");\r\n}\r\n","import { BindingDescriptor, ScriptElement } from \"../../types\";\r\nimport { EVENT_ATTRIBUTES } from \"../../utils/jsevents\";\r\nimport { syncBindBeforeHandler } from \"../../utils/directives\";\r\nimport\r\n{\r\n ALLOWED_GLOBALS,\r\n BLOCKED_GLOBALS,\r\n RESERVED_WORDS,\r\n} from \"../../utils/sandbox\";\r\nimport\r\n{\r\n isEventDirective,\r\n parseEventDirective,\r\n createModifiedHandler,\r\n getListenerOptions,\r\n} from \"../../utils/keyModifiers\";\r\nimport\r\n{\r\n expressionError,\r\n scriptError,\r\n warn,\r\n getComponentContext,\r\n ErrorCode,\r\n} from \"../../utils/devWarnings\";\r\nimport { createReactiveState } from \"./reactivity\";\r\nimport { transformCodeToStateAccess } from \"../../utils/stateTransform\";\r\nimport\r\n{\r\n frameworkHelperNames,\r\n createFrameworkHelpers,\r\n} from \"../helpers/frameworkHelpers\";\r\nimport { eventBusHelperNames, createEventBusHelpers } from \"../events/eventBus\";\r\nimport { getPendingLazyContent } from \"../builtins/lazyElement\";\r\n\r\n/**\r\n * Gets the actual HTMLElement from either a direct element or a ShadowRoot.\r\n */\r\nconst getHostElement = (host: HTMLElement | ShadowRoot): HTMLElement =>\r\n host instanceof ShadowRoot ? (host.host as HTMLElement) : host;\r\n\r\n/**\r\n * Main entry point for processing component scripts.\r\n *\r\n * 1. Extracts all variables and functions from <script> tags\r\n * 2. Applies attribute overrides (attributes take precedence over defaults)\r\n * 3. Creates attribute-only state entries (for attributes without script vars)\r\n * 4. Creates a reactive state that auto-updates DOM on changes\r\n * 5. Binds inline event handlers (onclick, etc.) to work with reactive state\r\n * 6. Evaluates and applies template bindings like {name} or {greet()}\r\n *\r\n * @param host - The component's root element or shadow root\r\n * @param scripts - Script elements from the component\r\n * @param bindings - Template bindings to connect to state\r\n * @param attributeOverrides - Attributes from HTML that override script defaults\r\n * @param onStateChange - Optional callback when state changes (for directive updates)\r\n * @param deferBindings - If true, don't apply bindings immediately (for module script support)\r\n * @param componentUrl - The absolute URL of the component (for resolving relative paths in registerComponent)\r\n * @param componentId - Optional unique ID for this component instance (for event bus cleanup)\r\n * @param refs - Optional refs Map (for $refs access in scripts)\r\n * @param templateBindings - Variable names from template bindings (for auto-prop access in scripts)\r\n * @returns The reactive state object - changes trigger automatic DOM updates\r\n */\r\nexport async function loadScripts(\r\n host: HTMLElement | ShadowRoot,\r\n scripts: ScriptElement[],\r\n bindings: BindingDescriptor[],\r\n attributeOverrides: Record<string, unknown> = {},\r\n onStateChange?: () => void,\r\n deferBindings: boolean = false,\r\n componentUrl?: string,\r\n componentId?: string,\r\n refs?: Map<string, HTMLElement>,\r\n templateBindings: string[] = [],\r\n): Promise<Record<string, unknown>>\r\n{\r\n const componentHost = getHostElement(host);\r\n const initialState: Record<string, unknown> = {};\r\n\r\n // Collect all script content for re-execution in event handlers\r\n const allScriptContent = scripts.map((s) => s.content).join(\"\\n\");\r\n\r\n // Apply attribute overrides FIRST - these are the prop values from usage\r\n // This allows: <my-component title=\"Data\"> to make title=\"Data\" available\r\n // before any script code runs\r\n for (const [key, value] of Object.entries(attributeOverrides))\r\n {\r\n initialState[key] = value;\r\n }\r\n\r\n // Add internal properties for loop event handlers BEFORE creating reactive state\r\n // These are prefixed with __ so they're skipped during destructuring\r\n (initialState as any).__scriptContent = allScriptContent;\r\n (initialState as any).__componentUrl = componentUrl;\r\n (initialState as any).__componentId = componentId;\r\n\r\n // Create reactive state - changes automatically update the DOM!\r\n // Start with attribute overrides so script code can reference them\r\n const reactiveState = createReactiveState(\r\n initialState,\r\n bindings,\r\n (binding, state) => updateSingleBinding(binding, state),\r\n onStateChange,\r\n );\r\n\r\n // Execute scripts with __state__ transformation\r\n // Scripts run with attribute values already in state\r\n // `let title = \"Default\"` becomes `__state__.title ??= \"Default\"`\r\n // Since title is already \"Data\" from attributes, ??= won't overwrite it\r\n // Derived values like `const test = ${title}...` will use the attribute value\r\n //\r\n // Suspend per-key reactive binding updates while the scripts run. Scripts\r\n // assign __state__.x one declaration at a time, but a single binding can\r\n // reference several variables (e.g. class=\"btn--{variant} btn--{size}\").\r\n // Updating that binding the moment the first variable is assigned would try\r\n // to evaluate a variable declared later in the same script, throwing a\r\n // spurious ReferenceError. We apply every binding together once execution\r\n // finishes (see applyBindings below / applyBindingsDeferred for modules).\r\n (reactiveState as any).__suspendReactivity = true;\r\n try\r\n {\r\n for (const script of scripts)\r\n {\r\n executeScriptWithReactiveState(\r\n script.content,\r\n reactiveState,\r\n componentUrl,\r\n componentId,\r\n componentHost, // Pass host element for $host access\r\n refs, // Pass refs for $refs access\r\n templateBindings, // Pass template bindings so auto-props are accessible\r\n );\r\n }\r\n } finally\r\n {\r\n (reactiveState as any).__suspendReactivity = false;\r\n }\r\n\r\n // Store reactive state on host element (for debugging and event handlers)\r\n (componentHost as any).__state = reactiveState;\r\n // Store script content for event handlers that need to be set up later\r\n (componentHost as any).__scriptContent = allScriptContent;\r\n // Store component URL for correct path resolution in framework helpers\r\n (componentHost as any).__componentUrl = componentUrl;\r\n // Store component ID for event bus cleanup\r\n (componentHost as any).__componentId = componentId;\r\n\r\n // Make onclick=\"handleClick()\" work by binding to reactive state\r\n // Pass script content so functions can be re-created with current state\r\n // NOTE: We defer this until after module scripts are loaded\r\n if (!deferBindings)\r\n {\r\n transformInlineEventHandlers(\r\n host,\r\n reactiveState,\r\n allScriptContent,\r\n componentHost,\r\n );\r\n\r\n // Apply initial bindings with current state values\r\n applyBindings(bindings, reactiveState);\r\n }\r\n\r\n return reactiveState;\r\n}\r\n\r\n/**\r\n * Apply bindings after all state is ready (including module scripts).\r\n * This should be called after module scripts have been executed.\r\n */\r\nexport function applyBindingsDeferred(\r\n host: HTMLElement | ShadowRoot,\r\n bindings: BindingDescriptor[],\r\n state: Record<string, unknown>,\r\n): void\r\n{\r\n const componentHost = getHostElement(host);\r\n const allScriptContent = (componentHost as any).__scriptContent || \"\";\r\n\r\n // Set up event handlers now that all state is available\r\n transformInlineEventHandlers(host, state, allScriptContent, componentHost);\r\n\r\n // Apply bindings with complete state\r\n applyBindings(bindings, state);\r\n}\r\n\r\n// ============================================================================\r\n// Event Handler Processing\r\n// ============================================================================\r\n\r\n/**\r\n * Finds all inline event handlers (onclick, oninput, etc.) and replaces them\r\n * with proper event listeners that have access to the component's scope.\r\n *\r\n * This is what makes vanilla HTML syntax work:\r\n * <button onclick=\"handleClick()\"> → just works!\r\n *\r\n * Also handles $on: directives with key/event modifiers:\r\n * <input $on:keyup.enter=\"submit()\"> → calls submit() only on Enter key\r\n * <button $on:click.prevent=\"handleClick()\"> → prevents default and calls handler\r\n *\r\n * NOTE: Skips elements inside $for loops - those are handled by the loop renderer.\r\n */\r\nfunction transformInlineEventHandlers(\r\n host: HTMLElement | ShadowRoot,\r\n state: Record<string, unknown>,\r\n scriptContent: string,\r\n componentHost: HTMLElement,\r\n): void\r\n{\r\n // Wire up handlers in `host` AND inside any pending <lazy> content\r\n // fragments. Lazy children are detached so a host-only walk would miss\r\n // them; addEventListener on detached nodes works fine and survives the\r\n // later DOM move when the lazy strategy fires.\r\n const roots: Array<HTMLElement | ShadowRoot | DocumentFragment> = [\r\n host,\r\n ...getPendingLazyContent(host),\r\n ];\r\n for (const root of roots)\r\n {\r\n const elements = Array.from(root.querySelectorAll(\"*\"));\r\n\r\n for (const element of elements)\r\n {\r\n // Skip elements that are inside a $for template or have $for themselves\r\n // These will be processed by the loop renderer with proper loop context\r\n if (isInsideForLoop(element))\r\n {\r\n continue;\r\n }\r\n\r\n // Process standard inline event handlers (onclick, oninput, etc.)\r\n for (const attrName of EVENT_ATTRIBUTES)\r\n {\r\n const handlerCode = element.getAttribute(attrName);\r\n\r\n if (handlerCode)\r\n {\r\n // Remove attribute so the browser doesn't try to eval it globally\r\n element.removeAttribute(attrName);\r\n\r\n // onclick → click\r\n const eventName = attrName.slice(2);\r\n\r\n // Create a real event listener with component context\r\n const handler = createVanillaEventHandler(\r\n handlerCode,\r\n state,\r\n scriptContent,\r\n componentHost,\r\n );\r\n if (handler)\r\n {\r\n element.addEventListener(eventName, handler);\r\n }\r\n }\r\n }\r\n\r\n // Process $on: event directives with modifiers\r\n processEventDirectives(element, state, scriptContent, componentHost);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Processes $on: event directives on an element.\r\n *\r\n * Syntax: $on:event.modifier1.modifier2=\"handler()\"\r\n *\r\n * Examples:\r\n * $on:keyup.enter=\"submit()\"\r\n * $on:click.ctrl.prevent=\"handleClick()\"\r\n * $on:keydown.escape=\"closeModal()\"\r\n * $on:keydown.w=\"moveUp()\"\r\n */\r\nfunction processEventDirectives(\r\n element: Element,\r\n state: Record<string, unknown>,\r\n scriptContent: string,\r\n componentHost: HTMLElement,\r\n): void\r\n{\r\n // Get all attributes that start with $on:\r\n const attrs = Array.from(element.attributes);\r\n const eventAttrs = attrs.filter((attr) => isEventDirective(attr.name));\r\n\r\n for (const attr of eventAttrs)\r\n {\r\n const parsed = parseEventDirective(attr.name);\r\n if (!parsed) continue;\r\n\r\n const handlerCode = attr.value;\r\n element.removeAttribute(attr.name);\r\n\r\n // Create the base event handler with component context\r\n const baseHandler = createVanillaEventHandler(\r\n handlerCode,\r\n state,\r\n scriptContent,\r\n componentHost,\r\n );\r\n\r\n if (!baseHandler) continue;\r\n\r\n // Wrap the handler with modifier checks\r\n const modifiedHandler = createModifiedHandler(baseHandler, parsed);\r\n\r\n // Get listener options (passive, capture, once)\r\n const options = getListenerOptions(parsed.eventModifiers);\r\n\r\n // Add the event listener\r\n element.addEventListener(parsed.eventName, modifiedHandler, options);\r\n }\r\n}\r\n\r\n/**\r\n * Checks if an element is inside a loop template.\r\n * Elements inside loops need special handling for their event handlers\r\n * (the loop renderer attaches them with the per-iteration scope).\r\n *\r\n * Recognizes both:\r\n * - the legacy `$for` attribute directive\r\n * - the `<for>` built-in element\r\n */\r\nfunction isInsideForLoop(element: Element): boolean\r\n{\r\n // Check the element itself\r\n if (element.hasAttribute(\"$for\") || element.tagName === \"FOR\")\r\n {\r\n return true;\r\n }\r\n\r\n // Check ancestors\r\n let current: Element | null = element.parentElement;\r\n while (current)\r\n {\r\n if (current.hasAttribute(\"$for\") || current.tagName === \"FOR\")\r\n {\r\n return true;\r\n }\r\n current = current.parentElement;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Creates an event handler function that executes the original handler code\r\n * with access to component variables, functions, and safe globals like alert().\r\n *\r\n * The handler has access to the REACTIVE state, so assignments like:\r\n * onclick=\"count++\"\r\n * will automatically update the DOM.\r\n *\r\n * Functions are RE-CREATED each time with current state values, so:\r\n * onclick=\"handleClick()\" will see the latest `name` value, not the original.\r\n */\r\nfunction createVanillaEventHandler(\r\n code: string,\r\n state: Record<string, unknown>,\r\n scriptContent: string,\r\n componentHost?: HTMLElement,\r\n): ((event: Event) => void) | null\r\n{\r\n try\r\n {\r\n // Get component URL from host for framework helpers path resolution\r\n const componentUrl = (componentHost as any)?.__componentUrl;\r\n const componentId = (componentHost as any)?.__componentId;\r\n\r\n // Include safe globals like alert, console, Math, JSON, etc.\r\n const allowed = getAllowedGlobalsWithValues(componentUrl, componentId);\r\n\r\n // Block dangerous globals like window, document, fetch, etc.\r\n const safeBlocked = getSafeBlockedGlobals();\r\n\r\n // Build the function parameters: event + blocked + allowed + \"state\" reference + \"$refs\" + \"$host\"\r\n // The reactive-state param is named `__state__` (not `state`) so a user\r\n // variable named `state` doesn't collide with it (which would produce\r\n // `let { state } = state;` — a \"already declared\" SyntaxError).\r\n // `$host` must be a parameter here (not just a script-scope closure)\r\n // because script functions are RE-CREATED from source in this handler\r\n // scope, losing their original closure over the script's $host.\r\n const allKeys = [\r\n \"event\",\r\n \"__state__\",\r\n \"$refs\",\r\n \"$host\",\r\n ...safeBlocked,\r\n ...allowed.keys,\r\n ];\r\n\r\n // Get ALL state keys (includes both script variables AND attribute values)\r\n const allStateKeys = Object.keys(state);\r\n\r\n // Separate functions from variables in state\r\n const funcNames = allStateKeys.filter(\r\n (key) => typeof state[key] === \"function\",\r\n );\r\n const varNames = allStateKeys.filter(\r\n (key) => typeof state[key] !== \"function\",\r\n );\r\n\r\n // Check if we have module script functions by looking for __moduleScript marker\r\n // Module scripts set this marker when they're reactive functions that manage state directly\r\n // Regular script functions need to be re-created each time to get fresh variable bindings\r\n const hasModuleScriptFunctions = (state as any).__hasModuleScripts === true;\r\n\r\n // Always use `let` for variables so inline handlers like onclick=\"count++\"\r\n // can mutate them. Any mutations are synced back to reactive state below\r\n // when the inline code references the variable.\r\n const destructureVars =\r\n varNames.length > 0 ? `let { ${varNames.join(\", \")} } = __state__;` : \"\";\r\n\r\n // For module scripts: destructure functions from state (they're reactive)\r\n // For regular scripts: DON'T destructure - we'll recreate them via funcDefs\r\n const destructureFuncs = hasModuleScriptFunctions\r\n ? funcNames.length > 0\r\n ? `const { ${funcNames.join(\", \")} } = __state__;`\r\n : \"\"\r\n : \"\";\r\n\r\n // Extract function definitions from script content to re-create them\r\n // with current variable values (not original closure values).\r\n // For module scripts: skip all functions (they're reactive and manage state directly)\r\n // For regular scripts: recreate ALL functions to get fresh variable bindings\r\n const functionsToSkip = hasModuleScriptFunctions ? funcNames : [];\r\n const rawFuncDefs = extractFunctionDefinitions(\r\n scriptContent,\r\n functionsToSkip,\r\n );\r\n\r\n // Transform function definitions to use __state__.varName for variable\r\n // access. This ensures async callbacks (like .then()) write directly to\r\n // reactive state instead of local destructured copies that won't be\r\n // synced back. No declaration rewrite: funcDefs are function definitions,\r\n // not top-level state declarations.\r\n const funcDefs = transformCodeToStateAccess(rawFuncDefs, varNames, {\r\n rewriteDeclarations: false,\r\n });\r\n\r\n // Sync back any variables the inline handler code references.\r\n // Inline code operates on local `let` copies (from the destructure above),\r\n // so we assign them back to reactive state after the handler runs.\r\n // Functions in regular scripts are re-created via funcDefs with fresh\r\n // bindings, and module-script functions write directly to state via\r\n // __state__ — neither needs this sync-back. Only raw inline code does.\r\n const codeReferencesVars = varNames.some((v) =>\r\n new RegExp(`\\\\b${v}\\\\b`).test(code),\r\n );\r\n const syncBack = !codeReferencesVars\r\n ? \"\"\r\n : varNames\r\n .filter((key) => new RegExp(`\\\\b${key}\\\\b`).test(code))\r\n .map((key) => `__state__.${key} = ${key};`)\r\n .join(\" \");\r\n\r\n // Check if the code or any function definitions use async/await\r\n const isAsync =\r\n /\\bawait\\b/.test(code) ||\r\n /\\bawait\\b/.test(funcDefs) ||\r\n /\\basync\\b/.test(funcDefs);\r\n\r\n // Add sourceURL so DevTools shows the component name instead of VM123:5\r\n const sourceUrl = componentUrl || \"ladrillos-event-handler\";\r\n\r\n // For async handlers, wrap in try/finally to ensure sync-back happens after await\r\n // For sync handlers, sync-back runs at the end as before\r\n const fnBody = isAsync\r\n ? `\"use strict\"; ${destructureVars} ${destructureFuncs} ${funcDefs} try { await (async () => { ${code} })(); } finally { ${syncBack} }\r\n//# sourceURL=${sourceUrl}`\r\n : `\"use strict\"; ${destructureVars} ${destructureFuncs} ${funcDefs} ${code}; ${syncBack}\r\n//# sourceURL=${sourceUrl}`;\r\n\r\n // Use AsyncFunction constructor for async handlers\r\n const AsyncFunction = Object.getPrototypeOf(\r\n async function () { },\r\n ).constructor;\r\n const fn = isAsync\r\n ? new AsyncFunction(...allKeys, fnBody)\r\n : new Function(...allKeys, fnBody);\r\n\r\n return (event: Event) =>\r\n {\r\n try\r\n {\r\n // If the element also has $bind for this event, sync its value into\r\n // state first so the handler reads the current value, not the previous\r\n syncBindBeforeHandler(event);\r\n\r\n // Get $refs from component host dynamically (they're set after script load)\r\n // Already wrapped in Proxy by webcomponent.ts for dot notation access\r\n const $refs = componentHost\r\n ? (componentHost as any).__refs || new Map()\r\n : new Map();\r\n\r\n const allValues = [\r\n event,\r\n state, // Pass reactive state\r\n $refs, // Pass $refs Map\r\n componentHost, // Pass $host (the component element)\r\n ...safeBlocked.map(() => undefined), // Shadow dangerous globals\r\n ...allowed.values, // Inject safe globals\r\n ];\r\n\r\n // Handle both sync and async handlers\r\n const result = fn(...allValues);\r\n\r\n // If the handler returns a promise, catch any async errors\r\n if (result && typeof result.catch === \"function\")\r\n {\r\n result.catch((e: Error) =>\r\n {\r\n const ctx = {\r\n tagName: componentHost?.tagName?.toLowerCase(),\r\n sourcePath: (state as any).__componentUrl,\r\n instanceId: (state as any).__componentId,\r\n };\r\n expressionError(code, e, {\r\n context: ctx.tagName ? ctx : getComponentContext(),\r\n errorCode: ErrorCode.EVENT_HANDLER_FAILED,\r\n });\r\n });\r\n }\r\n } catch (e)\r\n {\r\n // Build context from state metadata (more reliable than global context\r\n // since multiple components can initialize in parallel)\r\n const ctx = {\r\n tagName: componentHost?.tagName?.toLowerCase(),\r\n sourcePath: (state as any).__componentUrl,\r\n instanceId: (state as any).__componentId,\r\n };\r\n expressionError(code, e as Error, {\r\n context: ctx.tagName ? ctx : getComponentContext(),\r\n errorCode: ErrorCode.EVENT_HANDLER_FAILED,\r\n });\r\n }\r\n };\r\n } catch (e)\r\n {\r\n // Build context from component host for accurate error attribution\r\n // Use component host's tagName directly (more reliable than global context\r\n // which can be overwritten by parallel component initialization)\r\n const ctx = componentHost?.tagName\r\n ? {\r\n tagName: componentHost.tagName.toLowerCase(),\r\n sourcePath: (state as any).__componentUrl,\r\n instanceId: (state as any).__componentId,\r\n }\r\n : null;\r\n // Pass ctx explicitly to override global context\r\n warn(\r\n `Failed to create event handler: ${code} — ${(e as Error).message}`,\r\n ctx,\r\n );\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Cache of extracted function-definition strings.\r\n *\r\n * `extractFunctionDefinitions` scans the ENTIRE component script with several\r\n * regex passes and brace-matching. In the loop path it is called once per\r\n * rendered row (via `createLoopEventHandler`), so a `<for>` over N items with\r\n * inline handlers re-parsed the full script N times on the initial render. The\r\n * result depends only on (content, skipFunctions), so we memoize it. The cache\r\n * is bounded with FIFO eviction so long-lived apps with many distinct\r\n * components don't grow it without limit.\r\n */\r\nconst funcDefsCache = new Map<string, string>();\r\nconst MAX_FUNC_DEFS_CACHE = 500;\r\n\r\n/**\r\n * Extracts function definitions from script content.\r\n * These will be re-created in the event handler context with current state values.\r\n *\r\n * Memoized: the output is a pure function of (content, skipFunctions).\r\n *\r\n * @param content - The script content to extract functions from\r\n * @param skipFunctions - Function names to skip (already in state as reactive functions)\r\n */\r\nexport function extractFunctionDefinitions(\r\n content: string,\r\n skipFunctions: string[] = [],\r\n): string\r\n{\r\n const cacheKey = skipFunctions.join(\",\") + \"\\u0000\" + content;\r\n const cached = funcDefsCache.get(cacheKey);\r\n if (cached !== undefined) return cached;\r\n\r\n const result = computeFunctionDefinitions(content, skipFunctions);\r\n\r\n if (funcDefsCache.size >= MAX_FUNC_DEFS_CACHE)\r\n {\r\n const oldest = funcDefsCache.keys().next().value;\r\n if (oldest !== undefined) funcDefsCache.delete(oldest);\r\n }\r\n funcDefsCache.set(cacheKey, result);\r\n return result;\r\n}\r\n\r\nfunction computeFunctionDefinitions(\r\n content: string,\r\n skipFunctions: string[] = [],\r\n): string\r\n{\r\n const functions: string[] = [];\r\n\r\n // Match regular and async function declarations: function foo() {...}\r\n const funcRegex =\r\n /(?:async\\s+)?function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\([^)]*\\)\\s*\\{/g;\r\n let match;\r\n\r\n while ((match = funcRegex.exec(content)) !== null)\r\n {\r\n const funcName = match[1];\r\n\r\n // Skip functions that already exist in state (reactive module script functions)\r\n if (skipFunctions.includes(funcName))\r\n {\r\n continue;\r\n }\r\n\r\n // Find the matching closing brace\r\n const funcDef = extractBracedBlock(content, match.index);\r\n if (funcDef)\r\n {\r\n functions.push(funcDef);\r\n }\r\n }\r\n\r\n // Match arrow functions: const/let foo = (...) => {...} or const/let foo = async (...) => {...}\r\n const arrowRegex =\r\n /(?:const|let)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=\\s*(?:async\\s*)?\\([^)]*\\)\\s*=>\\s*\\{/g;\r\n\r\n while ((match = arrowRegex.exec(content)) !== null)\r\n {\r\n const funcName = match[1];\r\n\r\n // Skip functions that already exist in state (reactive module script functions)\r\n if (skipFunctions.includes(funcName))\r\n {\r\n continue;\r\n }\r\n\r\n // Find the matching closing brace for the arrow function body\r\n const startIndex = match.index;\r\n const bodyStart = content.indexOf(\"{\", startIndex + match[0].length - 1);\r\n const funcDef = extractBracedBlock(content, startIndex, bodyStart);\r\n if (funcDef)\r\n {\r\n functions.push(funcDef);\r\n }\r\n }\r\n\r\n // Join with semicolons to ensure proper statement separation\r\n // Arrow functions especially need this since they don't always have trailing semicolons\r\n return (\r\n functions.map((f) => f.trim()).join(\";\\n\") +\r\n (functions.length > 0 ? \";\" : \"\")\r\n );\r\n}\r\n\r\n/**\r\n * Extracts a complete braced block from content starting at startIndex.\r\n * Handles nested braces and strings correctly.\r\n */\r\nfunction extractBracedBlock(\r\n content: string,\r\n startIndex: number,\r\n braceStart?: number,\r\n): string | null\r\n{\r\n let braceCount = 0;\r\n let endIndex = startIndex;\r\n let inString = false;\r\n let stringChar = \"\";\r\n let foundFirstBrace = false;\r\n\r\n const searchStart = braceStart ?? startIndex;\r\n\r\n for (let i = searchStart; i < content.length; i++)\r\n {\r\n const char = content[i];\r\n const prevChar = i > 0 ? content[i - 1] : \"\";\r\n\r\n // Handle string detection (skip braces inside strings)\r\n if ((char === '\"' || char === \"'\" || char === \"`\") && prevChar !== \"\\\\\")\r\n {\r\n if (!inString)\r\n {\r\n inString = true;\r\n stringChar = char;\r\n } else if (char === stringChar)\r\n {\r\n inString = false;\r\n }\r\n }\r\n\r\n if (!inString)\r\n {\r\n if (char === \"{\")\r\n {\r\n braceCount++;\r\n foundFirstBrace = true;\r\n }\r\n if (char === \"}\") braceCount--;\r\n\r\n if (foundFirstBrace && braceCount === 0 && char === \"}\")\r\n {\r\n endIndex = i + 1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (braceCount !== 0) return null;\r\n return content.slice(startIndex, endIndex);\r\n}\r\n\r\n// ============================================================================\r\n// Script Parsing & Variable Extraction\r\n// ============================================================================\r\n\r\n/**\r\n * Executes script content in a sandboxed environment and extracts\r\n * all declared variables and functions.\r\n *\r\n * Example script:\r\n * let name = 'LadrillosJS';\r\n * function greet() { return `Hello ${name}`; }\r\n *\r\n * Returns: Map { 'name' => 'LadrillosJS', 'greet' => [Function] }\r\n *\r\n * @param content - The script content to execute\r\n * @param componentUrl - The component's URL for resolving relative paths in helpers\r\n * @param componentId - The component's unique ID for event bus cleanup\r\n */\r\nfunction extractScriptMembers(\r\n content: string,\r\n componentUrl?: string,\r\n componentId?: string,\r\n): Map<string, unknown>\r\n{\r\n const members = new Map<string, unknown>();\r\n\r\n try\r\n {\r\n const variableNames = extractVariableNames(content);\r\n const functionNames = extractFunctionNames(content);\r\n const allNames = [...variableNames, ...functionNames];\r\n\r\n // Always execute the script content (for side effects like console.log)\r\n // Only return members if there are any to extract\r\n // Add sourceURL so DevTools shows the component name instead of VM123:5\r\n const sourceUrl = componentUrl || \"ladrillos-component\";\r\n const wrappedScript = `\r\n \"use strict\";\r\n ${content}\r\n return { ${allNames.join(\", \")} };\r\n//# sourceURL=${sourceUrl}\r\n `;\r\n\r\n // Set up the sandboxed execution environment\r\n const allowed = getAllowedGlobalsWithValues(componentUrl, componentId);\r\n const safeBlocked = getSafeBlockedGlobals();\r\n\r\n const allKeys = [...safeBlocked, ...allowed.keys];\r\n const allValues = [\r\n ...safeBlocked.map(() => undefined), // Shadow dangerous globals\r\n ...allowed.values, // Inject safe globals\r\n ];\r\n\r\n const fn = new Function(...allKeys, wrappedScript);\r\n const result = fn(...allValues);\r\n\r\n for (const [key, value] of Object.entries(result))\r\n {\r\n members.set(key, value);\r\n }\r\n } catch (e)\r\n {\r\n scriptError(\"Error extracting script members\", e as Error);\r\n }\r\n\r\n return members;\r\n}\r\n\r\n/**\r\n * Extracts ONLY variable values from script content, without running side effects.\r\n * This is used in Phase 1 to get default values before reactive state is created.\r\n *\r\n * Unlike extractScriptMembers, this function:\r\n * - Only extracts variable declarations and their values\r\n * - Stubs out $listen and $emit to prevent side effects\r\n * - Does NOT extract functions (they'll be handled in Phase 2)\r\n *\r\n * @param content - The script content to parse\r\n */\r\nfunction extractScriptMembersValuesOnly(content: string): Map<string, unknown>\r\n{\r\n const members = new Map<string, unknown>();\r\n\r\n try\r\n {\r\n const variableNames = extractVariableNames(content);\r\n const functionNames = extractFunctionNames(content);\r\n const allNames = [...variableNames, ...functionNames];\r\n\r\n if (allNames.length === 0)\r\n {\r\n return members;\r\n }\r\n\r\n const wrappedScript = `\r\n \"use strict\";\r\n ${content}\r\n return { ${allNames.join(\", \")} };\r\n `;\r\n\r\n // Stub out $listen and $emit to prevent side effects during value extraction\r\n const stubListen = () => () => { }; // Returns unsubscribe function\r\n const stubEmit = () => { };\r\n\r\n // Minimal globals needed for value extraction\r\n const safeGlobals = [\r\n \"console\",\r\n \"Math\",\r\n \"JSON\",\r\n \"Date\",\r\n \"Array\",\r\n \"Object\",\r\n \"String\",\r\n \"Number\",\r\n \"Boolean\",\r\n ];\r\n const safeGlobalValues = safeGlobals.map(\r\n (name) => (globalThis as any)[name],\r\n );\r\n\r\n const allKeys = [...safeGlobals, \"$listen\", \"$emit\"];\r\n const allValues = [...safeGlobalValues, stubListen, stubEmit];\r\n\r\n const fn = new Function(...allKeys, wrappedScript);\r\n const result = fn(...allValues);\r\n\r\n for (const [key, value] of Object.entries(result))\r\n {\r\n members.set(key, value);\r\n }\r\n } catch (e)\r\n {\r\n // Silently handle errors - Phase 2 will re-execute with proper error handling\r\n }\r\n\r\n return members;\r\n}\r\n\r\n/**\r\n * Executes script content with __state__ transformation for reactivity.\r\n * This is Phase 2: runs after reactive state is created, so $listen callbacks\r\n * and other side effects can access the reactive state.\r\n *\r\n * The script is transformed so that:\r\n * - Variable declarations become __state__.varName = value\r\n * - Variable references become __state__.varName\r\n * - Callbacks capture __state__ reference (the reactive proxy)\r\n *\r\n * @param content - The script content to execute\r\n * @param reactiveState - The reactive state proxy\r\n * @param componentUrl - The component's URL for framework helpers\r\n * @param componentId - The component's ID for event bus cleanup\r\n * @param hostElement - The component's host element (for $host access)\r\n * @param refs - Optional refs Map (for $refs access)\r\n * @param templateBindings - Variable names from template bindings (auto-props)\r\n */\r\nfunction executeScriptWithReactiveState(\r\n content: string,\r\n reactiveState: Record<string, unknown>,\r\n componentUrl?: string,\r\n componentId?: string,\r\n hostElement?: HTMLElement,\r\n refs?: Map<string, HTMLElement>,\r\n templateBindings: string[] = [],\r\n): void\r\n{\r\n try\r\n {\r\n const variableNames = extractVariableNames(content);\r\n\r\n // Combine script variables with template bindings for transformation\r\n // This allows scripts to reference auto-bound props like {title} -> title\r\n const allVariables = [...new Set([...variableNames, ...templateBindings])];\r\n\r\n // Transform the script to use __state__ for variable access\r\n const transformedContent = transformCodeToStateAccess(\r\n content,\r\n allVariables,\r\n );\r\n\r\n const sourceUrl = componentUrl || \"ladrillos-component\";\r\n const wrappedScript = `\r\n \"use strict\";\r\n ${transformedContent}\r\n//# sourceURL=${sourceUrl}\r\n `;\r\n\r\n // Set up the sandboxed execution environment\r\n const allowed = getAllowedGlobalsWithValues(componentUrl, componentId);\r\n const safeBlocked = getSafeBlockedGlobals();\r\n\r\n // Add __state__, $host, and $refs as parameters\r\n const allKeys = [\r\n \"__state__\",\r\n \"$host\",\r\n \"$refs\",\r\n ...safeBlocked,\r\n ...allowed.keys,\r\n ];\r\n const allValues = [\r\n reactiveState, // __state__ points to reactive proxy\r\n hostElement, // $host points to the component's host element\r\n refs, // $refs points to the refs Map\r\n ...safeBlocked.map(() => undefined), // Shadow dangerous globals\r\n ...allowed.values, // Inject safe globals\r\n ];\r\n\r\n const fn = new Function(...allKeys, wrappedScript);\r\n fn(...allValues);\r\n } catch (e)\r\n {\r\n scriptError(\"Error executing script with reactive state\", e as Error);\r\n }\r\n}\r\n\r\n/**\r\n * Masks all function/arrow-function bodies in the source code with whitespace\r\n * (preserving newlines so line numbers stay aligned). This allows regex-based\r\n * extraction passes to reliably target only top-level declarations and\r\n * references, ignoring variables declared inside callbacks like\r\n * `$listen(..., (e) => { const x = ... })`.\r\n *\r\n * Limitations:\r\n * - Method shorthand on object literals (`obj = { foo() {} }`) is not\r\n * detected as a function body. Such usage is uncommon at top level in\r\n * component scripts, and any declarations inside will be (harmlessly)\r\n * treated as top-level.\r\n */\r\nfunction maskFunctionBodies(code: string): string\r\n{\r\n const chars = code.split(\"\");\r\n const len = code.length;\r\n let i = 0;\r\n let braceDepth = 0;\r\n let pendingFnBody = false;\r\n const fnStartDepths: number[] = [];\r\n const inFn = () => fnStartDepths.length > 0;\r\n\r\n const maskRange = (from: number, to: number) =>\r\n {\r\n for (let k = from; k < to; k++)\r\n {\r\n const ch = chars[k];\r\n if (ch !== \"\\n\" && ch !== \"\\r\") chars[k] = \" \";\r\n }\r\n };\r\n\r\n const skipLineComment = (start: number): number =>\r\n {\r\n let j = start;\r\n while (j < len && code[j] !== \"\\n\") j++;\r\n return j;\r\n };\r\n const skipBlockComment = (start: number): number =>\r\n {\r\n let j = start + 2;\r\n while (j < len - 1 && !(code[j] === \"*\" && code[j + 1] === \"/\")) j++;\r\n return Math.min(len, j + 2);\r\n };\r\n const skipString = (start: number, quote: string): number =>\r\n {\r\n let j = start + 1;\r\n while (j < len)\r\n {\r\n if (code[j] === \"\\\\\")\r\n {\r\n j += 2;\r\n continue;\r\n }\r\n if (code[j] === quote) return j + 1;\r\n if (code[j] === \"\\n\") return j; // unterminated; bail\r\n j++;\r\n }\r\n return j;\r\n };\r\n const skipTemplate = (start: number): number =>\r\n {\r\n let j = start + 1;\r\n while (j < len)\r\n {\r\n if (code[j] === \"\\\\\")\r\n {\r\n j += 2;\r\n continue;\r\n }\r\n if (code[j] === \"`\") return j + 1;\r\n if (code[j] === \"$\" && code[j + 1] === \"{\")\r\n {\r\n j += 2;\r\n let depth = 1;\r\n while (j < len && depth > 0)\r\n {\r\n const c = code[j];\r\n if (c === \"`\")\r\n {\r\n j = skipTemplate(j);\r\n continue;\r\n }\r\n if (c === '\"' || c === \"'\")\r\n {\r\n j = skipString(j, c);\r\n continue;\r\n }\r\n if (c === \"/\" && code[j + 1] === \"/\")\r\n {\r\n j = skipLineComment(j);\r\n continue;\r\n }\r\n if (c === \"/\" && code[j + 1] === \"*\")\r\n {\r\n j = skipBlockComment(j);\r\n continue;\r\n }\r\n if (c === \"{\") depth++;\r\n else if (c === \"}\") depth--;\r\n j++;\r\n }\r\n continue;\r\n }\r\n j++;\r\n }\r\n return j;\r\n };\r\n const isRegexContext = (idx: number): boolean =>\r\n {\r\n let j = idx - 1;\r\n while (j >= 0 && /\\s/.test(code[j])) j--;\r\n if (j < 0) return true;\r\n const c = code[j];\r\n if (\"([{,;:!&|?=+-*%^~<>\".includes(c)) return true;\r\n return /\\b(return|typeof|delete|void|in|of|new|instanceof|throw)$/.test(\r\n code.slice(0, j + 1),\r\n );\r\n };\r\n const skipRegex = (start: number): number =>\r\n {\r\n let j = start + 1;\r\n let inClass = false;\r\n while (j < len)\r\n {\r\n const c = code[j];\r\n if (c === \"\\\\\")\r\n {\r\n j += 2;\r\n continue;\r\n }\r\n if (c === \"[\") inClass = true;\r\n else if (c === \"]\") inClass = false;\r\n else if (c === \"/\" && !inClass)\r\n {\r\n j++;\r\n break;\r\n } else if (c === \"\\n\") break;\r\n j++;\r\n }\r\n while (j < len && /[a-zA-Z]/.test(code[j])) j++;\r\n return j;\r\n };\r\n\r\n while (i < len)\r\n {\r\n const c = code[i];\r\n\r\n if (c === \"/\" && code[i + 1] === \"/\")\r\n {\r\n const end = skipLineComment(i);\r\n if (inFn()) maskRange(i, end);\r\n i = end;\r\n continue;\r\n }\r\n if (c === \"/\" && code[i + 1] === \"*\")\r\n {\r\n const end = skipBlockComment(i);\r\n if (inFn()) maskRange(i, end);\r\n i = end;\r\n continue;\r\n }\r\n if (c === '\"' || c === \"'\")\r\n {\r\n const end = skipString(i, c);\r\n if (inFn()) maskRange(i, end);\r\n i = end;\r\n continue;\r\n }\r\n if (c === \"`\")\r\n {\r\n const end = skipTemplate(i);\r\n if (inFn()) maskRange(i, end);\r\n i = end;\r\n continue;\r\n }\r\n if (c === \"/\" && isRegexContext(i))\r\n {\r\n const end = skipRegex(i);\r\n if (inFn()) maskRange(i, end);\r\n i = end;\r\n continue;\r\n }\r\n\r\n if (c === \"{\")\r\n {\r\n braceDepth++;\r\n if (pendingFnBody)\r\n {\r\n fnStartDepths.push(braceDepth);\r\n pendingFnBody = false;\r\n } else if (inFn())\r\n {\r\n chars[i] = \" \";\r\n }\r\n i++;\r\n continue;\r\n }\r\n if (c === \"}\")\r\n {\r\n const closingFnBody =\r\n inFn() && fnStartDepths[fnStartDepths.length - 1] === braceDepth;\r\n if (closingFnBody)\r\n {\r\n fnStartDepths.pop();\r\n // Keep `}` un-masked so brace counting outside still works\r\n } else if (inFn())\r\n {\r\n chars[i] = \" \";\r\n }\r\n braceDepth--;\r\n i++;\r\n continue;\r\n }\r\n\r\n if (c === \"=\" && code[i + 1] === \">\")\r\n {\r\n if (inFn())\r\n {\r\n chars[i] = \" \";\r\n chars[i + 1] = \" \";\r\n } else\r\n {\r\n // Look ahead skipping whitespace/comments for `{` (concise body has\r\n // no declarations to worry about, so we only track block bodies).\r\n let j = i + 2;\r\n while (j < len)\r\n {\r\n const cc = code[j];\r\n if (/\\s/.test(cc))\r\n {\r\n j++;\r\n continue;\r\n }\r\n if (cc === \"/\" && code[j + 1] === \"/\")\r\n {\r\n j = skipLineComment(j);\r\n continue;\r\n }\r\n if (cc === \"/\" && code[j + 1] === \"*\")\r\n {\r\n j = skipBlockComment(j);\r\n continue;\r\n }\r\n break;\r\n }\r\n if (code[j] === \"{\") pendingFnBody = true;\r\n }\r\n i += 2;\r\n continue;\r\n }\r\n\r\n if (/[a-zA-Z_$]/.test(c))\r\n {\r\n const start = i;\r\n while (i < len && /[a-zA-Z0-9_$]/.test(code[i])) i++;\r\n const word = code.slice(start, i);\r\n if (inFn())\r\n {\r\n maskRange(start, i);\r\n } else if (word === \"function\")\r\n {\r\n pendingFnBody = true;\r\n }\r\n continue;\r\n }\r\n\r\n if (inFn() && c !== \"\\n\" && c !== \"\\r\")\r\n {\r\n chars[i] = \" \";\r\n }\r\n i++;\r\n }\r\n\r\n return chars.join(\"\");\r\n}\r\n\r\n/**\r\n * Finds variable declarations: let x = ..., const y = ..., var z = ...\r\n * Only returns TOP-LEVEL declarations — declarations inside callbacks,\r\n * arrow function bodies, and other nested scopes are intentionally skipped\r\n * so they remain real local variables after script transformation.\r\n *\r\n * Exported so webcomponent.ts can use it for observedAttributes.\r\n */\r\nexport function extractVariableNames(content: string): string[]\r\n{\r\n const masked = maskFunctionBodies(content);\r\n const names: string[] = [];\r\n const regex = /(?:let|const|var)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*=/g;\r\n let match;\r\n\r\n while ((match = regex.exec(masked)) !== null)\r\n {\r\n names.push(match[1]);\r\n }\r\n\r\n return names;\r\n}\r\n\r\n/**\r\n * Finds function declarations: function foo() {}, async function bar() {}\r\n * Only returns top-level declarations (consistent with extractVariableNames).\r\n */\r\nfunction extractFunctionNames(content: string): string[]\r\n{\r\n const masked = maskFunctionBodies(content);\r\n const names: string[] = [];\r\n const regex = /(?:async\\s+)?function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\(/g;\r\n let match;\r\n\r\n while ((match = regex.exec(masked)) !== null)\r\n {\r\n names.push(match[1]);\r\n }\r\n\r\n return names;\r\n}\r\n\r\n// ============================================================================\r\n// State Access Transformation\r\n// ============================================================================\r\n//\r\n// The transform itself lives in utils/stateTransform.ts\r\n// (transformCodeToStateAccess), shared with moduleExecutor.ts. It protects\r\n// string literals AND template-literal text segments, recursively transforms\r\n// ${...} interpolations, rewrites `let x = v` declarations to\r\n// `__state__.x ??= v`, and rewrites standalone references (object-shorthand\r\n// aware) to `__state__.x`.\r\n\r\n// ============================================================================\r\n// Security & Sandboxing Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Returns blocked globals, excluding JS reserved words that can't be\r\n * used as function parameter names (like 'with', 'class', etc.)\r\n */\r\nfunction getSafeBlockedGlobals(): readonly string[]\r\n{\r\n return BLOCKED_GLOBALS.filter((name) => !RESERVED_WORDS.has(name));\r\n}\r\n\r\n/**\r\n * Gets safe globals (alert, console, Math, JSON, etc.) with their actual values.\r\n * Also includes framework helpers like registerComponent, $use, $emit, $listen.\r\n * These are passed into the sandbox so component code feels like vanilla JS.\r\n *\r\n * @param componentUrl - The component's URL for resolving relative paths in helpers\r\n * @param componentId - The component's unique ID for event bus cleanup\r\n */\r\nfunction getAllowedGlobalsWithValues(\r\n componentUrl?: string,\r\n componentId?: string,\r\n):\r\n {\r\n keys: string[];\r\n values: unknown[];\r\n }\r\n{\r\n const keys: string[] = [];\r\n const values: unknown[] = [];\r\n\r\n // Add standard allowed globals (console, Math, JSON, etc.)\r\n for (const name of ALLOWED_GLOBALS)\r\n {\r\n if (name in globalThis)\r\n {\r\n keys.push(name);\r\n values.push((globalThis as any)[name]);\r\n }\r\n }\r\n\r\n // Add framework helpers bound to component URL for correct path resolution\r\n const helpers = createFrameworkHelpers(componentUrl || window.location.href);\r\n keys.push(...frameworkHelperNames);\r\n values.push(\r\n helpers.registerComponent,\r\n helpers.registerComponents,\r\n helpers.$use,\r\n );\r\n\r\n // Add event bus helpers bound to component ID for automatic cleanup\r\n const eventBusHelpers = createEventBusHelpers(componentId || \"anonymous\");\r\n keys.push(...eventBusHelperNames);\r\n values.push(eventBusHelpers.$emit, eventBusHelpers.$listen);\r\n\r\n return { keys, values };\r\n}\r\n\r\n// ============================================================================\r\n// Template Binding Evaluation\r\n// ============================================================================\r\n\r\n/**\r\n * Evaluates a binding expression like {name} or {name.toUpperCase()}\r\n * in the component's context.\r\n */\r\n/**\r\n * Cache of compiled expression evaluators.\r\n *\r\n * Compiling an expression with `new Function()` is expensive (parse + JIT) and\r\n * was previously done on EVERY evaluation. In the directive update path this\r\n * meant recompiling the same expression once per item per render — e.g. an\r\n * `$for` over 1000 rows recompiled its bindings 1000+ times on each update.\r\n * Caching the compiled function turns repeat evaluations into a plain call.\r\n *\r\n * The cache key combines the positional parameter names (the current state\r\n * keys) with the expression source, since the compiled function's parameters\r\n * are positional. The blocked globals are constant for the page lifetime, so\r\n * they don't need to participate in the key.\r\n */\r\nconst evaluatorCache = new Map<string, Map<string, Function>>();\r\nconst MAX_EVALUATOR_SIGNATURES = 100;\r\nconst MAX_EVALUATOR_CACHE = 5000;\r\n\r\n/** Matches strings usable as a JS function parameter name (no hyphens, etc.). */\r\nconst IDENTIFIER_RE = /^[A-Za-z_$][\\w$]*$/;\r\n\r\n// Blocked globals never change at runtime, so compute the param list and the\r\n// matching `undefined` argument array once and reuse them.\r\nlet cachedBlockedGlobals: readonly string[] | null = null;\r\nlet cachedBlockedUndefined: undefined[] | null = null;\r\n\r\nfunction evaluateExpression(\r\n expression: string,\r\n state: Record<string, unknown>,\r\n): unknown\r\n{\r\n try\r\n {\r\n // Only valid JS identifiers can be `new Function` parameter names. Some\r\n // state keys come from DOM attributes, which may be hyphenated (e.g.\r\n // \"data-id\", \"is-open\"); passing those as params would throw a SyntaxError\r\n // and break EVERY binding on the component. They can't be referenced in\r\n // expressions anyway, so drop them (and their values) here.\r\n const allKeys = Object.keys(state);\r\n const keys: string[] = [];\r\n const stateValues: unknown[] = [];\r\n for (let i = 0; i < allKeys.length; i++)\r\n {\r\n const k = allKeys[i];\r\n if (IDENTIFIER_RE.test(k))\r\n {\r\n keys.push(k);\r\n stateValues.push(state[k]);\r\n }\r\n }\r\n\r\n ensureBlockedGlobals();\r\n\r\n const exprMap = getEvaluatorMap(keys.join(\",\"));\r\n const fn = getCompiledEvaluator(keys, exprMap, expression);\r\n return fn(...cachedBlockedUndefined!, ...stateValues);\r\n } catch (e)\r\n {\r\n expressionError(expression, e as Error, {\r\n context: getComponentContext(),\r\n });\r\n return `{${expression}}`; // Return original on error\r\n }\r\n}\r\n\r\nfunction ensureBlockedGlobals(): readonly string[]\r\n{\r\n if (cachedBlockedGlobals === null)\r\n {\r\n cachedBlockedGlobals = getSafeBlockedGlobals();\r\n cachedBlockedUndefined = cachedBlockedGlobals.map(() => undefined);\r\n }\r\n return cachedBlockedGlobals;\r\n}\r\n\r\n/**\r\n * Returns the per-key-signature expression map for compiled evaluators.\r\n *\r\n * The cache is two-level (keysSig -> expression -> fn) so hot paths that\r\n * evaluate many expressions against one context shape can resolve the\r\n * signature once and then hit the inner map with the short expression\r\n * string - hashing the long joined key signature on every evaluation is\r\n * measurable when a loop update runs thousands of evals per flush.\r\n */\r\nfunction getEvaluatorMap(keysSig: string): Map<string, Function>\r\n{\r\n let exprMap = evaluatorCache.get(keysSig);\r\n if (!exprMap)\r\n {\r\n // Bound the number of distinct context shapes (FIFO eviction).\r\n if (evaluatorCache.size >= MAX_EVALUATOR_SIGNATURES)\r\n {\r\n const oldest = evaluatorCache.keys().next().value;\r\n if (oldest !== undefined) evaluatorCache.delete(oldest);\r\n }\r\n exprMap = new Map();\r\n evaluatorCache.set(keysSig, exprMap);\r\n }\r\n return exprMap;\r\n}\r\n\r\n/**\r\n * Returns the compiled evaluator for `expression` against the given state\r\n * keys, compiling and caching it on first use.\r\n *\r\n * Positional params are [blocked globals..., state keys...]. Only the state\r\n * keys + expression distinguish one compiled evaluator from another.\r\n */\r\nfunction getCompiledEvaluator(\r\n keys: string[],\r\n exprMap: Map<string, Function>,\r\n expression: string,\r\n): Function\r\n{\r\n let fn = exprMap.get(expression);\r\n if (!fn)\r\n {\r\n // Bound the cache so long-lived apps with many distinct expressions\r\n // don't grow it without limit (FIFO eviction of the oldest entry).\r\n if (exprMap.size >= MAX_EVALUATOR_CACHE)\r\n {\r\n const oldest = exprMap.keys().next().value;\r\n if (oldest !== undefined) exprMap.delete(oldest);\r\n }\r\n fn = new Function(\r\n ...cachedBlockedGlobals!,\r\n ...keys,\r\n `\"use strict\"; return ${expression};`,\r\n );\r\n exprMap.set(expression, fn);\r\n }\r\n return fn;\r\n}\r\n\r\n/**\r\n * Builds a pass-scoped fast evaluator bound to one context object.\r\n *\r\n * The generic `evaluateExpression(expr, context)` pays per call for\r\n * `Object.keys`, identifier filtering, and the cache-key join — noticeable\r\n * when a loop update evaluates thousands of bindings against one shared\r\n * context per flush. This factory hoists all of that: keys are extracted\r\n * once and the argument array is preallocated.\r\n *\r\n * Two modes:\r\n * - Legacy (no `volatileKeys`): every call refills ALL value slots from\r\n * the context, so callers may mutate any context value between calls.\r\n * - Static (`volatileKeys` given): all slots are filled once at creation;\r\n * only the named volatile slots are refilled — and only when the caller\r\n * invokes `refresh()` after mutating them. All other context VALUES\r\n * must stay unchanged for the evaluator's lifetime. This is the loop\r\n * renderer's mode: state values are constant within a flush, only the\r\n * item/index slots change per row.\r\n *\r\n * CONTRACT (both modes): the context's KEY SET must not change for the\r\n * lifetime of the returned evaluator. Callers create one per render pass\r\n * after all keys (including loop item/index) are present.\r\n *\r\n * The returned evaluator also exposes `compile`/`invoke`/`sig` so hot loops\r\n * can resolve an expression's compiled Function once per template and skip\r\n * the per-eval cache lookup entirely.\r\n */\r\nfunction createContextEvaluator(\r\n context: Record<string, unknown>,\r\n volatileKeys?: readonly string[],\r\n): BoundEvaluator\r\n{\r\n const blocked = ensureBlockedGlobals();\r\n\r\n const allKeys = Object.keys(context);\r\n const keys: string[] = [];\r\n for (let i = 0; i < allKeys.length; i++)\r\n {\r\n if (IDENTIFIER_RE.test(allKeys[i]))\r\n {\r\n keys.push(allKeys[i]);\r\n }\r\n }\r\n const sig = keys.join(\",\");\r\n const exprMap = getEvaluatorMap(sig);\r\n const nBlocked = blocked.length;\r\n const args: unknown[] = new Array(nBlocked + keys.length).fill(undefined);\r\n\r\n const fillAll = (): void =>\r\n {\r\n for (let i = 0; i < keys.length; i++)\r\n {\r\n args[nBlocked + i] = context[keys[i]];\r\n }\r\n };\r\n\r\n const isStatic = volatileKeys !== undefined;\r\n let volatileSlots: number[] | null = null;\r\n let volatileNames: string[] | null = null;\r\n if (isStatic)\r\n {\r\n fillAll();\r\n volatileSlots = [];\r\n volatileNames = [];\r\n for (const name of volatileKeys)\r\n {\r\n const idx = keys.indexOf(name);\r\n if (idx >= 0)\r\n {\r\n volatileSlots.push(nBlocked + idx);\r\n volatileNames.push(name);\r\n }\r\n }\r\n }\r\n\r\n const evaluator = ((expression: string): unknown =>\r\n {\r\n try\r\n {\r\n const fn = getCompiledEvaluator(keys, exprMap, expression);\r\n if (!isStatic) fillAll();\r\n return fn.apply(null, args);\r\n } catch (e)\r\n {\r\n expressionError(expression, e as Error, {\r\n context: getComponentContext(),\r\n });\r\n return `{${expression}}`; // Return original on error\r\n }\r\n }) as BoundEvaluator;\r\n\r\n evaluator.sig = sig;\r\n evaluator.refresh = isStatic\r\n ? (): void =>\r\n {\r\n for (let i = 0; i < volatileSlots!.length; i++)\r\n {\r\n args[volatileSlots![i]] = context[volatileNames![i]];\r\n }\r\n }\r\n : fillAll;\r\n evaluator.compile = (expression: string): Function | null =>\r\n {\r\n try\r\n {\r\n return getCompiledEvaluator(keys, exprMap, expression);\r\n } catch (e)\r\n {\r\n expressionError(expression, e as Error, {\r\n context: getComponentContext(),\r\n });\r\n return null;\r\n }\r\n };\r\n evaluator.invoke = (fn: Function, expression: string): unknown =>\r\n {\r\n try\r\n {\r\n if (!isStatic) fillAll();\r\n return fn.apply(null, args);\r\n } catch (e)\r\n {\r\n expressionError(expression, e as Error, {\r\n context: getComponentContext(),\r\n });\r\n return `{${expression}}`; // Return original on error\r\n }\r\n };\r\n return evaluator;\r\n}\r\n\r\n/**\r\n * Returns true for values that cannot survive a trip through a DOM attribute\r\n * (which can only hold strings): arrays, objects and functions.\r\n */\r\nfunction isNonPrimitive(value: unknown): boolean\r\n{\r\n return value !== null && (typeof value === \"object\" || typeof value === \"function\");\r\n}\r\n\r\n/**\r\n * Detects a \"pure\" attribute binding where the entire attribute value is a\r\n * single {expression} with no surrounding literal text (e.g. items={items},\r\n * but NOT alt=\"{name} logo\"). These are the only bindings eligible to be\r\n * passed as a typed DOM property instead of a stringified attribute.\r\n */\r\nfunction isPureAttributeBinding(descriptor: BindingDescriptor): boolean\r\n{\r\n if (!descriptor.isAttribute || !descriptor.attributeName) return false;\r\n if (descriptor.bindings.length !== 1) return false;\r\n const trimmed = descriptor.original.trim();\r\n if (!/^\\{[\\s\\S]*\\}$/.test(trimmed)) return false;\r\n return trimmed.slice(1, -1).trim() === descriptor.bindings[0].raw.trim();\r\n}\r\n\r\n/**\r\n * HTML boolean attributes: their presence (not their value) is what matters.\r\n * `<button disabled>` and `<button disabled=\"false\">` are BOTH disabled, so a\r\n * binding like disabled=\"{isDisabled}\" must ADD or REMOVE the attribute rather\r\n * than stringify the boolean. Mirrors how Vue/Lit treat boolean attributes.\r\n */\r\nconst BOOLEAN_ATTRIBUTES = new Set([\r\n \"disabled\",\r\n \"checked\",\r\n \"readonly\",\r\n \"required\",\r\n \"selected\",\r\n \"hidden\",\r\n \"multiple\",\r\n \"autofocus\",\r\n \"open\",\r\n \"novalidate\",\r\n \"formnovalidate\",\r\n \"inert\",\r\n \"reversed\",\r\n \"loop\",\r\n \"muted\",\r\n \"controls\",\r\n \"autoplay\",\r\n \"playsinline\",\r\n \"default\",\r\n \"ismap\",\r\n \"allowfullscreen\",\r\n]);\r\n\r\n/**\r\n * Sets a primitive (string/number/boolean) value onto a single-binding\r\n * attribute, applying two web-standard conventions:\r\n *\r\n * 1. Boolean attributes (disabled, checked, …) toggle presence: truthy adds\r\n * the attribute, falsy removes it.\r\n * 2. `null`/`undefined` removes the attribute entirely, so optional props\r\n * (tooltip=\"{tooltip}\", name=\"{name}\") default to absent instead of \"\".\r\n *\r\n * Other primitives are stringified as before, preserving existing behavior.\r\n */\r\nfunction setPrimitiveAttribute(\r\n element: Element,\r\n name: string,\r\n value: unknown,\r\n): void\r\n{\r\n if (BOOLEAN_ATTRIBUTES.has(name))\r\n {\r\n if (value) element.setAttribute(name, \"\");\r\n else element.removeAttribute(name);\r\n return;\r\n }\r\n\r\n if (value === null || value === undefined)\r\n {\r\n element.removeAttribute(name);\r\n return;\r\n }\r\n\r\n element.setAttribute(name, String(value));\r\n}\r\n\r\n/**\r\n * Updates a single binding with new state values.\r\n * Called by the reactive system when a dependency changes.\r\n */\r\nfunction updateSingleBinding(\r\n descriptor: BindingDescriptor,\r\n state: Record<string, unknown>,\r\n): void\r\n{\r\n // Pure attribute bindings (the whole value is a single {expr}) can preserve\r\n // the evaluated value's data type. When the value is a non-primitive\r\n // (array/object/function), assign it as a DOM PROPERTY on the target element\r\n // instead of stringifying it into an attribute. This mirrors how Lit/Vue\r\n // pass complex props to custom elements and lets children receive a real\r\n // array/object instead of \"item1,item2,item3\".\r\n if (isPureAttributeBinding(descriptor))\r\n {\r\n const element =\r\n (descriptor as any).element ?? descriptor.node.parentElement;\r\n const evaluated = evaluateExpression(descriptor.bindings[0].raw, state);\r\n\r\n if (element)\r\n {\r\n if (isNonPrimitive(evaluated))\r\n {\r\n // Remove the stringy attribute first so a null attributeChangedCallback\r\n // can't clobber the typed value we set on the next line.\r\n if (element.hasAttribute?.(descriptor.attributeName!))\r\n {\r\n element.removeAttribute(descriptor.attributeName!);\r\n }\r\n (element as any)[descriptor.attributeName!] = evaluated;\r\n } else\r\n {\r\n setPrimitiveAttribute(\r\n element,\r\n descriptor.attributeName!,\r\n evaluated,\r\n );\r\n }\r\n }\r\n return;\r\n }\r\n\r\n let result = descriptor.original;\r\n\r\n // Evaluate and replace each {expression} in the text\r\n for (const binding of descriptor.bindings)\r\n {\r\n const evaluated = evaluateExpression(binding.raw, state);\r\n const stringValue = String(evaluated ?? \"\");\r\n result = result.replace(`{${binding.raw}}`, stringValue);\r\n }\r\n\r\n if (descriptor.isAttribute && descriptor.attributeName)\r\n {\r\n // Update element attribute\r\n const element =\r\n (descriptor as any).element ?? descriptor.node.parentElement;\r\n if (element)\r\n {\r\n element.setAttribute(descriptor.attributeName, result);\r\n }\r\n } else\r\n {\r\n // Update text node content\r\n descriptor.node.textContent = result;\r\n }\r\n}\r\n\r\n/**\r\n * Replaces all {expression} bindings in the template with their evaluated values.\r\n *\r\n * Handles both:\r\n * - Text nodes: <h1>Hello {name}!</h1>\r\n * - Attributes: <img src=\"{imageUrl}\" alt=\"{name} logo\">\r\n */\r\nfunction applyBindings(\r\n bindings: BindingDescriptor[],\r\n state: Record<string, unknown>,\r\n): void\r\n{\r\n for (const descriptor of bindings)\r\n {\r\n updateSingleBinding(descriptor, state);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Expression Evaluator Export\r\n// ============================================================================\r\n\r\n/**\r\n * A pass-scoped evaluator bound to one context object, produced by\r\n * `DirectiveEvaluator.forContext`. Callable as `(expr) => unknown`; the\r\n * optional members let hot loops skip per-eval overhead (see\r\n * `createContextEvaluator` for the mode semantics).\r\n */\r\nexport interface BoundEvaluator\r\n{\r\n (expr: string): unknown;\r\n /**\r\n * Refill argument slots from the context: the volatile slots in static\r\n * mode, all slots in legacy mode. Static-mode callers MUST call this\r\n * after mutating a volatile context value.\r\n */\r\n refresh?: () => void;\r\n /** Compiled Function for `expr` under this key set, or null on a syntax error. */\r\n compile?: (expr: string) => Function | null;\r\n /** Invoke a Function from `compile` against the current argument slots. */\r\n invoke?: (fn: Function, expr: string) => unknown;\r\n /** Key-set signature; compiled Functions are only valid for a matching sig. */\r\n sig?: string;\r\n}\r\n\r\n/**\r\n * Directive-facing expression evaluator. Callable as\r\n * `(expr, context) => unknown`; `forContext` additionally builds a\r\n * pass-scoped fast evaluator bound to one context object (see\r\n * `createContextEvaluator`) whose key set must not change for the\r\n * lifetime of the returned function.\r\n */\r\nexport interface DirectiveEvaluator\r\n{\r\n (expr: string, context: Record<string, unknown>): unknown;\r\n forContext(\r\n context: Record<string, unknown>,\r\n volatileKeys?: readonly string[],\r\n ): BoundEvaluator;\r\n}\r\n\r\n/**\r\n * Creates and returns an expression evaluator function for use by directives.\r\n * This allows directives to evaluate expressions like \"item.name\" or \"count > 5\"\r\n * in the context of the component's state.\r\n */\r\nexport function createExpressionEvaluator(): DirectiveEvaluator\r\n{\r\n const evaluator = evaluateExpression as DirectiveEvaluator;\r\n evaluator.forContext = createContextEvaluator;\r\n return evaluator;\r\n}\r\n","/**\r\n * Framework-level configuration API for LadrillosJS.\r\n *\r\n * Exposed to consumers via `import { configure } from 'ladrillosjs'`.\r\n * All options are optional; unspecified keys retain their defaults.\r\n */\r\n\r\nimport { setCacheSize } from \"./component/cache\";\r\nimport {\r\n setErrorHandler,\r\n type LadrillosErrorHandler,\r\n} from \"../utils/devWarnings\";\r\n\r\n/**\r\n * Options accepted by `configure()`.\r\n */\r\nexport interface LadrillosConfig {\r\n /**\r\n * Maximum number of component source files retained in the LRU cache.\r\n * Defaults to 25. Must be a positive integer.\r\n */\r\n cacheSize?: number;\r\n\r\n /**\r\n * Custom error handler. Called in addition to the framework's built-in\r\n * console logging so embedders can route framework errors to telemetry.\r\n *\r\n * @example\r\n * configure({\r\n * onError: (err) => telemetry.capture(err),\r\n * });\r\n */\r\n onError?: LadrillosErrorHandler | null;\r\n\r\n /**\r\n * Opt-in event delegation for `<for>` loop rows. When enabled, eligible\r\n * inline handlers (onclick, $on:… on bubbling events) inside loop rows\r\n * share ONE listener per event type on the loop's container instead of\r\n * one listener per element — faster bulk row creation and less memory on\r\n * large lists. Handler code and template syntax are unchanged.\r\n *\r\n * Two observable differences versus direct listeners:\r\n * 1. `event.currentTarget` inside a loop handler is the list container,\r\n * not the row element (`event.target` is unaffected).\r\n * 2. A manual `stopPropagation()` call from a listener you attach\r\n * yourself between the row and the container stops delegated\r\n * handlers from firing.\r\n *\r\n * Non-bubbling events (focus, blur, mouseenter, …) and handlers using\r\n * the `.self`, `.capture`, `.once`, or `.passive` modifiers automatically\r\n * keep per-element listeners.\r\n *\r\n * Set this before components render; templates already rendered keep the\r\n * mode they were created with. Defaults to false.\r\n */\r\n delegateLoopEvents?: boolean;\r\n}\r\n\r\nlet loopDelegationEnabled = false;\r\n\r\n/** Whether opt-in loop event delegation is active (see LadrillosConfig). */\r\nexport function isLoopDelegationEnabled(): boolean {\r\n return loopDelegationEnabled;\r\n}\r\n\r\n/**\r\n * Configure framework-level options.\r\n *\r\n * Safe to call at any time; subsequent calls override prior values. Pass\r\n * `onError: null` to clear a previously registered handler.\r\n */\r\nexport function configure(config: LadrillosConfig): void {\r\n if (config.cacheSize !== undefined) {\r\n setCacheSize(config.cacheSize);\r\n }\r\n if (config.onError !== undefined) {\r\n setErrorHandler(config.onError);\r\n }\r\n if (config.delegateLoopEvents !== undefined) {\r\n loopDelegationEnabled = config.delegateLoopEvents;\r\n }\r\n}\r\n","/**\r\n * Keyed List Diffing Algorithm\r\n *\r\n * Uses a simplified LIS (Longest Increasing Subsequence) approach\r\n * for optimal DOM operations.\r\n *\r\n * Benefits:\r\n * - Minimizes DOM operations (moves instead of recreate)\r\n * - Preserves element state (focus, scroll, animations)\r\n * - O(n) best case, O(n log n) worst case\r\n *\r\n * Usage with $for:\r\n * $for=\"item in items track by item.id\"\r\n * ^^^^^^^^^^^^^^\r\n * Key expression for efficient diffing\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport interface DiffOperation\r\n{\r\n type: \"insert\" | \"remove\" | \"move\" | \"update\";\r\n /** Index in the old array (for remove/move/update) */\r\n oldIndex?: number;\r\n /** Index in the new array (for insert/move/update) */\r\n newIndex?: number;\r\n /** The item data */\r\n item?: unknown;\r\n /** Key for keyed operations */\r\n key?: unknown;\r\n}\r\n\r\ninterface KeyedItem\r\n{\r\n key: unknown;\r\n item: unknown;\r\n index: number;\r\n}\r\n\r\n// ============================================================================\r\n// Keyed Diffing\r\n// ============================================================================\r\n\r\n/**\r\n * Computes the minimal set of DOM operations to transform oldItems into newItems.\r\n * Uses keys for identity matching - items with the same key are considered the same.\r\n *\r\n * @param oldItems - Previous array items\r\n * @param newItems - New array items\r\n * @param getKey - Function to extract a unique key from an item\r\n * @returns Array of operations to perform\r\n *\r\n * @example\r\n * const ops = diffKeyed(\r\n * [{ id: 1, name: 'A' }, { id: 2, name: 'B' }],\r\n * [{ id: 2, name: 'B' }, { id: 1, name: 'A' }, { id: 3, name: 'C' }],\r\n * item => item.id\r\n * );\r\n * // ops = [\r\n * // { type: 'move', oldIndex: 1, newIndex: 0, key: 2 },\r\n * // { type: 'move', oldIndex: 0, newIndex: 1, key: 1 },\r\n * // { type: 'insert', newIndex: 2, key: 3, item: { id: 3, name: 'C' } }\r\n * // ]\r\n */\r\nexport function diffKeyed<T>(\r\n oldItems: T[],\r\n newItems: T[],\r\n getKey: (item: T, index: number) => unknown\r\n): DiffOperation[]\r\n{\r\n const operations: DiffOperation[] = [];\r\n\r\n // Build key -> index maps\r\n const oldKeyToIndex = new Map<unknown, number>();\r\n const newKeyToIndex = new Map<unknown, number>();\r\n\r\n for (let i = 0; i < oldItems.length; i++)\r\n {\r\n oldKeyToIndex.set(getKey(oldItems[i], i), i);\r\n }\r\n\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n newKeyToIndex.set(getKey(newItems[i], i), i);\r\n }\r\n\r\n // Track which old items have been matched\r\n const matchedOld = new Set<number>();\r\n const matchedNew = new Set<number>();\r\n\r\n // Phase 1: Find items to remove (in old but not in new)\r\n for (let i = 0; i < oldItems.length; i++)\r\n {\r\n const key = getKey(oldItems[i], i);\r\n if (!newKeyToIndex.has(key))\r\n {\r\n operations.push({\r\n type: \"remove\",\r\n oldIndex: i,\r\n key,\r\n item: oldItems[i],\r\n });\r\n }\r\n }\r\n\r\n // Phase 2: Find items to insert (in new but not in old)\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n const key = getKey(newItems[i], i);\r\n if (!oldKeyToIndex.has(key))\r\n {\r\n operations.push({\r\n type: \"insert\",\r\n newIndex: i,\r\n key,\r\n item: newItems[i],\r\n });\r\n matchedNew.add(i);\r\n }\r\n }\r\n\r\n // Phase 3: Find moves using LIS for minimal operations\r\n // Build array of new positions for matched items\r\n const newPositions: number[] = [];\r\n const oldToNew: number[] = [];\r\n\r\n for (let i = 0; i < oldItems.length; i++)\r\n {\r\n const key = getKey(oldItems[i], i);\r\n const newIdx = newKeyToIndex.get(key);\r\n if (newIdx !== undefined)\r\n {\r\n newPositions.push(newIdx);\r\n oldToNew[i] = newIdx;\r\n }\r\n }\r\n\r\n // Find LIS to determine which items don't need to move\r\n const lisIndices = longestIncreasingSubsequence(newPositions);\r\n const lisSet = new Set(lisIndices.map((i) => newPositions[i]));\r\n\r\n // Items not in LIS need to be moved\r\n let oldIdx = 0;\r\n for (const newPos of newPositions)\r\n {\r\n while (\r\n oldIdx < oldItems.length &&\r\n !newKeyToIndex.has(getKey(oldItems[oldIdx], oldIdx))\r\n )\r\n {\r\n oldIdx++;\r\n }\r\n\r\n if (oldIdx < oldItems.length)\r\n {\r\n const key = getKey(oldItems[oldIdx], oldIdx);\r\n const oldIndex = oldIdx;\r\n const newIndex = newKeyToIndex.get(key)!;\r\n\r\n if (!lisSet.has(newIndex))\r\n {\r\n operations.push({\r\n type: \"move\",\r\n oldIndex,\r\n newIndex,\r\n key,\r\n item: oldItems[oldIndex],\r\n });\r\n }\r\n oldIdx++;\r\n }\r\n }\r\n\r\n // Phase 4: Find updates (same key but different content)\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n const key = getKey(newItems[i], i);\r\n const oldIdx = oldKeyToIndex.get(key);\r\n if (oldIdx !== undefined)\r\n {\r\n const oldItem = oldItems[oldIdx];\r\n const newItem = newItems[i];\r\n // Only mark as update if content actually changed\r\n if (!shallowEqual(oldItem, newItem))\r\n {\r\n operations.push({\r\n type: \"update\",\r\n oldIndex: oldIdx,\r\n newIndex: i,\r\n key,\r\n item: newItem,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return operations;\r\n}\r\n\r\n/**\r\n * Simpler diff for non-keyed lists.\r\n * Less efficient but works when items don't have stable identity.\r\n *\r\n * @param oldLength - Previous array length\r\n * @param newLength - New array length\r\n * @param newItems - New array items\r\n * @returns Array of operations\r\n */\r\nexport function diffUnkeyed<T>(\r\n oldLength: number,\r\n newLength: number,\r\n newItems: T[]\r\n): DiffOperation[]\r\n{\r\n const operations: DiffOperation[] = [];\r\n\r\n // Items to remove\r\n for (let i = newLength; i < oldLength; i++)\r\n {\r\n operations.push({ type: \"remove\", oldIndex: i });\r\n }\r\n\r\n // Items to insert\r\n for (let i = oldLength; i < newLength; i++)\r\n {\r\n operations.push({ type: \"insert\", newIndex: i, item: newItems[i] });\r\n }\r\n\r\n // All remaining items need update\r\n for (let i = 0; i < Math.min(oldLength, newLength); i++)\r\n {\r\n operations.push({\r\n type: \"update\",\r\n oldIndex: i,\r\n newIndex: i,\r\n item: newItems[i],\r\n });\r\n }\r\n\r\n return operations;\r\n}\r\n\r\n// ============================================================================\r\n// LIS Algorithm (for optimal move detection)\r\n// ============================================================================\r\n\r\n/**\r\n * Finds the Longest Increasing Subsequence.\r\n * Used to determine which items are already in correct relative order.\r\n *\r\n * @param arr - Array of numbers\r\n * @returns Indices of the LIS in the original array\r\n */\r\nfunction longestIncreasingSubsequence(arr: number[]): number[]\r\n{\r\n if (arr.length === 0) return [];\r\n\r\n const n = arr.length;\r\n const dp: number[] = new Array(n).fill(1);\r\n const parent: number[] = new Array(n).fill(-1);\r\n let maxLength = 1;\r\n let maxIndex = 0;\r\n\r\n for (let i = 1; i < n; i++)\r\n {\r\n for (let j = 0; j < i; j++)\r\n {\r\n if (arr[j] < arr[i] && dp[j] + 1 > dp[i])\r\n {\r\n dp[i] = dp[j] + 1;\r\n parent[i] = j;\r\n }\r\n }\r\n if (dp[i] > maxLength)\r\n {\r\n maxLength = dp[i];\r\n maxIndex = i;\r\n }\r\n }\r\n\r\n // Reconstruct the LIS\r\n const result: number[] = [];\r\n let current = maxIndex;\r\n while (current !== -1)\r\n {\r\n result.unshift(current);\r\n current = parent[current];\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Computes the set of positions that form the longest increasing subsequence\r\n * of `source`, ignoring entries whose value is < 0 (used to mark brand-new\r\n * items that must always be (re)inserted).\r\n *\r\n * The loop renderer uses this to decide which reused elements are already in\r\n * correct relative DOM order and can therefore stay put — only the remaining\r\n * elements need to be moved. This turns an in-order content update into zero\r\n * DOM moves and minimizes moves for partial reorders.\r\n *\r\n * Runs in O(n log n) using patience sorting with predecessor links.\r\n *\r\n * @param source - For each new position, the element's previous index, or -1 if new\r\n * @returns Set of new-position indices that should NOT be moved\r\n */\r\nexport function getStableIndices(source: number[]): Set<number>\r\n{\r\n const n = source.length;\r\n const result = new Set<number>();\r\n if (n === 0) return result;\r\n\r\n // Fast path: reused indices already in increasing order (the common case —\r\n // pure content updates, appends, single removes). Every reused element is\r\n // then stable by definition, so the patience sort below can be skipped.\r\n let prevValue = -1;\r\n let inOrder = true;\r\n for (let i = 0; i < n; i++)\r\n {\r\n const value = source[i];\r\n if (value < 0) continue;\r\n if (value <= prevValue)\r\n {\r\n inOrder = false;\r\n break;\r\n }\r\n prevValue = value;\r\n }\r\n if (inOrder)\r\n {\r\n for (let i = 0; i < n; i++)\r\n {\r\n if (source[i] >= 0) result.add(i);\r\n }\r\n return result;\r\n }\r\n\r\n // piles[k] holds the position with the smallest tail value for an increasing\r\n // run of length k + 1. prev links each position to its predecessor in the run.\r\n const piles: number[] = [];\r\n const prev: number[] = new Array(n).fill(-1);\r\n\r\n for (let i = 0; i < n; i++)\r\n {\r\n const value = source[i];\r\n if (value < 0) continue; // new element — never part of the stable run\r\n\r\n // Binary search for the first pile whose tail value is >= value.\r\n let lo = 0;\r\n let hi = piles.length;\r\n while (lo < hi)\r\n {\r\n const mid = (lo + hi) >> 1;\r\n if (source[piles[mid]] < value) lo = mid + 1;\r\n else hi = mid;\r\n }\r\n\r\n if (lo > 0) prev[i] = piles[lo - 1];\r\n piles[lo] = i;\r\n }\r\n\r\n // Walk the predecessor chain back from the last pile to collect the LIS.\r\n let cur = piles.length > 0 ? piles[piles.length - 1] : -1;\r\n while (cur !== -1)\r\n {\r\n result.add(cur);\r\n cur = prev[cur];\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ============================================================================\r\n// Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Shallow equality check for detecting content changes.\r\n */\r\nfunction shallowEqual(a: unknown, b: unknown): boolean\r\n{\r\n if (a === b) return true;\r\n if (typeof a !== typeof b) return false;\r\n if (a === null || b === null) return a === b;\r\n if (typeof a !== \"object\") return a === b;\r\n\r\n const aObj = a as Record<string, unknown>;\r\n const bObj = b as Record<string, unknown>;\r\n\r\n const aKeys = Object.keys(aObj);\r\n const bKeys = Object.keys(bObj);\r\n\r\n if (aKeys.length !== bKeys.length) return false;\r\n\r\n for (const key of aKeys)\r\n {\r\n if (aObj[key] !== bObj[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Creates a key getter function from a key expression.\r\n *\r\n * @param keyExpr - Key expression (e.g., \"item.id\" or just \"id\" if item is scope)\r\n * @param itemName - The loop variable name (e.g., \"item\")\r\n * @returns A function that extracts the key from an item\r\n *\r\n * @example\r\n * const getKey = createKeyGetter(\"item.id\", \"item\");\r\n * getKey({ id: 123, name: \"foo\" }) // 123\r\n */\r\nexport function createKeyGetter<T>(\r\n keyExpr: string | undefined,\r\n itemName: string\r\n): (item: T, index: number) => unknown\r\n{\r\n if (!keyExpr)\r\n {\r\n // No key expression - use index as key (not ideal but functional)\r\n return (_item, index) => index;\r\n }\r\n\r\n // Handle \"item.id\" -> extract \"id\" from item\r\n // Handle just \"id\" -> assume it's a property of item\r\n const path = keyExpr.startsWith(itemName + \".\")\r\n ? keyExpr.slice(itemName.length + 1).split(\".\")\r\n : keyExpr.split(\".\");\r\n\r\n return (item: T) =>\r\n {\r\n let value: unknown = item;\r\n for (const key of path)\r\n {\r\n if (value === null || value === undefined) return undefined;\r\n value = (value as Record<string, unknown>)[key];\r\n }\r\n return value;\r\n };\r\n}\r\n\r\n/**\r\n * Applies diff operations to a list of DOM elements.\r\n * This is the main integration point with the loop renderer.\r\n *\r\n * @param container - Parent element containing the list\r\n * @param elements - Current rendered elements\r\n * @param operations - Diff operations to apply\r\n * @param createFn - Function to create a new element for an item\r\n * @param updateFn - Function to update an existing element\r\n * @returns The new array of elements\r\n */\r\nexport function applyDiffOperations<T>(\r\n container: Element | ShadowRoot,\r\n elements: Element[],\r\n operations: DiffOperation[],\r\n createFn: (item: T, index: number) => Element,\r\n updateFn: (element: Element, item: T, index: number) => void\r\n): Element[]\r\n{\r\n const newElements = [...elements];\r\n\r\n // Sort operations to ensure correct order:\r\n // 1. Removes (from end to start to preserve indices)\r\n // 2. Updates (in place)\r\n // 3. Inserts (from start to end)\r\n // 4. Moves (handled by insert after remove)\r\n const removes = operations\r\n .filter((op) => op.type === \"remove\")\r\n .sort((a, b) => (b.oldIndex ?? 0) - (a.oldIndex ?? 0));\r\n const updates = operations.filter((op) => op.type === \"update\");\r\n const inserts = operations.filter(\r\n (op) => op.type === \"insert\" || op.type === \"move\"\r\n );\r\n\r\n // Apply removes\r\n for (const op of removes)\r\n {\r\n if (op.oldIndex !== undefined)\r\n {\r\n const element = newElements[op.oldIndex];\r\n if (element)\r\n {\r\n element.remove();\r\n }\r\n newElements.splice(op.oldIndex, 1);\r\n }\r\n }\r\n\r\n // Apply updates\r\n for (const op of updates)\r\n {\r\n if (op.newIndex !== undefined && op.item !== undefined)\r\n {\r\n const element = newElements[op.oldIndex!];\r\n if (element)\r\n {\r\n updateFn(element, op.item as T, op.newIndex);\r\n }\r\n }\r\n }\r\n\r\n // Apply inserts\r\n for (const op of inserts)\r\n {\r\n if (op.newIndex !== undefined && op.item !== undefined)\r\n {\r\n const element = createFn(op.item as T, op.newIndex);\r\n const referenceElement = newElements[op.newIndex];\r\n if (referenceElement)\r\n {\r\n container.insertBefore(element, referenceElement);\r\n } else\r\n {\r\n container.appendChild(element);\r\n }\r\n newElements.splice(op.newIndex, 0, element);\r\n }\r\n }\r\n\r\n return newElements;\r\n}\r\n","/**\r\n * LadrillosJS Directive Processor\r\n *\r\n * Handles all template directives:\r\n * - $for: Loop rendering\r\n * - $if/$else-if/$else: Conditional rendering\r\n * - $show: CSS visibility toggle\r\n * - $bind: Two-way data binding\r\n * - $ref: Element references\r\n */\r\n\r\nimport\r\n{\r\n ConditionalDescriptor,\r\n LoopDescriptor,\r\n TwoWayBindingDescriptor,\r\n} from \"../../types\";\r\nimport\r\n{\r\n BIND_DIRECTIVE,\r\n REF_DIRECTIVE,\r\n DIRECTIVE_PATTERNS,\r\n escapeCssSelector,\r\n syncBindBeforeHandler,\r\n} from \"../../utils/directives\";\r\nimport { scanLazyElements, getPendingLazyContent } from \"../builtins/lazyElement\";\r\nimport { isLoopDelegationEnabled } from \"../configure\";\r\n\r\n// ============================================================================\r\n// Built-in element tag names (uppercase = DOM tagName form)\r\n// ============================================================================\r\n\r\nconst FOR_TAG = \"FOR\";\r\nconst IF_TAG = \"IF\";\r\nconst ELSE_IF_TAG = \"ELSE-IF\";\r\nconst ELSE_TAG = \"ELSE\";\r\nconst SHOW_TAG = \"SHOW\";\r\nimport { EVENT_ATTRIBUTE_SET } from \"../../utils/jsevents\";\r\nimport\r\n{\r\n isEventDirective,\r\n parseEventDirective,\r\n createModifiedHandler,\r\n getListenerOptions,\r\n} from \"../../utils/keyModifiers\";\r\nimport\r\n{\r\n extractFunctionDefinitions,\r\n extractVariableNames,\r\n} from \"../js/scriptParser\";\r\nimport { createEventBusHelpers } from \"../events/eventBus\";\r\nimport\r\n{\r\n createKeyGetter,\r\n getStableIndices,\r\n} from \"../diff/listDiff\";\r\nimport type { BoundEvaluator, DirectiveEvaluator } from \"../js/scriptParser\";\r\nimport { warn, error } from \"../../utils/devWarnings\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\nexport type RefMap = Map<string, HTMLElement>;\r\n\r\nexport type DirectiveContext = {\r\n loops: LoopDescriptor[];\r\n conditionals: ConditionalDescriptor[][];\r\n twoWayBindings: TwoWayBindingDescriptor[];\r\n refs: RefMap;\r\n showElements: ShowDescriptor[];\r\n};\r\n\r\n/**\r\n * Registry for two-way bindings.\r\n * Maps state keys to the elements bound to them.\r\n */\r\nexport type TwoWayBindingRegistry = Map<\r\n string,\r\n Array<{\r\n element: HTMLElement;\r\n path: string[];\r\n isContentEditable?: boolean;\r\n }>\r\n>;\r\n\r\nexport type ShowDescriptor = {\r\n element: HTMLElement;\r\n expression: string;\r\n originalDisplay: string;\r\n};\r\n\r\n// ============================================================================\r\n// Helper Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Strips curly braces from a binding expression.\r\n * e.g., \"{!isLoggedIn}\" -> \"!isLoggedIn\"\r\n * \"isLoggedIn\" -> \"isLoggedIn\" (no change if no braces)\r\n */\r\nfunction stripBindingBraces(expression: string): string\r\n{\r\n const trimmed = expression.trim();\r\n if (trimmed.startsWith(\"{\") && trimmed.endsWith(\"}\"))\r\n {\r\n return trimmed.slice(1, -1).trim();\r\n }\r\n return trimmed;\r\n}\r\n\r\n// ============================================================================\r\n// Main Directive Scanner\r\n// ============================================================================\r\n\r\n/**\r\n * Scans the template for all directives and returns descriptors for each.\r\n * This should be called after the template HTML is injected into the DOM.\r\n */\r\nexport function scanDirectives(\r\n host: HTMLElement | ShadowRoot,\r\n): DirectiveContext\r\n{\r\n const context: DirectiveContext = {\r\n loops: [],\r\n conditionals: [],\r\n twoWayBindings: [],\r\n refs: new Map(),\r\n showElements: [],\r\n };\r\n\r\n // <lazy> is preprocessed in `loadTemplate` so its children sit in a detached\r\n // DocumentFragment (no premature connectedCallback for inner custom\r\n // elements). Each pending fragment is reachable via the sentinel left\r\n // behind in `host`. We run every directive scanner on `host` AND on each\r\n // pending lazy fragment so refs, $for, $if, $show, $bind, etc. work\r\n // exactly the same inside `<lazy>` as outside. Wiring is preserved when\r\n // reveal moves the fragment's nodes into the host tree.\r\n //\r\n // Order matters per root:\r\n // 1. refs – needed first so scripts can read $refs\r\n // 2. for – extracts loop templates so other scanners ignore them\r\n // 3. show – CSS visibility toggles\r\n // 4. bind – two-way bindings on form elements\r\n // 5. if/else-if/else – reactive conditionals (LAST: detaches subtrees,\r\n // so other scanners must run while bodies are live)\r\n const roots: Array<HTMLElement | ShadowRoot | DocumentFragment> = [\r\n host,\r\n ...getPendingLazyContent(host),\r\n ];\r\n for (const root of roots)\r\n {\r\n scanRefs(root, context);\r\n scanLoops(root, context);\r\n scanShow(root, context);\r\n scanTwoWayBindings(root, context);\r\n scanConditionals(root, context);\r\n }\r\n // Process any remaining <lazy> elements (e.g. nested ones revealed during\r\n // scanning). In practice this is a no-op for the common case because\r\n // loadTemplate already preprocessed top-level <lazy>.\r\n scanLazyElements(host);\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Scans the template for all directives and returns descriptors for each.\r\n * This version accepts an existing refs Map to populate (used when refs\r\n * need to be available before scripts run).\r\n */\r\nexport function scanDirectivesWithRefs(\r\n host: HTMLElement | ShadowRoot,\r\n existingRefs: RefMap,\r\n): DirectiveContext\r\n{\r\n const context: DirectiveContext = {\r\n loops: [],\r\n conditionals: [],\r\n twoWayBindings: [],\r\n refs: existingRefs,\r\n showElements: [],\r\n };\r\n\r\n const roots: Array<HTMLElement | ShadowRoot | DocumentFragment> = [\r\n host,\r\n ...getPendingLazyContent(host),\r\n ];\r\n for (const root of roots)\r\n {\r\n scanRefs(root, context);\r\n scanLoops(root, context);\r\n scanShow(root, context);\r\n scanTwoWayBindings(root, context);\r\n scanConditionals(root, context);\r\n }\r\n scanLazyElements(host);\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Scans for $ref directives only and populates the refs Map.\r\n * This can be called early (before scripts run) to make refs available.\r\n */\r\nexport function scanRefsOnly(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n refs: RefMap,\r\n): void\r\n{\r\n const elements = Array.from(\r\n host.querySelectorAll(`[${escapeCssSelector(REF_DIRECTIVE)}]`),\r\n );\r\n\r\n for (const element of elements)\r\n {\r\n const refName = element.getAttribute(REF_DIRECTIVE);\r\n if (refName)\r\n {\r\n refs.set(refName, element as HTMLElement);\r\n // Note: Don't remove the attribute here - let scanDirectives do it later\r\n // so that we don't break the directive scanning flow\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// $ref Directive\r\n// ============================================================================\r\n\r\n/**\r\n * Scans for $ref directives and creates element references.\r\n *\r\n * Usage: <input $ref=\"inputElement\">\r\n * Access: $refs.inputElement (preferred) or $refs.get('inputElement')\r\n */\r\nfunction scanRefs(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n context: DirectiveContext,\r\n): void\r\n{\r\n const elements = Array.from(\r\n host.querySelectorAll(`[${escapeCssSelector(REF_DIRECTIVE)}]`),\r\n );\r\n\r\n for (const element of elements)\r\n {\r\n const refName = element.getAttribute(REF_DIRECTIVE);\r\n if (refName)\r\n {\r\n context.refs.set(refName, element as HTMLElement);\r\n // Remove the directive attribute from DOM\r\n element.removeAttribute(REF_DIRECTIVE);\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// <for> Built-in Element\r\n// ============================================================================\r\n\r\n/**\r\n * Scans for <for> elements and creates loop descriptors.\r\n *\r\n * Syntax:\r\n * <for each=\"item in items\">…</for>\r\n * <for each=\"(item, index) in items\" key=\"item.id\">…</for>\r\n * <for each=\"(value, key, index) in object\" track-by=\"value.id\">…</for>\r\n *\r\n * The element body is the per-iteration template. Multiple top-level\r\n * children are supported; they are wrapped in a single <span style=\r\n * \"display:contents\"> so the loop machinery can treat them as one root.\r\n */\r\nfunction scanLoops(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n context: DirectiveContext,\r\n): void\r\n{\r\n // Outermost-first: snapshot live, but skip nested <for> inside another <for>\r\n // (those are processed when the outer loop renders an iteration).\r\n const elements = Array.from(host.querySelectorAll(\"for\"));\r\n\r\n for (const element of elements)\r\n {\r\n if (!element.parentNode) continue; // already extracted by an outer pass\r\n if (hasForAncestor(element)) continue;\r\n\r\n const expression =\r\n element.getAttribute(\"each\") || element.getAttribute(\"of\") || \"\";\r\n if (!expression)\r\n {\r\n warn(`<for> requires an \"each\" attribute, e.g. <for each=\"item in items\">.`);\r\n continue;\r\n }\r\n\r\n let parsed = parseForExpression(expression);\r\n if (!parsed)\r\n {\r\n warn(`Invalid <for each=\"…\"> expression: \"${expression}\"`);\r\n continue;\r\n }\r\n\r\n // key=\"…\" or track-by=\"…\" override anything in the each expression.\r\n const keyAttr =\r\n element.getAttribute(\"key\") ||\r\n element.getAttribute(\"track-by\") ||\r\n parsed.key;\r\n\r\n // Build the per-iteration template root.\r\n const template = buildLoopTemplate(element);\r\n if (!template)\r\n {\r\n warn(`<for each=\"${expression}\"> has no content to render.`);\r\n continue;\r\n }\r\n\r\n const placeholder = document.createComment(` <for> ${expression} `);\r\n const parent = element.parentElement || host;\r\n parent.insertBefore(placeholder, element);\r\n element.remove();\r\n\r\n const descriptor: LoopDescriptor = {\r\n template,\r\n expression,\r\n itemName: parsed.item,\r\n indexName: parsed.index,\r\n arrayName: parsed.array,\r\n keyAttribute: keyAttr,\r\n placeholder,\r\n renderedElements: [],\r\n originalParent: parent as Element | ShadowRoot,\r\n // Detected once here so renderLoop can skip the per-row conditional\r\n // walk (a querySelectorAll on every clone) for conditional-free\r\n // templates. resolveLoopConditionals never matches a root-level <if>\r\n // (querySelectorAll excludes the root), so querySelector parity holds.\r\n hasConditionals: template.querySelector(IF_TAG) !== null,\r\n };\r\n\r\n context.loops.push(descriptor);\r\n }\r\n}\r\n\r\n/**\r\n * Build the per-iteration template element from a <for>'s contents.\r\n * - Single element child → that child (fastest, zero overhead).\r\n * - Otherwise → wrap children in <span style=\"display:contents\">.\r\n */\r\nfunction buildLoopTemplate(forEl: Element): Element | null\r\n{\r\n // Collect non-whitespace nodes.\r\n const significant: Node[] = [];\r\n for (const n of Array.from(forEl.childNodes))\r\n {\r\n if (n.nodeType === Node.TEXT_NODE && !n.textContent?.trim()) continue;\r\n significant.push(n);\r\n }\r\n if (significant.length === 0) return null;\r\n\r\n if (\r\n significant.length === 1 &&\r\n significant[0].nodeType === Node.ELEMENT_NODE\r\n )\r\n {\r\n return significant[0] as Element;\r\n }\r\n\r\n // Multi-child or text+element: wrap in a transparent span.\r\n const wrap = document.createElement(\"span\");\r\n wrap.style.display = \"contents\";\r\n for (const n of Array.from(forEl.childNodes))\r\n {\r\n wrap.appendChild(n);\r\n }\r\n return wrap;\r\n}\r\n\r\n/** Walk up the tree checking for an ancestor <for>. */\r\nfunction hasForAncestor(el: Element): boolean\r\n{\r\n let p: Element | null = el.parentElement;\r\n while (p)\r\n {\r\n if (p.tagName === FOR_TAG) return true;\r\n p = p.parentElement;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Parses a $for expression into its components.\r\n *\r\n * Examples:\r\n * \"item in items\" → { item: \"item\", array: \"items\" }\r\n * \"(item, index) in items\" → { item: \"item\", index: \"index\", array: \"items\" }\r\n * \"{ id, name } in users\" → { item: \"{ id, name }\", array: \"users\" }\r\n */\r\nfunction parseForExpression(expression: string):\r\n {\r\n item: string;\r\n index?: string;\r\n key?: string;\r\n array: string;\r\n } | null\r\n{\r\n const match = expression.match(DIRECTIVE_PATTERNS.forAlias);\r\n if (!match) return null;\r\n\r\n let [, lhs, rhs] = match;\r\n lhs = lhs.trim();\r\n rhs = rhs.trim();\r\n\r\n // Extract key if present: \"item in items track by item.id\"\r\n let key: string | undefined;\r\n const trackMatch = rhs.match(/\\s+track\\s+by\\s+(.+)$/i);\r\n if (trackMatch)\r\n {\r\n key = trackMatch[1].trim();\r\n rhs = rhs.slice(0, trackMatch.index).trim();\r\n }\r\n\r\n // Strip parentheses: \"(item, index)\" → \"item, index\"\r\n const stripped = lhs.replace(DIRECTIVE_PATTERNS.stripParens, \"\").trim();\r\n\r\n // Check for index: \"item, index\"\r\n const iteratorMatch = stripped.match(DIRECTIVE_PATTERNS.forIterator);\r\n\r\n let item: string;\r\n let index: string | undefined;\r\n let thirdParam: string | undefined;\r\n\r\n if (iteratorMatch)\r\n {\r\n // Has comma-separated values\r\n item = stripped.replace(DIRECTIVE_PATTERNS.forIterator, \"\").trim();\r\n index = iteratorMatch[1]?.trim();\r\n thirdParam = iteratorMatch[2]?.trim();\r\n } else\r\n {\r\n item = stripped;\r\n }\r\n\r\n return {\r\n item,\r\n index: index || thirdParam, // Support both (item, index) and (value, key, index)\r\n key,\r\n array: rhs,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// <if> / <else-if> / <else> Built-in Elements\r\n// ============================================================================\r\n\r\n/**\r\n * Scans for <if>/<else-if>/<else> chains.\r\n *\r\n * A chain is:\r\n * <if condition=\"…\">…</if>\r\n * <else-if condition=\"…\">…</else-if> (zero or more, immediate siblings)\r\n * <else>…</else> (optional, must be last)\r\n *\r\n * The elements themselves are used as the conditional descriptor's `element`,\r\n * with `display: contents` so they don't introduce a visual wrapper.\r\n */\r\nfunction scanConditionals(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n context: DirectiveContext,\r\n): void\r\n{\r\n const ifElements = Array.from(host.querySelectorAll(\"if\"));\r\n\r\n for (const ifElement of ifElements)\r\n {\r\n // NOTE: Do NOT skip on `!isConnected`. When an outer <if> is processed\r\n // first in this same loop, it gets detached from the host tree along\r\n // with its nested <if>/<else-if>/<else> children. Those nested elements\r\n // are still valid (their parentElement is the detached outer <if>) and\r\n // must be processed so their conditions are wired up. Skipping them\r\n // here leaves them as raw <if> custom elements that always render their\r\n // children regardless of the condition.\r\n if (hasForAncestor(ifElement)) continue;\r\n\r\n const group: ConditionalDescriptor[] = [];\r\n const rawCondition = ifElement.getAttribute(\"condition\") || \"\";\r\n const condition = stripBindingBraces(rawCondition);\r\n\r\n const placeholder = document.createComment(` <if> ${condition} `);\r\n const parent = ifElement.parentElement || host;\r\n const nextSibling = ifElement.nextSibling;\r\n\r\n parent.insertBefore(placeholder, ifElement);\r\n\r\n group.push(\r\n createConditionalDescriptor(\r\n ifElement as Element,\r\n condition,\r\n \"if\",\r\n placeholder,\r\n parent as Element | ShadowRoot,\r\n nextSibling,\r\n ),\r\n );\r\n\r\n // Walk forward through immediate siblings collecting <else-if>/<else>.\r\n let current = ifElement.nextElementSibling;\r\n while (current)\r\n {\r\n const tag = current.tagName;\r\n if (tag === ELSE_IF_TAG)\r\n {\r\n const rawElseIf = current.getAttribute(\"condition\") || \"\";\r\n const elseIfCondition = stripBindingBraces(rawElseIf);\r\n const next = current.nextElementSibling;\r\n group.push(\r\n createConditionalDescriptor(\r\n current,\r\n elseIfCondition,\r\n \"else-if\",\r\n placeholder,\r\n parent as Element | ShadowRoot,\r\n current.nextSibling,\r\n ),\r\n );\r\n current.remove();\r\n current = next;\r\n } else if (tag === ELSE_TAG)\r\n {\r\n group.push(\r\n createConditionalDescriptor(\r\n current,\r\n \"\",\r\n \"else\",\r\n placeholder,\r\n parent as Element | ShadowRoot,\r\n current.nextSibling,\r\n ),\r\n );\r\n current.remove();\r\n break;\r\n } else\r\n {\r\n break;\r\n }\r\n }\r\n\r\n ifElement.remove();\r\n\r\n for (const desc of group)\r\n {\r\n desc.group = group;\r\n }\r\n\r\n context.conditionals.push(group);\r\n }\r\n}\r\n\r\nfunction createConditionalDescriptor(\r\n element: Element,\r\n condition: string,\r\n type: \"if\" | \"else-if\" | \"else\",\r\n placeholder: Comment,\r\n parent: Element | ShadowRoot,\r\n nextSibling: Node | null,\r\n): ConditionalDescriptor\r\n{\r\n // Remove the condition attribute (no longer needed once captured) and apply\r\n // display:contents so the element renders transparently without a wrapper box.\r\n element.removeAttribute(\"condition\");\r\n (element as HTMLElement).style.display = \"contents\";\r\n\r\n return {\r\n element,\r\n condition,\r\n type,\r\n placeholder,\r\n group: [], // filled in by caller\r\n originalParent: parent,\r\n nextSibling,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// <show> Built-in Element\r\n// ============================================================================\r\n\r\n/**\r\n * Scans for <show condition=\"…\">…</show> elements.\r\n * Unlike <if>, <show> keeps the element in the DOM and toggles CSS display.\r\n * The element renders with `display: contents` when shown (no visual wrapper)\r\n * and `display: none` when hidden.\r\n */\r\nfunction scanShow(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n context: DirectiveContext,\r\n): void\r\n{\r\n const elements = Array.from(host.querySelectorAll(\"show\"));\r\n\r\n for (const element of elements)\r\n {\r\n if (!element.parentNode) continue;\r\n if (hasForAncestor(element)) continue;\r\n\r\n const rawExpression = element.getAttribute(\"condition\") || \"\";\r\n const expression = stripBindingBraces(rawExpression);\r\n\r\n const htmlElement = element as HTMLElement;\r\n htmlElement.style.display = \"contents\";\r\n\r\n context.showElements.push({\r\n element: htmlElement,\r\n expression,\r\n // \"contents\" is the visible-state display; updateShowElements will\r\n // restore this when condition becomes truthy.\r\n originalDisplay: \"contents\",\r\n });\r\n\r\n element.removeAttribute(\"condition\");\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// $bind Directive (Two-way Binding)\r\n// ============================================================================\r\n\r\n/**\r\n * Scans for $bind directives on form elements.\r\n * Creates two-way bindings between input values and reactive state.\r\n */\r\nfunction scanTwoWayBindings(\r\n host: HTMLElement | ShadowRoot | DocumentFragment,\r\n context: DirectiveContext,\r\n): void\r\n{\r\n const elements = Array.from(\r\n host.querySelectorAll(`[${escapeCssSelector(BIND_DIRECTIVE)}]`),\r\n );\r\n\r\n for (const element of elements)\r\n {\r\n const expression = element.getAttribute(BIND_DIRECTIVE);\r\n if (!expression) continue;\r\n\r\n // Skip if inside a loop template\r\n if (isInsideUnprocessedLoop(element, context)) continue;\r\n\r\n const path = expression.split(\".\");\r\n const isContentEditable = element.hasAttribute(\"contenteditable\");\r\n\r\n const descriptor: TwoWayBindingDescriptor = {\r\n element: element as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement,\r\n path,\r\n raw: expression,\r\n isContentEditable,\r\n };\r\n\r\n context.twoWayBindings.push(descriptor);\r\n\r\n // Remove directive attribute\r\n element.removeAttribute(BIND_DIRECTIVE);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Checks if an element is inside an unprocessed <for> template.\r\n * Used to skip $bind etc. that live inside loop bodies.\r\n */\r\nfunction isInsideUnprocessedLoop(\r\n element: Element,\r\n _context: DirectiveContext,\r\n): boolean\r\n{\r\n return hasForAncestor(element);\r\n}\r\n\r\n// ============================================================================\r\n// Directive Executors\r\n// ============================================================================\r\n\r\n/**\r\n * Renders all loops with the current state.\r\n */\r\nexport function renderLoops(\r\n loops: LoopDescriptor[],\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): void\r\n{\r\n for (const loop of loops)\r\n {\r\n renderLoop(loop, state, evaluateExpression);\r\n }\r\n}\r\n\r\n/**\r\n * Renders a single loop with keyed diffing for optimal DOM updates.\r\n * Uses LIS-based algorithm to minimize DOM operations.\r\n */\r\nfunction renderLoop(\r\n loop: LoopDescriptor,\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): void\r\n{\r\n // Get the array to iterate over\r\n const arrayValue = evaluateExpression(loop.arrayName, state);\r\n\r\n if (!arrayValue || !isIterable(arrayValue))\r\n {\r\n // Clear all if array is empty/invalid\r\n for (const el of loop.renderedElements)\r\n {\r\n el.remove();\r\n }\r\n loop.renderedElements = [];\r\n loop.previousItems = [];\r\n return;\r\n }\r\n\r\n const newItems = Array.from(arrayValue as Iterable<unknown>);\r\n const oldItems = loop.previousItems || [];\r\n const oldElements = loop.renderedElements;\r\n\r\n // Initialize key getter if not already done (cached for performance)\r\n if (!loop.keyGetter)\r\n {\r\n loop.keyGetter = createKeyGetter(loop.keyAttribute, loop.itemName);\r\n }\r\n\r\n // One reusable context for ALL evaluation this pass — creates and updates\r\n // alike. Handlers never capture it (they close over a small per-row\r\n // context, below), so mutating item/index per element is safe and avoids\r\n // copying the whole component state once per item.\r\n const updateContext = createBaseLoopContext(state);\r\n\r\n // Prime the item/index keys so the pass-scoped fast evaluator captures the\r\n // complete key set (its contract: keys must not change once created —\r\n // values may, and do, change per row below).\r\n updateContext[loop.itemName] = null;\r\n if (loop.indexName) updateContext[loop.indexName] = 0;\r\n\r\n // Static-mode fast evaluator: state slots are filled once, and only the\r\n // item/index slots are refreshed per row (setRow → refresh()). State\r\n // values cannot change mid-pass — no user code runs during a flush.\r\n const volatileKeys = loop.indexName\r\n ? [loop.itemName, loop.indexName]\r\n : [loop.itemName];\r\n const evalOne: BoundEvaluator =\r\n typeof (evaluateExpression as Partial<DirectiveEvaluator>).forContext ===\r\n \"function\"\r\n ? (evaluateExpression as DirectiveEvaluator).forContext(\r\n updateContext,\r\n volatileKeys,\r\n )\r\n : (expr) => evaluateExpression(expr, updateContext);\r\n\r\n // Point the shared context (and the evaluator's volatile slots) at a row.\r\n const setRow = (item: unknown, index: number): void =>\r\n {\r\n updateContext[loop.itemName] = item;\r\n if (loop.indexName) updateContext[loop.indexName] = index;\r\n evalOne.refresh?.();\r\n };\r\n\r\n // Everything handler creation needs that is identical across rows — name\r\n // lists, the generated destructuring prelude, event-bus helpers — built at\r\n // most once per pass, and only if a handler attribute is actually seen.\r\n let handlerSetup: LoopHandlerSetup | null = null;\r\n const getSetup = (): LoopHandlerSetup =>\r\n (handlerSetup ??= createLoopHandlerSetup(\r\n state,\r\n loop.indexName ? [loop.itemName, loop.indexName] : [loop.itemName],\r\n ));\r\n\r\n // Refresh the small per-row context captured by an element's handlers so a\r\n // reused row's handlers read the CURRENT item/index at event time, not the\r\n // values from when the element was first created.\r\n const refreshRowCtx = (el: Element, item: unknown, index: number): void =>\r\n {\r\n const rowCtx = (el as any)[LOOP_ROW_CTX] as\r\n | Record<string, unknown>\r\n | undefined;\r\n if (rowCtx)\r\n {\r\n rowCtx[loop.itemName] = item;\r\n if (loop.indexName) rowCtx[loop.indexName] = index;\r\n }\r\n };\r\n\r\n // Precompiled row-instantiation plan for this template (null when the\r\n // template needs the generic walk — nested <if>/<for>).\r\n const plan = getCreationPlan(loop);\r\n\r\n // Helper to create a new element for an item\r\n const createElement = (item: unknown, index: number): Element =>\r\n {\r\n const clone = loop.template.cloneNode(true) as Element;\r\n setRow(item, index);\r\n // Small per-row context for event handlers: item/index own-properties\r\n // over a pass-shared prototype carrying state functions and markers.\r\n const rowCtx: Record<string, unknown> = Object.create(getSetup().proto);\r\n rowCtx[loop.itemName] = item;\r\n if (loop.indexName) rowCtx[loop.indexName] = index;\r\n (clone as any)[LOOP_ROW_CTX] = rowCtx;\r\n if (plan)\r\n {\r\n applyCreationPlan(clone, plan, evalOne, rowCtx, getSetup, loop);\r\n return clone;\r\n }\r\n // Resolve any <if>/<else-if>/<else> chains nested inside the loop\r\n // template before processing bindings so dead branches are pruned.\r\n // Skipped entirely when scan time proved the template has none.\r\n if (loop.hasConditionals)\r\n {\r\n resolveLoopConditionals(\r\n clone,\r\n updateContext,\r\n evaluateExpression,\r\n evalOne,\r\n );\r\n }\r\n processElementBindings(\r\n clone,\r\n updateContext,\r\n evaluateExpression,\r\n evalOne,\r\n rowCtx,\r\n getSetup,\r\n );\r\n return clone;\r\n };\r\n\r\n // Build the reconciled element list. `source[i]` is the previous index of\r\n // the element now at position i, or -1 for a freshly created one — this\r\n // drives the shared LIS-based move minimization below.\r\n const newElements: Element[] = new Array(newItems.length);\r\n const source: number[] = new Array(newItems.length);\r\n\r\n // Fast path: pairwise-identical items mean no structural change — some\r\n // OTHER state the loop's bindings reference changed (e.g. a selection\r\n // flag). Refresh bindings in place and skip key maps, diffing, and\r\n // placement entirely.\r\n if (\r\n newItems.length === oldItems.length &&\r\n oldElements.length === newItems.length\r\n )\r\n {\r\n let identical = true;\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n if (newItems[i] !== oldItems[i])\r\n {\r\n identical = false;\r\n break;\r\n }\r\n }\r\n if (identical)\r\n {\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n setRow(newItems[i], i);\r\n refreshRowCtx(oldElements[i], newItems[i], i);\r\n updateElementBindings(\r\n oldElements[i],\r\n updateContext,\r\n evaluateExpression,\r\n evalOne,\r\n getSetup,\r\n );\r\n }\r\n loop.previousItems = newItems;\r\n return;\r\n }\r\n }\r\n\r\n if (loop.keyAttribute)\r\n {\r\n // Keyed reconciliation - match elements by key for optimal reuse.\r\n const keyToElement = new Map<unknown, Element>();\r\n const keyToOldIndex = new Map<unknown, number>();\r\n for (let i = 0; i < oldItems.length; i++)\r\n {\r\n const key = loop.keyGetter(oldItems[i], i);\r\n keyToOldIndex.set(key, i);\r\n if (oldElements[i]) keyToElement.set(key, oldElements[i]);\r\n }\r\n\r\n // Remove elements whose key disappeared. A key-set difference is all\r\n // that's needed here — the LIS-based placement below handles moves, so\r\n // running the full diff (which computes move operations nobody reads)\r\n // would be O(n²) wasted work per flush.\r\n const newKeys = new Set<unknown>();\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n newKeys.add(loop.keyGetter(newItems[i], i));\r\n }\r\n for (const [key, el] of keyToElement)\r\n {\r\n if (!newKeys.has(key))\r\n {\r\n el.remove();\r\n keyToElement.delete(key);\r\n }\r\n }\r\n\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n const item = newItems[i];\r\n const key = loop.keyGetter(item, i);\r\n const existingEl = keyToElement.get(key);\r\n if (existingEl)\r\n {\r\n // Reuse existing element - update bindings against the shared context.\r\n setRow(item, i);\r\n refreshRowCtx(existingEl, item, i);\r\n updateElementBindings(\r\n existingEl,\r\n updateContext,\r\n evaluateExpression,\r\n evalOne,\r\n getSetup,\r\n );\r\n newElements[i] = existingEl;\r\n source[i] = keyToOldIndex.get(key) ?? -1;\r\n } else\r\n {\r\n newElements[i] = createElement(item, i);\r\n source[i] = -1;\r\n }\r\n }\r\n } else\r\n {\r\n // Non-keyed reconciliation - reuse elements by position (index identity).\r\n const reuseCount = Math.min(oldItems.length, newItems.length);\r\n for (let i = 0; i < newItems.length; i++)\r\n {\r\n if (i < reuseCount)\r\n {\r\n setRow(newItems[i], i);\r\n refreshRowCtx(oldElements[i], newItems[i], i);\r\n updateElementBindings(\r\n oldElements[i],\r\n updateContext,\r\n evaluateExpression,\r\n evalOne,\r\n getSetup,\r\n );\r\n newElements[i] = oldElements[i];\r\n source[i] = i;\r\n } else\r\n {\r\n newElements[i] = createElement(newItems[i], i);\r\n source[i] = -1;\r\n }\r\n }\r\n // Remove trailing elements that no longer have a matching item.\r\n for (let i = reuseCount; i < oldElements.length; i++)\r\n {\r\n oldElements[i]?.remove();\r\n }\r\n }\r\n\r\n // Place elements in target order, moving only those that are not part of the\r\n // longest stable (increasing) run of reused elements. Elements already in\r\n // correct relative order stay put, so an in-order content update or a plain\r\n // append performs the minimum number of DOM moves.\r\n const stable = getStableIndices(source);\r\n const parent = loop.placeholder.parentNode;\r\n if (parent)\r\n {\r\n let prev: Node = loop.placeholder;\r\n for (let i = 0; i < newElements.length; i++)\r\n {\r\n const el = newElements[i];\r\n if (stable.has(i))\r\n {\r\n // Reused element already in correct relative position — leave it.\r\n prev = el;\r\n } else\r\n {\r\n // New or out-of-order element: move it directly after its predecessor.\r\n if (prev.nextSibling !== el)\r\n {\r\n parent.insertBefore(el, prev.nextSibling);\r\n }\r\n prev = el;\r\n }\r\n }\r\n }\r\n\r\n loop.renderedElements = newElements;\r\n\r\n // Store current items for next diff\r\n loop.previousItems = [...newItems];\r\n}\r\n\r\n/**\r\n * Builds the shared per-pass evaluation context (everything except the\r\n * item/index entries). Spreading the component state is the expensive part,\r\n * so renderLoop builds this ONCE per pass and mutates the item/index keys\r\n * per element — for creates and updates alike — instead of recreating the\r\n * whole object each time. Event handlers never capture this object; they\r\n * get a small per-row context (see createLoopHandlerSetup).\r\n */\r\nfunction createBaseLoopContext(\r\n state: Record<string, unknown>,\r\n): Record<string, unknown>\r\n{\r\n const scriptContentFromState = (state as any).__scriptContent;\r\n return {\r\n ...state,\r\n __reactiveState__: state,\r\n __scriptContent__: scriptContentFromState || \"\",\r\n __componentUrl__: (state as any).__componentUrl || \"\",\r\n };\r\n}\r\n\r\n/**\r\n * A binding template pre-parsed into alternating static text and\r\n * expression segments: the rendered value is\r\n * `statics[0] + eval(exprs[0]) + statics[1] + … + statics[exprs.length]`.\r\n * Parsing once at collection time replaces a regex `.replace` (plus a\r\n * closure allocation) per binding per update with a plain concat loop.\r\n */\r\ntype ParsedBinding = {\r\n statics: string[];\r\n exprs: string[];\r\n /**\r\n * Compiled evaluator Functions aligned with `exprs`, valid only for the\r\n * key-set signature in `fnsSig` (null = compile error, falls back to the\r\n * reporting slow path). Resolved once per template per context shape so\r\n * hot loops skip the per-eval cache lookup — see compiledFnsFor.\r\n */\r\n fns?: (Function | null)[];\r\n fnsSig?: string;\r\n};\r\n\r\n/**\r\n * Parsed templates are shared globally: every row of a 1,000-row loop has\r\n * the same handful of template strings, so parsing is done once per\r\n * distinct template rather than once per node.\r\n */\r\nconst parsedTemplateCache = new Map<string, ParsedBinding>();\r\n\r\n/**\r\n * Returns compiled Functions for every expression in `parsed`, resolving\r\n * them through the bound evaluator once per (template, context shape) and\r\n * reusing them afterwards. A null entry means the expression failed to\r\n * compile; callers fall back to the plain evaluator for it so the original\r\n * per-update error reporting is preserved.\r\n */\r\nfunction compiledFnsFor(\r\n parsed: ParsedBinding,\r\n evalOne: BoundEvaluator,\r\n): (Function | null)[]\r\n{\r\n if (parsed.fnsSig !== evalOne.sig)\r\n {\r\n const fns: (Function | null)[] = new Array(parsed.exprs.length);\r\n for (let i = 0; i < parsed.exprs.length; i++)\r\n {\r\n fns[i] = evalOne.compile!(parsed.exprs[i]);\r\n }\r\n parsed.fns = fns;\r\n parsed.fnsSig = evalOne.sig;\r\n }\r\n return parsed.fns!;\r\n}\r\n\r\nfunction parseBindingTemplate(template: string): ParsedBinding\r\n{\r\n let parsed = parsedTemplateCache.get(template);\r\n if (parsed) return parsed;\r\n\r\n const statics: string[] = [];\r\n const exprs: string[] = [];\r\n const re = /\\{([^}]+)\\}/g;\r\n let last = 0;\r\n let m: RegExpExecArray | null;\r\n while ((m = re.exec(template)))\r\n {\r\n statics.push(template.slice(last, m.index));\r\n exprs.push(m[1].trim());\r\n last = m.index + m[0].length;\r\n }\r\n statics.push(template.slice(last));\r\n\r\n parsed = { statics, exprs };\r\n parsedTemplateCache.set(template, parsed);\r\n return parsed;\r\n}\r\n\r\n/**\r\n * Per-element cache of everything the update path needs to touch: text\r\n * nodes and attributes carrying a `__originalTemplate` (with the template\r\n * pre-parsed into segments), and the comment placeholders of nested <if>\r\n * chains. Collected with TreeWalkers once, then reused on every\r\n * subsequent update — the subtree structure of a reused loop element only\r\n * changes when a conditional branch swaps, and that invalidates the cache\r\n * below.\r\n */\r\ntype LoopBindingCache = {\r\n texts: { node: Text; parsed: ParsedBinding }[];\r\n attrs: { attr: Attr; parsed: ParsedBinding }[];\r\n conds: Comment[];\r\n};\r\n\r\nconst BINDING_CACHE = \"__ladrillosBindingCache\" as const;\r\n\r\n/**\r\n * Per-element key holding the small context its event handlers close over\r\n * ({item, index} own-props over a pass-shared prototype). renderLoop\r\n * refreshes the item/index values whenever the element is reused for a\r\n * different row, so handlers read current data at event time.\r\n */\r\nconst LOOP_ROW_CTX = \"__ladrillosLoopCtx\" as const;\r\n\r\nfunction collectBindingCache(element: Element): LoopBindingCache\r\n{\r\n const texts: LoopBindingCache[\"texts\"] = [];\r\n const attrs: LoopBindingCache[\"attrs\"] = [];\r\n const conds: Comment[] = [];\r\n\r\n const collectAttrs = (el: Element): void =>\r\n {\r\n const list = el.attributes;\r\n for (let i = 0; i < list.length; i++)\r\n {\r\n const template = (list[i] as any).__originalTemplate;\r\n if (template)\r\n {\r\n attrs.push({ attr: list[i], parsed: parseBindingTemplate(template) });\r\n }\r\n }\r\n };\r\n\r\n // A TreeWalker's nextNode does not include the root, so the root's\r\n // attributes are collected explicitly first.\r\n collectAttrs(element);\r\n const walker = document.createTreeWalker(\r\n element,\r\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\r\n );\r\n let node: Node | null;\r\n while ((node = walker.nextNode()))\r\n {\r\n if (node.nodeType === Node.TEXT_NODE)\r\n {\r\n const template = (node as any).__originalTemplate;\r\n if (template)\r\n {\r\n texts.push({\r\n node: node as Text,\r\n parsed: parseBindingTemplate(template),\r\n });\r\n }\r\n } else if (node.nodeType === Node.ELEMENT_NODE)\r\n {\r\n collectAttrs(node as Element);\r\n } else if ((node as any)[LOOP_COND_META])\r\n {\r\n conds.push(node as Comment);\r\n }\r\n }\r\n\r\n return { texts, attrs, conds };\r\n}\r\n\r\n// ============================================================================\r\n// Loop creation plan — per-template precompiled row instantiation\r\n// ============================================================================\r\n//\r\n// For loop templates without <if> chains or nested <for> elements, every\r\n// row's subtree structure is identical to the template's, so the location of\r\n// each bound text node, bound attribute, and handler attribute can be\r\n// recorded ONCE as a child-index path from the root. Creating a row then\r\n// costs cloneNode plus direct navigation to exactly the nodes that need\r\n// work — no TreeWalker over the whole subtree, no per-node attribute\r\n// scanning, and all templates/handler code pre-parsed. This is computed\r\n// lazily at first render (no build step) and is invisible to callers: the\r\n// applied result — evaluated bindings, listeners, seeded binding cache — is\r\n// identical to what the generic processElementBindings walk produces.\r\n\r\ntype PlanTextEntry = { path: number[]; parsed: ParsedBinding };\r\ntype PlanAttrEntry = { path: number[]; name: string; parsed: ParsedBinding };\r\ntype PlanHandlerEntry = {\r\n path: number[];\r\n /** Attribute to strip from the clone. */\r\n attrName: string;\r\n /** DOM event name to listen for. */\r\n eventName: string;\r\n /** Handler source with {expr} bindings already rewritten. */\r\n code: string;\r\n /** Modifier info for $on: directives (null for plain onXXX handlers). */\r\n directive: NonNullable<ReturnType<typeof parseEventDirective>> | null;\r\n options?: ReturnType<typeof getListenerOptions>;\r\n};\r\n\r\n/**\r\n * A group of delegated handler entries sharing one element (path). `stamp`\r\n * is the immutable marker object written onto every row's element at that\r\n * path — shared across rows, so stamping costs one property write.\r\n */\r\ntype PlanDelegatedGroup = {\r\n path: number[];\r\n entries: PlanHandlerEntry[];\r\n stamp: { owner: LoopDescriptor; entries: PlanHandlerEntry[] };\r\n};\r\n\r\ntype LoopCreationPlan = {\r\n texts: PlanTextEntry[];\r\n attrs: PlanAttrEntry[];\r\n /** Handlers attached per element (delegation off or ineligible). */\r\n handlers: PlanHandlerEntry[];\r\n /** Handlers served by one container listener per event type (or null). */\r\n delegated: PlanDelegatedGroup[] | null;\r\n /** Distinct event types needing a container listener. */\r\n delegatedEvents: string[];\r\n};\r\n\r\n// ============================================================================\r\n// Opt-in event delegation (configure({ delegateLoopEvents: true }))\r\n// ============================================================================\r\n//\r\n// Instead of one listener per handler per row (2,000 addEventListener calls\r\n// and closures for a 1,000-row list with two handlers), eligible handlers\r\n// share ONE listener per event type on the loop's container. Rows carry two\r\n// expando stamps: the handler element points at its plan entries, the row\r\n// root already carries the per-row context. On an event, the dispatcher\r\n// walks target → container collecting this loop's matched entries\r\n// (inner-to-outer, mimicking bubble order), resolves the row context at the\r\n// row root, and invokes — honoring stopPropagation between handlers via\r\n// event.cancelBubble.\r\n//\r\n// Eligibility: the event must bubble and the handler must not use the\r\n// `.self` (reads currentTarget), `.capture`, `.once`, or `.passive`\r\n// modifiers; ineligible handlers keep per-element listeners transparently.\r\n\r\n/** Events that bubble (and are worth delegating). */\r\nconst DELEGATABLE_EVENTS = new Set([\r\n \"click\",\r\n \"dblclick\",\r\n \"auxclick\",\r\n \"contextmenu\",\r\n \"mousedown\",\r\n \"mouseup\",\r\n \"mousemove\",\r\n \"mouseover\",\r\n \"mouseout\",\r\n \"pointerdown\",\r\n \"pointerup\",\r\n \"pointermove\",\r\n \"pointerover\",\r\n \"pointerout\",\r\n \"pointercancel\",\r\n \"touchstart\",\r\n \"touchend\",\r\n \"touchmove\",\r\n \"touchcancel\",\r\n \"keydown\",\r\n \"keyup\",\r\n \"keypress\",\r\n \"input\",\r\n \"beforeinput\",\r\n \"change\",\r\n \"submit\",\r\n \"reset\",\r\n \"focusin\",\r\n \"focusout\",\r\n \"wheel\",\r\n \"dragstart\",\r\n \"drag\",\r\n \"dragend\",\r\n \"dragenter\",\r\n \"dragover\",\r\n \"dragleave\",\r\n \"drop\",\r\n \"cut\",\r\n \"copy\",\r\n \"paste\",\r\n]);\r\n\r\n/** Stamp on a handler element inside a delegated row (shared per plan group). */\r\nconst DELEGATED_KEY = \"__ladrillosDelegated\" as const;\r\n\r\n/** Stamp on a delegated row's root marking which loop owns it. */\r\nconst LOOP_ROW_OWNER = \"__ladrillosLoopOwner\" as const;\r\n\r\nfunction isDelegatableHandler(\r\n eventName: string,\r\n directive: PlanHandlerEntry[\"directive\"],\r\n): boolean\r\n{\r\n if (!DELEGATABLE_EVENTS.has(eventName)) return false;\r\n if (directive)\r\n {\r\n const mods = directive.eventModifiers;\r\n if (\r\n mods.includes(\"self\") ||\r\n mods.includes(\"capture\") ||\r\n mods.includes(\"once\") ||\r\n mods.includes(\"passive\")\r\n )\r\n {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\ntype DelegationState = {\r\n container: Node;\r\n /** Latest handler setup — refreshed each render pass. */\r\n setup: LoopHandlerSetup;\r\n /** Event types that already have a container listener. */\r\n events: Set<string>;\r\n};\r\n\r\nconst delegationStates = new WeakMap<LoopDescriptor, DelegationState>();\r\n\r\n/**\r\n * Attaches (once per loop per event type) the shared container listeners\r\n * and keeps the dispatch setup current.\r\n */\r\nfunction ensureDelegation(\r\n loop: LoopDescriptor,\r\n setup: LoopHandlerSetup,\r\n events: readonly string[],\r\n): void\r\n{\r\n let state = delegationStates.get(loop);\r\n if (!state)\r\n {\r\n const container = (loop.placeholder.parentNode ??\r\n loop.originalParent) as Node;\r\n state = { container, setup, events: new Set() };\r\n delegationStates.set(loop, state);\r\n }\r\n state.setup = setup;\r\n for (const type of events)\r\n {\r\n if (!state.events.has(type))\r\n {\r\n state.events.add(type);\r\n const captured = state;\r\n state.container.addEventListener(type, (event: Event) =>\r\n dispatchDelegated(event, loop, captured),\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Shared container listener body: walk target → container collecting this\r\n * loop's stamped handler elements (inner-to-outer), resolve the row context\r\n * at the row root, then invoke in bubble order. `event.cancelBubble` (set\r\n * by stopPropagation, including the `.stop` modifier) stops the remaining\r\n * handlers exactly as it would stop real bubbling between per-element\r\n * listeners.\r\n */\r\nfunction dispatchDelegated(\r\n event: Event,\r\n loop: LoopDescriptor,\r\n state: DelegationState,\r\n): void\r\n{\r\n const container = state.container;\r\n const matched: PlanHandlerEntry[][] = [];\r\n let rowCtx: Record<string, unknown> | null = null;\r\n\r\n let node: Node | null = event.target as Node | null;\r\n while (node && node !== container)\r\n {\r\n const stamp = (node as any)[DELEGATED_KEY] as\r\n | { owner: LoopDescriptor; entries: PlanHandlerEntry[] }\r\n | undefined;\r\n if (stamp && stamp.owner === loop)\r\n {\r\n matched.push(stamp.entries);\r\n }\r\n if ((node as any)[LOOP_ROW_OWNER] === loop)\r\n {\r\n rowCtx =\r\n ((node as any)[LOOP_ROW_CTX] as Record<string, unknown>) ?? null;\r\n break; // row roots are direct children of the container\r\n }\r\n node = node.parentNode;\r\n }\r\n if (rowCtx === null || matched.length === 0) return;\r\n\r\n for (const entries of matched)\r\n {\r\n for (const h of entries)\r\n {\r\n if (h.eventName !== event.type) continue;\r\n runDelegatedHandler(h, event, rowCtx, state.setup);\r\n if (event.cancelBubble) return;\r\n }\r\n }\r\n}\r\n\r\nfunction runDelegatedHandler(\r\n h: PlanHandlerEntry,\r\n event: Event,\r\n rowCtx: Record<string, unknown>,\r\n setup: LoopHandlerSetup,\r\n): void\r\n{\r\n const fn = getLoopHandlerFn(h.code, setup);\r\n if (!fn) return;\r\n\r\n const run = (ev: Event): void =>\r\n {\r\n try\r\n {\r\n // If the element also has $bind for this event, sync its value into\r\n // state first so the handler reads the current value, not the previous\r\n syncBindBeforeHandler(ev);\r\n\r\n fn(ev, rowCtx, setup.reactiveState, setup.emit, setup.listen);\r\n } catch (e)\r\n {\r\n error(`Error in loop event handler: ${h.code}`, null, e);\r\n }\r\n };\r\n\r\n if (h.directive)\r\n {\r\n createModifiedHandler(run, h.directive)(event);\r\n } else\r\n {\r\n run(event);\r\n }\r\n}\r\n\r\n/** Plan per loop descriptor; null marks a template the plan can't cover. */\r\nconst creationPlans = new WeakMap<LoopDescriptor, LoopCreationPlan | null>();\r\n\r\nfunction getCreationPlan(loop: LoopDescriptor): LoopCreationPlan | null\r\n{\r\n let plan = creationPlans.get(loop);\r\n if (plan === undefined)\r\n {\r\n plan = buildCreationPlan(loop);\r\n creationPlans.set(loop, plan);\r\n }\r\n return plan;\r\n}\r\n\r\nfunction buildCreationPlan(loop: LoopDescriptor): LoopCreationPlan | null\r\n{\r\n // Conditionals change the subtree per row, and nested <for> subtrees rely\r\n // on the generic walk's semantics — fall back for both.\r\n if (loop.hasConditionals) return null;\r\n if (loop.template.querySelector(FOR_TAG) !== null) return null;\r\n\r\n const texts: PlanTextEntry[] = [];\r\n const attrs: PlanAttrEntry[] = [];\r\n const handlers: PlanHandlerEntry[] = [];\r\n const path: number[] = [];\r\n\r\n const visit = (node: Node): void =>\r\n {\r\n if (node.nodeType === Node.ELEMENT_NODE)\r\n {\r\n const list = (node as Element).attributes;\r\n for (let i = 0; i < list.length; i++)\r\n {\r\n const attr = list[i];\r\n if (EVENT_ATTRIBUTE_SET.has(attr.name))\r\n {\r\n handlers.push({\r\n path: path.slice(),\r\n attrName: attr.name,\r\n eventName: attr.name.slice(2),\r\n code: bindHandlerExpressions(attr.value),\r\n directive: null,\r\n });\r\n } else if (isEventDirective(attr.name))\r\n {\r\n const parsedDirective = parseEventDirective(attr.name);\r\n if (parsedDirective)\r\n {\r\n handlers.push({\r\n path: path.slice(),\r\n attrName: attr.name,\r\n eventName: parsedDirective.eventName,\r\n code: bindHandlerExpressions(attr.value),\r\n directive: parsedDirective,\r\n options: getListenerOptions(parsedDirective.eventModifiers),\r\n });\r\n }\r\n } else if (attr.value.includes(\"{\"))\r\n {\r\n attrs.push({\r\n path: path.slice(),\r\n name: attr.name,\r\n parsed: parseBindingTemplate(attr.value),\r\n });\r\n }\r\n }\r\n } else if (node.nodeType === Node.TEXT_NODE)\r\n {\r\n const text = node.textContent;\r\n if (text && text.includes(\"{\"))\r\n {\r\n texts.push({ path: path.slice(), parsed: parseBindingTemplate(text) });\r\n }\r\n }\r\n const children = node.childNodes;\r\n for (let i = 0; i < children.length; i++)\r\n {\r\n path.push(i);\r\n visit(children[i]);\r\n path.pop();\r\n }\r\n };\r\n visit(loop.template);\r\n\r\n // Partition handlers between delegation and per-element attachment. The\r\n // flag is read once here (the plan is cached per loop), so set\r\n // delegateLoopEvents before components render.\r\n let direct = handlers;\r\n let delegated: PlanDelegatedGroup[] | null = null;\r\n const delegatedEvents: string[] = [];\r\n if (isLoopDelegationEnabled() && handlers.length > 0)\r\n {\r\n direct = [];\r\n const byPath = new Map<string, PlanDelegatedGroup>();\r\n for (const h of handlers)\r\n {\r\n if (isDelegatableHandler(h.eventName, h.directive))\r\n {\r\n const key = h.path.join(\",\");\r\n let group = byPath.get(key);\r\n if (!group)\r\n {\r\n const entries: PlanHandlerEntry[] = [];\r\n group = { path: h.path, entries, stamp: { owner: loop, entries } };\r\n byPath.set(key, group);\r\n }\r\n group.entries.push(h);\r\n if (!delegatedEvents.includes(h.eventName))\r\n {\r\n delegatedEvents.push(h.eventName);\r\n }\r\n } else\r\n {\r\n direct.push(h);\r\n }\r\n }\r\n if (byPath.size > 0) delegated = [...byPath.values()];\r\n }\r\n\r\n return { texts, attrs, handlers: direct, delegated, delegatedEvents };\r\n}\r\n\r\n/**\r\n * Instantiates one row from a fresh clone using the precomputed plan:\r\n * evaluates each bound text/attribute in place, attaches handlers, and\r\n * seeds the element's binding cache exactly as the generic walk would.\r\n */\r\nfunction applyCreationPlan(\r\n clone: Element,\r\n plan: LoopCreationPlan,\r\n evalOne: BoundEvaluator,\r\n rowCtx: Record<string, unknown>,\r\n getSetup: () => LoopHandlerSetup,\r\n loop: LoopDescriptor,\r\n): void\r\n{\r\n const canInvoke = evalOne.invoke !== undefined && evalOne.sig !== undefined;\r\n\r\n const resolve = (path: number[]): Node =>\r\n {\r\n let node: Node = clone;\r\n for (let i = 0; i < path.length; i++)\r\n {\r\n node = node.childNodes[path[i]];\r\n }\r\n return node;\r\n };\r\n\r\n const cacheTexts: LoopBindingCache[\"texts\"] = new Array(plan.texts.length);\r\n for (let t = 0; t < plan.texts.length; t++)\r\n {\r\n const { path, parsed } = plan.texts[t];\r\n const node = resolve(path) as Text;\r\n (node as any).__originalTemplate = node.textContent;\r\n const { statics, exprs } = parsed;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = statics[0];\r\n for (let j = 0; j < exprs.length; j++)\r\n {\r\n const fn = fns !== null ? fns[j] : null;\r\n const result =\r\n fn !== null ? evalOne.invoke!(fn, exprs[j]) : evalOne(exprs[j]);\r\n next += String(result ?? \"\") + statics[j + 1];\r\n }\r\n node.textContent = next;\r\n cacheTexts[t] = { node, parsed };\r\n }\r\n\r\n const cacheAttrs: LoopBindingCache[\"attrs\"] = new Array(plan.attrs.length);\r\n for (let a = 0; a < plan.attrs.length; a++)\r\n {\r\n const { path, name, parsed } = plan.attrs[a];\r\n const el = resolve(path) as Element;\r\n const attr = el.getAttributeNode(name)!;\r\n (attr as any).__originalTemplate = attr.value;\r\n const { statics, exprs } = parsed;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = statics[0];\r\n for (let j = 0; j < exprs.length; j++)\r\n {\r\n const fn = fns !== null ? fns[j] : null;\r\n const result =\r\n fn !== null ? evalOne.invoke!(fn, exprs[j]) : evalOne(exprs[j]);\r\n next +=\r\n (result !== null && typeof result === \"object\"\r\n ? JSON.stringify(result)\r\n : String(result ?? \"\")) + statics[j + 1];\r\n }\r\n attr.value = next;\r\n cacheAttrs[a] = { attr, parsed };\r\n }\r\n\r\n if (plan.handlers.length > 0 || plan.delegated !== null)\r\n {\r\n const setup = getSetup();\r\n for (const h of plan.handlers)\r\n {\r\n const el = resolve(h.path) as Element;\r\n el.removeAttribute(h.attrName);\r\n const base = createLoopEventHandler(h.code, rowCtx, setup);\r\n if (!base) continue;\r\n if (h.directive)\r\n {\r\n el.addEventListener(\r\n h.eventName,\r\n createModifiedHandler(base, h.directive),\r\n h.options,\r\n );\r\n } else\r\n {\r\n el.addEventListener(h.eventName, base);\r\n }\r\n }\r\n if (plan.delegated !== null)\r\n {\r\n // No listeners on the row at all: stamp the handler elements with\r\n // their (shared) plan entries and mark the row root as this loop's.\r\n // The container listener resolves everything at dispatch time.\r\n (clone as any)[LOOP_ROW_OWNER] = loop;\r\n for (const group of plan.delegated)\r\n {\r\n const el = resolve(group.path) as Element;\r\n for (const h of group.entries)\r\n {\r\n el.removeAttribute(h.attrName);\r\n }\r\n (el as any)[DELEGATED_KEY] = group.stamp;\r\n }\r\n ensureDelegation(loop, setup, plan.delegatedEvents);\r\n }\r\n }\r\n\r\n (clone as any)[BINDING_CACHE] = {\r\n texts: cacheTexts,\r\n attrs: cacheAttrs,\r\n conds: [],\r\n };\r\n}\r\n\r\n/**\r\n * Updates bindings on an existing element (for keyed diffing reuse).\r\n *\r\n * Uses the per-element binding cache instead of re-walking the subtree on\r\n * every update; the cache is (re)built on first use and whenever a nested\r\n * conditional swaps branches (the only structural change possible on a\r\n * reused element). DOM writes are skipped when the computed value matches\r\n * what's already there, so an unchanged row costs only expression evals.\r\n *\r\n * `evalOne` is the pass-scoped fast evaluator bound to `context`; both\r\n * refer to the same state, `evalOne` just skips per-call context setup.\r\n */\r\nfunction updateElementBindings(\r\n element: Element,\r\n context: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n evalOne: BoundEvaluator = (expr) => evaluateExpression(expr, context),\r\n getSetup?: () => LoopHandlerSetup,\r\n): void\r\n{\r\n let cache = (element as any)[BINDING_CACHE] as LoopBindingCache | undefined;\r\n if (!cache)\r\n {\r\n cache = collectBindingCache(element);\r\n (element as any)[BINDING_CACHE] = cache;\r\n }\r\n\r\n // Re-evaluate any <if>/<else-if>/<else> chains nested inside the element\r\n // (loop iteration) so the rendered branch matches the current per-item\r\n // context. A swapped branch changes the subtree, so the cache is rebuilt\r\n // (the freshly rendered branch was already processed with the current\r\n // context, so re-updating its bindings below is an idempotent no-op).\r\n if (\r\n cache.conds.length > 0 &&\r\n updateLoopConditionals(\r\n cache.conds,\r\n context,\r\n evaluateExpression,\r\n evalOne,\r\n ((element as any)[LOOP_ROW_CTX] as Record<string, unknown>) ?? context,\r\n getSetup,\r\n )\r\n )\r\n {\r\n cache = collectBindingCache(element);\r\n (element as any)[BINDING_CACHE] = cache;\r\n }\r\n\r\n // With a full BoundEvaluator, resolve each template's compiled Functions\r\n // once and invoke them directly — no per-eval cache lookup or arg refill.\r\n const canInvoke = evalOne.invoke !== undefined && evalOne.sig !== undefined;\r\n\r\n const texts = cache.texts;\r\n for (let i = 0; i < texts.length; i++)\r\n {\r\n const { node, parsed } = texts[i];\r\n const { statics, exprs } = parsed;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = statics[0];\r\n for (let j = 0; j < exprs.length; j++)\r\n {\r\n const fn = fns !== null ? fns[j] : null;\r\n const result =\r\n fn !== null ? evalOne.invoke!(fn, exprs[j]) : evalOne(exprs[j]);\r\n next += String(result ?? \"\") + statics[j + 1];\r\n }\r\n if (node.textContent !== next) node.textContent = next;\r\n }\r\n\r\n const attrs = cache.attrs;\r\n for (let i = 0; i < attrs.length; i++)\r\n {\r\n const { attr, parsed } = attrs[i];\r\n const { statics, exprs } = parsed;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = statics[0];\r\n for (let j = 0; j < exprs.length; j++)\r\n {\r\n const fn = fns !== null ? fns[j] : null;\r\n const result =\r\n fn !== null ? evalOne.invoke!(fn, exprs[j]) : evalOne(exprs[j]);\r\n next +=\r\n (result !== null && typeof result === \"object\"\r\n ? JSON.stringify(result)\r\n : String(result ?? \"\")) + statics[j + 1];\r\n }\r\n if (attr.value !== next) attr.value = next;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// <if>/<else-if>/<else> support inside <for> loop iterations\r\n// ============================================================================\r\n//\r\n// The top-level `scanConditionals` pass cannot wire up conditionals inside a\r\n// `<for>` template because `scanLoops` extracts loop bodies from the live host\r\n// tree before `scanConditionals` runs. To support conditionals nested in\r\n// loops, we resolve them per-iteration on the cloned template:\r\n//\r\n// - On create: prune dead branches and render the chosen branch.\r\n// - On update (keyed/non-keyed reuse): re-evaluate the chain against the\r\n// current item context and swap the rendered branch if it changed.\r\n//\r\n// The branch chain (deep clones of the original `<if>`/`<else-if>`/`<else>`\r\n// elements) is stashed on a comment placeholder so subsequent updates can\r\n// re-render any branch.\r\n\r\nconst LOOP_COND_META = \"__ladrillosLoopCond\" as const;\r\n\r\ntype LoopConditionalBranch = {\r\n type: \"if\" | \"else-if\" | \"else\";\r\n condition: string; // empty string for else\r\n /**\r\n * A `<template>` whose `.content` holds a deep-clone of the branch's\r\n * original children. We use a `<template>` (rather than the original\r\n * `<if>`/`<else>` element) so the branch tag never re-appears in the\r\n * live DOM — otherwise `resolveLoopConditionals`' tag-based scan would\r\n * re-discover the rendered branch on its next iteration.\r\n */\r\n template: HTMLTemplateElement;\r\n};\r\n\r\ntype LoopConditionalMeta = {\r\n branches: LoopConditionalBranch[];\r\n currentIndex: number; // -1 when no branch is rendered\r\n currentEl: Element | null;\r\n};\r\n\r\nfunction chooseLoopConditionalBranch(\r\n branches: LoopConditionalBranch[],\r\n evalOne: (expr: string) => unknown,\r\n): number\r\n{\r\n for (let i = 0; i < branches.length; i++)\r\n {\r\n const b = branches[i];\r\n if (b.type === \"else\") return i;\r\n try\r\n {\r\n if (evalOne(b.condition)) return i;\r\n } catch\r\n {\r\n // Treat evaluation errors as false so subsequent branches can match.\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\nfunction renderLoopConditionalBranch(\r\n branch: LoopConditionalBranch,\r\n): Element\r\n{\r\n // Wrap in a transparent `<span style=\"display:contents\">` so the rendered\r\n // branch contributes no layout box and doesn't visually nest its content.\r\n const wrap = document.createElement(\"span\");\r\n wrap.style.display = \"contents\";\r\n wrap.appendChild(branch.template.content.cloneNode(true));\r\n return wrap;\r\n}\r\n\r\n/**\r\n * Build a LoopConditionalBranch from an `<if>`/`<else-if>`/`<else>` element.\r\n * The element's children are moved into a `<template>` so the branch\r\n * tag itself never participates in further scans/renders.\r\n */\r\nfunction buildLoopConditionalBranch(\r\n el: Element,\r\n type: \"if\" | \"else-if\" | \"else\",\r\n): LoopConditionalBranch\r\n{\r\n const tpl = document.createElement(\"template\");\r\n // Use cloneNode on each child so the original element remains intact\r\n // until the caller removes it. This avoids any ambiguity with live\r\n // collections during the surrounding scan loop.\r\n for (const child of Array.from(el.childNodes))\r\n {\r\n tpl.content.appendChild(child.cloneNode(true));\r\n }\r\n const condition =\r\n type === \"else\"\r\n ? \"\"\r\n : stripBindingBraces(el.getAttribute(\"condition\") || \"\");\r\n return { type, condition, template: tpl };\r\n}\r\n\r\n/**\r\n * Walk the cloned loop iteration root, finding `<if>` chains (skipping any\r\n * `<if>` that lives inside a nested `<for>`) and replacing each chain with\r\n * a comment placeholder + the chosen branch (or nothing). Stores the chain\r\n * on the placeholder so future updates can swap branches.\r\n */\r\nfunction resolveLoopConditionals(\r\n root: Element,\r\n context: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n evalOne?: BoundEvaluator,\r\n): void\r\n{\r\n const chooser: (expr: string) => unknown =\r\n evalOne ?? ((expr) => evaluateExpression(expr, context));\r\n // Loop because resolving an outer chain inserts a new branch subtree that\r\n // may itself contain further `<if>` chains we still need to process.\r\n // querySelectorAll returns a static snapshot; re-querying each iteration\r\n // picks up any newly-attached `<if>` nodes.\r\n // Guard against pathological infinite loops just in case.\r\n let safety = 10000;\r\n while (safety-- > 0)\r\n {\r\n let target: Element | null = null;\r\n const candidates = root.querySelectorAll(IF_TAG);\r\n for (let i = 0; i < candidates.length; i++)\r\n {\r\n const candidate = candidates[i];\r\n if (!candidate.parentNode) continue;\r\n if (hasForAncestor(candidate)) continue;\r\n target = candidate;\r\n break;\r\n }\r\n if (!target) return;\r\n\r\n const branches: LoopConditionalBranch[] = [];\r\n branches.push(buildLoopConditionalBranch(target, \"if\"));\r\n\r\n const toRemove: Element[] = [];\r\n let cur = target.nextElementSibling;\r\n while (cur)\r\n {\r\n if (cur.tagName === ELSE_IF_TAG)\r\n {\r\n branches.push(buildLoopConditionalBranch(cur, \"else-if\"));\r\n toRemove.push(cur);\r\n cur = cur.nextElementSibling;\r\n } else if (cur.tagName === ELSE_TAG)\r\n {\r\n branches.push(buildLoopConditionalBranch(cur, \"else\"));\r\n toRemove.push(cur);\r\n break;\r\n } else\r\n {\r\n break;\r\n }\r\n }\r\n\r\n const placeholder = document.createComment(\" <if> (loop) \");\r\n const meta: LoopConditionalMeta = {\r\n branches,\r\n currentIndex: -1,\r\n currentEl: null,\r\n };\r\n (placeholder as any)[LOOP_COND_META] = meta;\r\n\r\n target.parentNode!.insertBefore(placeholder, target);\r\n target.remove();\r\n for (const r of toRemove) r.remove();\r\n\r\n const chosenIdx = chooseLoopConditionalBranch(branches, chooser);\r\n if (chosenIdx >= 0)\r\n {\r\n const rendered = renderLoopConditionalBranch(branches[chosenIdx]);\r\n placeholder.parentNode!.insertBefore(rendered, placeholder.nextSibling);\r\n meta.currentIndex = chosenIdx;\r\n meta.currentEl = rendered;\r\n }\r\n // Continue the while loop; the chosen branch may contain inner <if>\r\n // chains that will now be discovered on the next iteration. Their\r\n // bindings will be processed by the caller's processElementBindings\r\n // pass after resolveLoopConditionals returns.\r\n }\r\n}\r\n\r\n/**\r\n * On reuse, find any loop-conditional placeholders in the subtree and\r\n * re-evaluate them. If the chosen branch is unchanged, do nothing — the\r\n * normal updateElementBindings recursion will refresh bindings inside the\r\n * rendered branch. If it changed, swap in a fresh branch and process it.\r\n *\r\n * `rowCtx` is the per-row handler context of the element being reused, so\r\n * handlers created inside a freshly swapped branch capture THIS row's\r\n * item/index — not the shared pass context that later rows will mutate.\r\n */\r\nfunction updateLoopConditionals(\r\n placeholders: readonly Comment[],\r\n context: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n evalOne: BoundEvaluator,\r\n rowCtx: Record<string, unknown>,\r\n getSetup?: () => LoopHandlerSetup,\r\n): boolean\r\n{\r\n let structureChanged = false;\r\n for (const placeholder of placeholders)\r\n {\r\n const meta = (placeholder as any)[LOOP_COND_META] as LoopConditionalMeta;\r\n const newIdx = chooseLoopConditionalBranch(meta.branches, evalOne);\r\n if (newIdx === meta.currentIndex) continue;\r\n structureChanged = true;\r\n\r\n if (meta.currentEl && meta.currentEl.parentNode)\r\n {\r\n meta.currentEl.remove();\r\n }\r\n meta.currentEl = null;\r\n meta.currentIndex = -1;\r\n\r\n if (newIdx >= 0)\r\n {\r\n const el = renderLoopConditionalBranch(meta.branches[newIdx]);\r\n placeholder.parentNode!.insertBefore(el, placeholder.nextSibling);\r\n meta.currentIndex = newIdx;\r\n meta.currentEl = el;\r\n // Resolve any nested <if> chains and process bindings on the freshly\r\n // rendered subtree using the current per-item context.\r\n resolveLoopConditionals(el, context, evaluateExpression, evalOne);\r\n processElementBindings(\r\n el,\r\n context,\r\n evaluateExpression,\r\n evalOne,\r\n rowCtx,\r\n getSetup,\r\n );\r\n }\r\n }\r\n return structureChanged;\r\n}\r\n\r\n/**\r\n * Processes {bindings} within an element and its children.\r\n * Also transforms inline event handlers (onclick, etc.) to work with component scope.\r\n * Stores original templates for efficient updates during keyed diffing.\r\n *\r\n * Walks the whole subtree in one flat pass (the previous per-child\r\n * recursion re-walked every text node once per ancestor level) and seeds\r\n * the element's binding cache with what it finds, so the first\r\n * updateElementBindings call doesn't need its own collection walk.\r\n */\r\nfunction processElementBindings(\r\n element: Element,\r\n context: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n evalOnePass?: BoundEvaluator,\r\n handlerCtx?: Record<string, unknown>,\r\n getSetupIn?: () => LoopHandlerSetup,\r\n): void\r\n{\r\n const texts: LoopBindingCache[\"texts\"] = [];\r\n const boundAttrs: LoopBindingCache[\"attrs\"] = [];\r\n const conds: Comment[] = [];\r\n\r\n // Pass-scoped fast evaluator: reuse the caller's when provided (renderLoop\r\n // shares one across ALL rows of a pass); otherwise build one bound to this\r\n // context in legacy per-call-refill mode.\r\n const evalOne: BoundEvaluator =\r\n evalOnePass ??\r\n (typeof (evaluateExpression as Partial<DirectiveEvaluator>).forContext ===\r\n \"function\"\r\n ? (evaluateExpression as DirectiveEvaluator).forContext(context)\r\n : (expr) => evaluateExpression(expr, context));\r\n\r\n // Context captured by event handlers. renderLoop passes the small per-row\r\n // object; standalone callers fall back to the evaluation context.\r\n const hCtx = handlerCtx ?? context;\r\n let fallbackSetup: LoopHandlerSetup | null = null;\r\n const getSetup =\r\n getSetupIn ??\r\n ((): LoopHandlerSetup =>\r\n (fallbackSetup ??= createLoopHandlerSetupFromContext(context)));\r\n\r\n // With a full BoundEvaluator, resolve compiled Functions per template once\r\n // (shared across every row of the loop) and invoke them directly.\r\n const canInvoke = evalOne.invoke !== undefined && evalOne.sig !== undefined;\r\n\r\n const evalSegment = (\r\n fns: (Function | null)[] | null,\r\n exprs: string[],\r\n j: number,\r\n ): unknown =>\r\n {\r\n const fn = fns !== null ? fns[j] : null;\r\n return fn !== null ? evalOne.invoke!(fn, exprs[j]) : evalOne(exprs[j]);\r\n };\r\n\r\n const processOne = (el: Element): void =>\r\n {\r\n // Process attributes - first replace bindings, then transform event handlers\r\n for (const attr of Array.from(el.attributes))\r\n {\r\n // Event-handler attributes (onclick, $on:…) are compiled as JavaScript by\r\n // transformLoopEventHandlers. We must NOT string-interpolate per-item data\r\n // into their source here: splicing an untrusted item value straight into\r\n // handler code is a code-injection vector. Their {expr} bindings are turned\r\n // into live, scoped sub-expressions by the handler compiler instead.\r\n if (EVENT_ATTRIBUTE_SET.has(attr.name) || isEventDirective(attr.name))\r\n {\r\n continue;\r\n }\r\n\r\n if (attr.value.includes(\"{\"))\r\n {\r\n // Store original template for keyed diffing reuse\r\n const parsed = parseBindingTemplate(attr.value);\r\n (attr as any).__originalTemplate = attr.value;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = parsed.statics[0];\r\n for (let j = 0; j < parsed.exprs.length; j++)\r\n {\r\n const result = evalSegment(fns, parsed.exprs, j);\r\n // Serialize objects/arrays to JSON so child components can parse\r\n // them. This allows email=\"{item}\" to pass the actual object, not\r\n // \"[object Object]\".\r\n next +=\r\n (result !== null && typeof result === \"object\"\r\n ? JSON.stringify(result)\r\n : String(result ?? \"\")) + parsed.statics[j + 1];\r\n }\r\n attr.value = next;\r\n boundAttrs.push({ attr, parsed });\r\n }\r\n }\r\n\r\n // Transform inline event handlers (onclick, etc.) into proper event listeners.\r\n transformLoopEventHandlers(el, hCtx, getSetup);\r\n };\r\n\r\n processOne(element);\r\n const walker = document.createTreeWalker(\r\n element,\r\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\r\n );\r\n let node: Node | null;\r\n while ((node = walker.nextNode()))\r\n {\r\n if (node.nodeType === Node.TEXT_NODE)\r\n {\r\n const textContent = node.textContent;\r\n if (textContent && textContent.includes(\"{\"))\r\n {\r\n // Store original template for keyed diffing reuse\r\n const parsed = parseBindingTemplate(textContent);\r\n (node as any).__originalTemplate = textContent;\r\n const fns = canInvoke ? compiledFnsFor(parsed, evalOne) : null;\r\n let next = parsed.statics[0];\r\n for (let j = 0; j < parsed.exprs.length; j++)\r\n {\r\n next +=\r\n String(evalSegment(fns, parsed.exprs, j) ?? \"\") +\r\n parsed.statics[j + 1];\r\n }\r\n node.textContent = next;\r\n texts.push({ node: node as Text, parsed });\r\n }\r\n } else if (node.nodeType === Node.ELEMENT_NODE)\r\n {\r\n processOne(node as Element);\r\n } else if ((node as any)[LOOP_COND_META])\r\n {\r\n conds.push(node as Comment);\r\n }\r\n }\r\n\r\n (element as any)[BINDING_CACHE] = { texts, attrs: boundAttrs, conds };\r\n}\r\n\r\n/**\r\n * Rewrites `{expr}` occurrences inside a loop event-handler into live JS\r\n * sub-expressions evaluated in the handler's scope:\r\n *\r\n * onclick=\"removeTodo({todo.id})\" -> removeTodo((todo.id))\r\n *\r\n * The loop variables (item/index) and component state are already in scope when\r\n * the handler runs, so `todo.id` is READ as a value rather than having the\r\n * item's data string-spliced into the handler source. That closes the\r\n * code-injection path that string interpolation opened when list data was\r\n * untrusted. Handlers written with plain expressions — `removeTodo(todo.id)`,\r\n * the form used throughout the docs — need no braces and are unaffected.\r\n */\r\nfunction bindHandlerExpressions(code: string): string\r\n{\r\n return code.replace(/\\{([^}]+)\\}/g, (_, expr) => `(${expr.trim()})`);\r\n}\r\n\r\n/**\r\n * Transforms inline event handlers (onclick, oninput, etc.) on an element\r\n * into proper event listeners with access to component scope.\r\n *\r\n * Also handles $on: event directives with key/event modifiers:\r\n * $on:keyup.enter=\"submit()\"\r\n * $on:click.prevent=\"handleClick()\"\r\n *\r\n * Handler bodies are plain JavaScript with the loop's item/index variables and\r\n * component state in scope: onclick=\"removeTodo(todo.id)\". Any `{expr}` inside a\r\n * handler is turned into a scoped sub-expression (see bindHandlerExpressions),\r\n * never string-interpolated into the source.\r\n *\r\n * `rowCtx` is the small per-row context the handler closes over; `getSetup`\r\n * resolves the pass-shared handler setup lazily so rows without handlers\r\n * never pay for it.\r\n */\r\nfunction transformLoopEventHandlers(\r\n element: Element,\r\n rowCtx: Record<string, unknown>,\r\n getSetup: () => LoopHandlerSetup,\r\n): void\r\n{\r\n // Scan the element's OWN attributes (usually 0–3) for handler names\r\n // rather than probing getAttribute for every known event attribute —\r\n // per-row that turned into tens of thousands of misses on large lists.\r\n const attrs = element.attributes;\r\n let handlerAttrs: { name: string; value: string }[] | null = null;\r\n for (let i = 0; i < attrs.length; i++)\r\n {\r\n const name = attrs[i].name;\r\n if (EVENT_ATTRIBUTE_SET.has(name) || isEventDirective(name))\r\n {\r\n (handlerAttrs ??= []).push({ name, value: attrs[i].value });\r\n }\r\n }\r\n if (!handlerAttrs) return;\r\n\r\n const setup = getSetup();\r\n for (const { name, value } of handlerAttrs)\r\n {\r\n // Process standard inline event handlers (onclick, oninput, etc.)\r\n if (EVENT_ATTRIBUTE_SET.has(name))\r\n {\r\n // Remove the attribute so browser doesn't try to eval it globally\r\n element.removeAttribute(name);\r\n\r\n // onclick → click\r\n const eventName = name.slice(2);\r\n\r\n // Create event listener with component context\r\n const handler = createLoopEventHandler(\r\n bindHandlerExpressions(value),\r\n rowCtx,\r\n setup,\r\n );\r\n if (handler)\r\n {\r\n element.addEventListener(eventName, handler);\r\n }\r\n } else\r\n {\r\n // $on: event directive with modifiers\r\n processLoopEventDirective(element, name, value, rowCtx, setup);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Processes one $on: event directive on a loop-rendered element.\r\n *\r\n * Syntax: $on:event.modifier1.modifier2=\"handler()\"\r\n *\r\n * Examples:\r\n * $on:keyup.enter=\"submit()\"\r\n * $on:click.ctrl.prevent=\"handleClick()\"\r\n */\r\nfunction processLoopEventDirective(\r\n element: Element,\r\n attrName: string,\r\n attrValue: string,\r\n rowCtx: Record<string, unknown>,\r\n setup: LoopHandlerSetup,\r\n): void\r\n{\r\n const parsed = parseEventDirective(attrName);\r\n if (!parsed) return;\r\n\r\n const handlerCode = bindHandlerExpressions(attrValue);\r\n element.removeAttribute(attrName);\r\n\r\n // Create the base event handler with loop context\r\n const baseHandler = createLoopEventHandler(handlerCode, rowCtx, setup);\r\n if (!baseHandler) return;\r\n\r\n // Wrap the handler with modifier checks\r\n const modifiedHandler = createModifiedHandler(baseHandler, parsed);\r\n\r\n // Get listener options (passive, capture, once)\r\n const options = getListenerOptions(parsed.eventModifiers);\r\n\r\n // Add the event listener\r\n element.addEventListener(parsed.eventName, modifiedHandler, options);\r\n}\r\n\r\n/**\r\n * Extracted function definitions per script content. Every row of a loop\r\n * shares one component script, so parsing it once (not once per handler\r\n * per row) is a large win when creating many rows.\r\n */\r\nconst funcDefsCache = new Map<string, string>();\r\n\r\n/**\r\n * Compiled handler functions keyed by their full source body. The body\r\n * embeds the handler code and every destructured name, so body equality\r\n * implies the compiled function is interchangeable — only the runtime\r\n * arguments (context, reactiveState) differ between rows. This collapses\r\n * one `new Function` compile per handler per row into one per distinct\r\n * handler shape.\r\n */\r\nconst loopHandlerFnCache = new Map<string, Function>();\r\nconst MAX_HANDLER_FN_CACHE = 1000;\r\n\r\n/**\r\n * Everything loop event-handler creation needs that is identical across the\r\n * rows of one render pass: the generated destructuring prelude (name lists,\r\n * function definitions, sync-back), the event-bus helpers, the prototype\r\n * for per-row handler contexts, and a per-pass compiled-handler cache.\r\n *\r\n * The old path rebuilt all of this — including a multi-KB function body\r\n * string embedding the component's function definitions — once per handler\r\n * per row, which dominated large list creation.\r\n */\r\ntype LoopHandlerSetup = {\r\n reactiveState: Record<string, unknown>;\r\n /** Prototype for per-row handler contexts: state functions + markers. */\r\n proto: Record<string, unknown>;\r\n /** Function-body text before/after the handler code. */\r\n bodyPrefix: string;\r\n bodySuffix: string;\r\n emit: (eventName: string, data?: unknown) => void;\r\n listen: Function;\r\n /** Compiled handler per code string for this pass (null = failed). */\r\n fnCache: Map<string, Function | null>;\r\n};\r\n\r\n/**\r\n * Builds the pass-shared handler setup from the component state and the\r\n * loop's variable names. Mirrors the name derivation the per-row builder\r\n * used: state entries split into variables (destructured as `let` with\r\n * sync-back) and functions; loop variables destructured as `const` from the\r\n * per-row context, dropping any that a state variable would shadow (the\r\n * state destructure wins, as it did with the old spread-based context).\r\n */\r\nfunction createLoopHandlerSetup(\r\n state: Record<string, unknown>,\r\n loopVarNamesIn: readonly string[],\r\n): LoopHandlerSetup\r\n{\r\n const scriptContent = ((state as any).__scriptContent as string) || \"\";\r\n const hasScriptContent = scriptContent.trim().length > 0;\r\n const hasModuleScripts = (state as any).__hasModuleScripts === true;\r\n\r\n const stateVarNames: string[] = [];\r\n const funcNames: string[] = [];\r\n for (const key of Object.keys(state))\r\n {\r\n if (key.startsWith(\"__\")) continue;\r\n if (typeof state[key] === \"function\") funcNames.push(key);\r\n else stateVarNames.push(key);\r\n }\r\n\r\n const loopVarNames = loopVarNamesIn.filter(\r\n (name) => !stateVarNames.includes(name),\r\n );\r\n // A loop variable shadows a same-named state function in the row context,\r\n // so it must not also appear in the function destructure.\r\n const visibleFuncNames = funcNames.filter(\r\n (name) => !loopVarNamesIn.includes(name),\r\n );\r\n\r\n let funcDefs = \"\";\r\n let destructureFuncs = \"\";\r\n if (hasModuleScripts || !hasScriptContent)\r\n {\r\n // Module-script functions are reactive (or no source is available):\r\n // destructure them from the handler context.\r\n destructureFuncs =\r\n visibleFuncNames.length > 0\r\n ? `const { ${visibleFuncNames.join(\", \")} } = context;`\r\n : \"\";\r\n } else\r\n {\r\n // Regular scripts: re-create functions from script content so they\r\n // work with the local variables that will be synced back to state.\r\n const cached = funcDefsCache.get(scriptContent);\r\n if (cached !== undefined)\r\n {\r\n funcDefs = cached;\r\n } else\r\n {\r\n funcDefs = extractFunctionDefinitions(scriptContent, []);\r\n funcDefsCache.set(scriptContent, funcDefs);\r\n }\r\n }\r\n\r\n const destructureLoopVars =\r\n loopVarNames.length > 0\r\n ? `const { ${loopVarNames.join(\", \")} } = context;`\r\n : \"\";\r\n const destructureStateVars =\r\n stateVarNames.length > 0\r\n ? `let { ${stateVarNames.join(\", \")} } = reactiveState;`\r\n : \"\";\r\n // Sync state variables back after execution (only for regular scripts)\r\n const syncBack =\r\n !hasModuleScripts && stateVarNames.length > 0\r\n ? stateVarNames.map((key) => `reactiveState.${key} = ${key};`).join(\" \")\r\n : \"\";\r\n\r\n const componentId =\r\n ((state as any).__componentId as string) || \"anonymous\";\r\n const eventBusHelpers = createEventBusHelpers(componentId);\r\n\r\n const proto: Record<string, unknown> = {\r\n __reactiveState__: state,\r\n __scriptContent__: scriptContent,\r\n __componentUrl__: (state as any).__componentUrl || \"\",\r\n };\r\n for (const name of funcNames)\r\n {\r\n proto[name] = state[name];\r\n }\r\n\r\n return {\r\n reactiveState: state,\r\n proto,\r\n bodyPrefix: `\"use strict\";\r\n ${destructureLoopVars}\r\n ${destructureStateVars}\r\n ${destructureFuncs}\r\n ${funcDefs}\r\n `,\r\n bodySuffix: `;\r\n ${syncBack}`,\r\n emit: eventBusHelpers.$emit,\r\n listen: eventBusHelpers.$listen,\r\n fnCache: new Map(),\r\n };\r\n}\r\n\r\n/**\r\n * Fallback setup builder for processElementBindings calls that don't come\r\n * from renderLoop (none in the current codebase): derives the loop-variable\r\n * names the way the old per-row builder did — context keys that aren't\r\n * internal markers, functions, or state entries.\r\n */\r\nfunction createLoopHandlerSetupFromContext(\r\n context: Record<string, unknown>,\r\n): LoopHandlerSetup\r\n{\r\n const state =\r\n (context.__reactiveState__ as Record<string, unknown>) ?? context;\r\n const loopVarNames = Object.keys(context).filter(\r\n (key) =>\r\n !key.startsWith(\"__\") &&\r\n typeof context[key] !== \"function\" &&\r\n !Object.prototype.hasOwnProperty.call(state, key),\r\n );\r\n return createLoopHandlerSetup(state, loopVarNames);\r\n}\r\n\r\n/**\r\n * Resolves the compiled handler Function for `code` under `setup`.\r\n * Two cache levels: the per-pass map (code → fn) makes repeat rows a single\r\n * Map hit; the global body-keyed map dedupes compiles across passes and\r\n * components (byte-identical bodies are interchangeable — only the runtime\r\n * arguments differ).\r\n */\r\nfunction getLoopHandlerFn(\r\n code: string,\r\n setup: LoopHandlerSetup,\r\n): Function | null\r\n{\r\n let fn = setup.fnCache.get(code);\r\n if (fn !== undefined) return fn;\r\n\r\n const fnBody = setup.bodyPrefix + code + setup.bodySuffix;\r\n fn = loopHandlerFnCache.get(fnBody) ?? null;\r\n if (fn === null)\r\n {\r\n try\r\n {\r\n if (loopHandlerFnCache.size >= MAX_HANDLER_FN_CACHE)\r\n {\r\n const oldest = loopHandlerFnCache.keys().next().value;\r\n if (oldest !== undefined) loopHandlerFnCache.delete(oldest);\r\n }\r\n fn = new Function(\r\n \"event\",\r\n \"context\",\r\n \"reactiveState\",\r\n \"$emit\",\r\n \"$listen\",\r\n fnBody,\r\n );\r\n loopHandlerFnCache.set(fnBody, fn);\r\n } catch (e)\r\n {\r\n warn(\r\n `Failed to create loop event handler: ${code} — ${(e as Error).message}`,\r\n );\r\n fn = null;\r\n }\r\n }\r\n setup.fnCache.set(code, fn);\r\n return fn;\r\n}\r\n\r\n/**\r\n * Creates an event handler function for a loop-rendered element. The handler\r\n * reads state variables live from the reactive state and the loop variables\r\n * from `rowCtx` — the small per-row context renderLoop keeps refreshed on\r\n * element reuse, so the handler always sees the row's CURRENT item/index.\r\n */\r\nfunction createLoopEventHandler(\r\n code: string,\r\n rowCtx: Record<string, unknown>,\r\n setup: LoopHandlerSetup,\r\n): ((event: Event) => void) | null\r\n{\r\n const fn = getLoopHandlerFn(code, setup);\r\n if (!fn) return null;\r\n\r\n const { reactiveState, emit, listen } = setup;\r\n return (event: Event) =>\r\n {\r\n try\r\n {\r\n // If the element also has $bind for this event, sync its value into\r\n // state first so the handler reads the current value, not the previous\r\n syncBindBeforeHandler(event);\r\n\r\n fn(event, rowCtx, reactiveState, emit, listen);\r\n } catch (e)\r\n {\r\n error(`Error in loop event handler: ${code}`, null, e);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Updates all conditionals with the current state.\r\n */\r\nexport function updateConditionals(\r\n conditionals: ConditionalDescriptor[][],\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): void\r\n{\r\n for (const group of conditionals)\r\n {\r\n updateConditionalGroup(group, state, evaluateExpression);\r\n }\r\n}\r\n\r\n/**\r\n * Updates a single conditional group.\r\n */\r\nfunction updateConditionalGroup(\r\n group: ConditionalDescriptor[],\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): void\r\n{\r\n // Remove all currently visible elements\r\n for (const desc of group)\r\n {\r\n if (desc.element.parentNode)\r\n {\r\n desc.element.remove();\r\n }\r\n }\r\n\r\n // Find the first matching condition\r\n for (const desc of group)\r\n {\r\n let shouldShow = false;\r\n\r\n if (desc.type === \"else\")\r\n {\r\n shouldShow = true; // $else always shows if we reach it\r\n } else\r\n {\r\n const result = evaluateExpression(desc.condition, state);\r\n shouldShow = Boolean(result);\r\n }\r\n\r\n if (shouldShow)\r\n {\r\n // Insert this element after the placeholder\r\n desc.placeholder.parentNode?.insertBefore(\r\n desc.element,\r\n desc.placeholder.nextSibling,\r\n );\r\n break; // Only show the first matching condition\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Updates all $show elements with the current state.\r\n */\r\nexport function updateShowElements(\r\n showElements: ShowDescriptor[],\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): void\r\n{\r\n for (const desc of showElements)\r\n {\r\n const result = evaluateExpression(desc.expression, state);\r\n const shouldShow = Boolean(result);\r\n\r\n desc.element.style.display = shouldShow ? desc.originalDisplay : \"none\";\r\n }\r\n}\r\n\r\n/**\r\n * Sets up two-way bindings and returns a registry for state→input sync.\r\n *\r\n * Returns a function that should be called when state changes to update\r\n * all bound input elements with the new state values.\r\n */\r\nexport function setupTwoWayBindings(\r\n bindings: TwoWayBindingDescriptor[],\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n): (changedKey?: string) => void\r\n{\r\n // Registry mapping state keys to bound elements\r\n const registry: TwoWayBindingRegistry = new Map();\r\n\r\n for (const binding of bindings)\r\n {\r\n setupTwoWayBinding(binding, state, evaluateExpression, registry);\r\n }\r\n\r\n // Return a function that updates all bound inputs when state changes\r\n return (changedKey?: string) =>\r\n {\r\n updateBoundInputs(registry, state, evaluateExpression, changedKey);\r\n };\r\n}\r\n\r\n/**\r\n * Sets up a single two-way binding and registers it for state→input sync.\r\n */\r\nfunction setupTwoWayBinding(\r\n binding: TwoWayBindingDescriptor,\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n registry: TwoWayBindingRegistry,\r\n): void\r\n{\r\n const element = binding.element;\r\n const { raw, path, isContentEditable } = binding;\r\n\r\n // Get initial value from state and set on element\r\n const initialValue = evaluateExpression(raw, state);\r\n setElementValue(element, initialValue, isContentEditable);\r\n\r\n // Register this binding for state→input sync\r\n // The key is the first part of the path (top-level state key)\r\n const stateKey = path[0];\r\n if (!registry.has(stateKey))\r\n {\r\n registry.set(stateKey, []);\r\n }\r\n registry.get(stateKey)!.push({\r\n element: element as HTMLElement,\r\n path,\r\n isContentEditable,\r\n });\r\n\r\n // Also register for the full raw expression (handles nested paths)\r\n if (raw !== stateKey && !registry.has(raw))\r\n {\r\n registry.set(raw, []);\r\n }\r\n if (raw !== stateKey)\r\n {\r\n registry.get(raw)!.push({\r\n element: element as HTMLElement,\r\n path,\r\n isContentEditable,\r\n });\r\n }\r\n\r\n // Determine event type based on element\r\n const eventType = getInputEventType(element);\r\n\r\n // Track if we're currently updating from state to prevent feedback loops\r\n let isUpdatingFromState = false;\r\n\r\n // Store the flag on the element so updateBoundInputs can set it\r\n (element as any).__isUpdatingFromState = () => isUpdatingFromState;\r\n (element as any).__setUpdatingFromState = (val: boolean) =>\r\n {\r\n isUpdatingFromState = val;\r\n };\r\n\r\n // Sync input value → state. Also exposed on the element so inline event\r\n // handlers for the same event (e.g. onchange alongside $bind on a select)\r\n // can pull the value into state before user code reads it — inline\r\n // handlers are registered earlier, so without this they'd see the\r\n // previous value. See syncBindBeforeHandler in utils/directives.\r\n const syncToState = (): void =>\r\n {\r\n // Skip if this change was triggered by state→input sync\r\n if (isUpdatingFromState) return;\r\n\r\n const newValue = getElementValue(element, isContentEditable);\r\n setNestedValue(state, path, newValue);\r\n };\r\n (element as any).__ladrillosBindSync = { eventType, sync: syncToState };\r\n\r\n // Listen for changes and update state\r\n element.addEventListener(eventType, syncToState);\r\n}\r\n\r\n/**\r\n * Updates all bound input elements when state changes.\r\n * Called by the reactivity system when a state property is modified.\r\n *\r\n * @param registry - Map of state keys to bound elements\r\n * @param state - Current reactive state\r\n * @param evaluateExpression - Function to evaluate expressions against state\r\n * @param changedKey - The key that changed (optional, updates all if not provided)\r\n */\r\nfunction updateBoundInputs(\r\n registry: TwoWayBindingRegistry,\r\n state: Record<string, unknown>,\r\n evaluateExpression: (\r\n expr: string,\r\n context: Record<string, unknown>,\r\n ) => unknown,\r\n changedKey?: string,\r\n): void\r\n{\r\n // If a specific key changed, only update elements bound to that key\r\n const keysToUpdate = changedKey ? [changedKey] : Array.from(registry.keys());\r\n\r\n for (const key of keysToUpdate)\r\n {\r\n const bindings = registry.get(key);\r\n if (!bindings) continue;\r\n\r\n for (const binding of bindings)\r\n {\r\n const { element, path, isContentEditable } = binding;\r\n\r\n // Get the current value from state\r\n const rawExpression = path.join(\".\");\r\n const currentValue = evaluateExpression(rawExpression, state);\r\n\r\n // Set flag to prevent feedback loop (input event → state update → input update)\r\n const setFlag = (element as any).__setUpdatingFromState;\r\n if (setFlag) setFlag(true);\r\n\r\n // Update the element with the new value\r\n setElementValue(element, currentValue, isContentEditable);\r\n\r\n // Clear the flag after a microtask to ensure the event handler sees it\r\n if (setFlag)\r\n {\r\n queueMicrotask(() => setFlag(false));\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Gets the appropriate event type for an input element.\r\n */\r\nfunction getInputEventType(element: HTMLElement): string\r\n{\r\n if (element instanceof HTMLSelectElement)\r\n {\r\n return \"change\";\r\n }\r\n if (element instanceof HTMLInputElement)\r\n {\r\n const type = element.type.toLowerCase();\r\n if (type === \"checkbox\" || type === \"radio\")\r\n {\r\n return \"change\";\r\n }\r\n }\r\n return \"input\";\r\n}\r\n\r\n/**\r\n * Gets the value from an input element.\r\n */\r\nfunction getElementValue(\r\n element: HTMLElement,\r\n isContentEditable?: boolean,\r\n): unknown\r\n{\r\n if (isContentEditable)\r\n {\r\n return element.textContent || \"\";\r\n }\r\n\r\n if (element instanceof HTMLInputElement)\r\n {\r\n const type = element.type.toLowerCase();\r\n if (type === \"checkbox\")\r\n {\r\n return element.checked;\r\n }\r\n if (type === \"number\" || type === \"range\")\r\n {\r\n return element.valueAsNumber;\r\n }\r\n return element.value;\r\n }\r\n\r\n if (element instanceof HTMLSelectElement)\r\n {\r\n if (element.multiple)\r\n {\r\n return Array.from(element.selectedOptions).map((o) => o.value);\r\n }\r\n return element.value;\r\n }\r\n\r\n if (element instanceof HTMLTextAreaElement)\r\n {\r\n return element.value;\r\n }\r\n\r\n return (element as any).value ?? \"\";\r\n}\r\n\r\n/**\r\n * Sets the value on an input element.\r\n */\r\nfunction setElementValue(\r\n element: HTMLElement,\r\n value: unknown,\r\n isContentEditable?: boolean,\r\n): void\r\n{\r\n if (isContentEditable)\r\n {\r\n element.textContent = String(value ?? \"\");\r\n return;\r\n }\r\n\r\n if (element instanceof HTMLInputElement)\r\n {\r\n const type = element.type.toLowerCase();\r\n if (type === \"checkbox\")\r\n {\r\n element.checked = Boolean(value);\r\n } else\r\n {\r\n element.value = String(value ?? \"\");\r\n }\r\n return;\r\n }\r\n\r\n if (element instanceof HTMLSelectElement)\r\n {\r\n element.value = String(value ?? \"\");\r\n return;\r\n }\r\n\r\n if (element instanceof HTMLTextAreaElement)\r\n {\r\n element.value = String(value ?? \"\");\r\n return;\r\n }\r\n\r\n (element as any).value = value;\r\n}\r\n\r\n/**\r\n * Sets a nested value in an object using a path array.\r\n */\r\nfunction setNestedValue(\r\n obj: Record<string, unknown>,\r\n path: string[],\r\n value: unknown,\r\n): void\r\n{\r\n let current: any = obj;\r\n\r\n for (let i = 0; i < path.length - 1; i++)\r\n {\r\n const key = path[i];\r\n if (!(key in current) || typeof current[key] !== \"object\")\r\n {\r\n current[key] = {};\r\n }\r\n current = current[key];\r\n }\r\n\r\n current[path[path.length - 1]] = value;\r\n}\r\n\r\n/**\r\n * Checks if a value is iterable.\r\n */\r\nfunction isIterable(value: unknown): boolean\r\n{\r\n return (\r\n value !== null &&\r\n value !== undefined &&\r\n (Array.isArray(value) ||\r\n typeof (value as any)[Symbol.iterator] === \"function\" ||\r\n typeof value === \"object\")\r\n );\r\n}\r\n","/**\r\n * Batch Update Scheduler\r\n *\r\n * Batches multiple state updates into a single DOM update cycle.\r\n *\r\n * This prevents:\r\n * - Multiple re-renders when setting multiple properties\r\n * - Layout thrashing from interleaved reads/writes\r\n * - Unnecessary work when the same property is updated multiple times\r\n *\r\n * @example\r\n * // Without batching: 3 re-renders\r\n * state.count = 1;\r\n * state.name = \"hello\";\r\n * state.items.push(newItem);\r\n *\r\n * // With batching: 1 re-render\r\n * batch(() => {\r\n * state.count = 1;\r\n * state.name = \"hello\";\r\n * state.items.push(newItem);\r\n * });\r\n */\r\n\r\nimport { error } from \"../../utils/devWarnings\";\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\ntype FlushCallback = () => void;\r\ntype SchedulerJob = FlushCallback & {\r\n id?: number;\r\n pre?: boolean;\r\n active?: boolean;\r\n};\r\n\r\n// ============================================================================\r\n// State\r\n// ============================================================================\r\n\r\n/**\r\n * Queue of pending update jobs\r\n */\r\nconst queue: SchedulerJob[] = [];\r\n\r\n/**\r\n * Set of queued job ids for deduplication\r\n */\r\nconst queuedIds = new Set<number>();\r\n\r\n/**\r\n * Pending promise for the current flush cycle\r\n */\r\nlet currentFlushPromise: Promise<void> | null = null;\r\n\r\n/**\r\n * Whether we're currently flushing the queue\r\n */\r\nlet isFlushing = false;\r\n\r\n/**\r\n * Whether a flush is pending (scheduled but not started)\r\n */\r\nlet isFlushPending = false;\r\n\r\n/**\r\n * Job ID counter for deduplication\r\n */\r\nlet jobIdCounter = 0;\r\n\r\n/**\r\n * Resolved promise for microtask scheduling\r\n */\r\nconst resolvedPromise = Promise.resolve();\r\n\r\n// ============================================================================\r\n// Core Functions\r\n// ============================================================================\r\n\r\n/**\r\n * Schedules a job to run in the next microtask.\r\n * Jobs are deduplicated by id - if the same job is queued multiple times,\r\n * it only runs once.\r\n *\r\n * @param job - The update function to schedule\r\n * @returns The job id for tracking\r\n */\r\nexport function queueJob(job: SchedulerJob): number {\r\n // Assign an id if not present\r\n if (job.id === undefined) {\r\n job.id = ++jobIdCounter;\r\n }\r\n\r\n // Deduplicate - don't queue the same job twice\r\n if (!queuedIds.has(job.id)) {\r\n queuedIds.add(job.id);\r\n queue.push(job);\r\n queueFlush();\r\n }\r\n\r\n return job.id;\r\n}\r\n\r\n/**\r\n * Creates a scheduler job with a stable id for deduplication.\r\n * Use this to ensure the same logical update only runs once per flush.\r\n *\r\n * @param fn - The update function\r\n * @param id - Optional stable id (uses auto-increment if not provided)\r\n * @returns A scheduler job with an id\r\n */\r\nexport function createSchedulerJob(\r\n fn: FlushCallback,\r\n id?: number,\r\n): SchedulerJob {\r\n const job = fn as SchedulerJob;\r\n job.id = id ?? ++jobIdCounter;\r\n job.active = true;\r\n return job;\r\n}\r\n\r\n/**\r\n * Schedules the queue to be flushed in the next microtask.\r\n */\r\nfunction queueFlush(): void {\r\n if (!isFlushing && !isFlushPending) {\r\n isFlushPending = true;\r\n currentFlushPromise = resolvedPromise.then(flushJobs);\r\n }\r\n}\r\n\r\n/**\r\n * Flushes all queued jobs.\r\n */\r\nfunction flushJobs(): void {\r\n isFlushPending = false;\r\n isFlushing = true;\r\n\r\n // Sort by id to ensure parent updates run before children\r\n // (lower ids are typically registered earlier)\r\n queue.sort((a, b) => (a.id ?? 0) - (b.id ?? 0));\r\n\r\n try {\r\n for (const job of queue) {\r\n if (job.active !== false) {\r\n try {\r\n job();\r\n } catch (e) {\r\n error(\"Error in scheduled update\", null, e);\r\n }\r\n }\r\n }\r\n } finally {\r\n // Clear the queue\r\n queue.length = 0;\r\n queuedIds.clear();\r\n isFlushing = false;\r\n currentFlushPromise = null;\r\n }\r\n}\r\n\r\n/**\r\n * Wait for the current flush to complete.\r\n *\r\n * @returns Promise that resolves after the current flush\r\n *\r\n * @example\r\n * state.count = 1;\r\n * await nextTick();\r\n * // DOM is now updated\r\n * console.log(element.textContent);\r\n */\r\nexport function nextTick(): Promise<void> {\r\n return currentFlushPromise ?? resolvedPromise;\r\n}\r\n\r\n/**\r\n * Execute multiple state updates in a single batch.\r\n * All updates within the callback are deferred and\r\n * applied together in one DOM update cycle.\r\n *\r\n * @param fn - Function containing multiple state updates\r\n *\r\n * @example\r\n * batch(() => {\r\n * state.firstName = \"John\";\r\n * state.lastName = \"Doe\";\r\n * state.age = 30;\r\n * });\r\n * // Only one DOM update occurs\r\n */\r\nexport function batch(fn: () => void): void {\r\n // If we're already flushing or there's a pending flush,\r\n // the updates will be batched naturally\r\n fn();\r\n}\r\n\r\n/**\r\n * Force an immediate synchronous flush of all pending updates.\r\n * Use sparingly - async batching is usually preferred.\r\n */\r\nexport function flushSync(): void {\r\n if (currentFlushPromise) {\r\n flushJobs();\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Component Update Scheduler\r\n// ============================================================================\r\n\r\n/**\r\n * Per-component update job registry.\r\n * Maps component IDs to their update jobs for deduplication.\r\n */\r\nconst componentJobs = new Map<string, SchedulerJob>();\r\n\r\n/**\r\n * Schedules a component update with automatic deduplication.\r\n * Multiple calls for the same component in the same tick\r\n * result in only one update.\r\n *\r\n * @param componentId - Unique component identifier\r\n * @param updateFn - The component's update function\r\n */\r\nexport function scheduleComponentUpdate(\r\n componentId: string,\r\n updateFn: () => void,\r\n): void {\r\n let job = componentJobs.get(componentId);\r\n\r\n if (!job) {\r\n job = createSchedulerJob(() => {\r\n updateFn();\r\n });\r\n componentJobs.set(componentId, job);\r\n }\r\n\r\n queueJob(job);\r\n}\r\n\r\n/**\r\n * Removes a component from the scheduler registry.\r\n * Call this in disconnectedCallback to prevent memory leaks.\r\n *\r\n * @param componentId - The component ID to unregister\r\n */\r\nexport function unregisterComponent(componentId: string): void {\r\n const job = componentJobs.get(componentId);\r\n if (job) {\r\n job.active = false;\r\n componentJobs.delete(componentId);\r\n }\r\n}\r\n","import { LadrillosComponent } from \"../../types\";\r\nimport { loadStyles } from \"../css/cssParser/cssParser\";\r\nimport { loadTemplate } from \"../html/htmlparser\";\r\nimport\r\n{\r\n loadScripts,\r\n extractVariableNames,\r\n createExpressionEvaluator,\r\n applyBindingsDeferred,\r\n} from \"../js/scriptParser\";\r\nimport\r\n{\r\n executeModuleScriptsWithReactivity,\r\n cleanupModuleScripts,\r\n loadPlainExternalScripts,\r\n loadExternalStyles,\r\n} from \"../js/moduleExecutor\";\r\nimport { cleanupComponentListeners } from \"../events/eventBus\";\r\nimport\r\n{\r\n scanDirectives,\r\n scanRefsOnly,\r\n scanDirectivesWithRefs,\r\n renderLoops,\r\n updateConditionals,\r\n updateShowElements,\r\n setupTwoWayBindings,\r\n DirectiveContext,\r\n} from \"../directives/directiveProcessor\";\r\nimport { createRefsProxy } from \"../helpers/frameworkHelpers\";\r\nimport { setComponentContext, warn } from \"../../utils/devWarnings\";\r\nimport\r\n{\r\n scheduleComponentUpdate,\r\n unregisterComponent,\r\n} from \"../scheduler/batchScheduler\";\r\n\r\n/**\r\n * Instance member names that live on the component itself (as class fields),\r\n * NOT on the prototype. The prop-accessor machinery below guards against\r\n * shadowing native DOM properties and existing prototype members, but it can't\r\n * see these instance fields via `hasOwnProperty(prototype, name)`.\r\n *\r\n * If a component declares a state variable / template binding with one of these\r\n * names (most commonly `state`), we must NOT generate a prop getter/setter or\r\n * treat it as a typed prop. Doing so shadows the field — e.g. a `state`\r\n * accessor whose getter reads `this.state[name]` calls itself and blows the\r\n * stack (RangeError: Maximum call stack size exceeded). The variable still\r\n * works as ordinary reactive state (accessed as `this.state.<name>`).\r\n */\r\nconst RESERVED_INSTANCE_PROPS = new Set<string>([\r\n \"state\",\r\n \"_root\",\r\n \"_initialized\",\r\n \"_componentId\",\r\n \"_directives\",\r\n \"_evaluator\",\r\n \"_updateBoundInputs\",\r\n \"_pendingProps\",\r\n \"_propsReady\",\r\n]);\r\n\r\n/**\r\n * Creates a Web Component class from a Ladrillos component definition.\r\n *\r\n * This function creates the class but does NOT register it with customElements.\r\n * Use createWebComponent() if you want to both create and register.\r\n *\r\n * Follows the Web Components specification:\r\n * - Proper lifecycle callbacks (connectedCallback, disconnectedCallback, etc.)\r\n * - Observed attributes with attributeChangedCallback\r\n * - Shadow DOM encapsulation (optional)\r\n * - Reactive state that syncs with the DOM\r\n *\r\n * - Attributes from HTML OVERRIDE script variable defaults\r\n * - Script variables serve as DEFAULT values when no attribute is provided\r\n *\r\n * Example:\r\n * <my-counter count=\"5\"></my-counter> <!-- count = 5, not the default -->\r\n * <my-counter></my-counter> <!-- count = 0 (script default) -->\r\n */\r\nexport function createWebComponentClass(\r\n component: LadrillosComponent,\r\n useShadowDOM: boolean,\r\n): typeof HTMLElement\r\n{\r\n const {\r\n tagName,\r\n template,\r\n scripts,\r\n externalScripts,\r\n externalStyles,\r\n styles,\r\n sourcePath,\r\n templateBindings = [],\r\n } = component;\r\n\r\n // Pre-extract variable names from scripts for observedAttributes\r\n // This runs once when the component class is defined\r\n const allScriptContent = scripts.map((s) => s.content).join(\"\\n\");\r\n const declaredVariables = extractVariableNames(allScriptContent);\r\n\r\n // Combine script variables + template binding variables for observed attributes\r\n // This allows {title} in template to auto-bind from title=\"value\" attribute\r\n const allObservedAttributes = [\r\n ...new Set([...declaredVariables, ...templateBindings]),\r\n ];\r\n\r\n class LadrillosWebComponent extends HTMLElement\r\n {\r\n // =========================================================================\r\n // Static Properties (Web Component Spec)\r\n // =========================================================================\r\n\r\n /**\r\n * Attributes to observe for changes.\r\n * Derived from both script variable declarations AND template bindings.\r\n * When these attributes change, attributeChangedCallback is called.\r\n */\r\n static get observedAttributes(): string[]\r\n {\r\n return allObservedAttributes;\r\n }\r\n\r\n // =========================================================================\r\n // Instance Properties\r\n // =========================================================================\r\n\r\n /** Reactive state - changes automatically update the DOM */\r\n state: Record<string, unknown> = {};\r\n\r\n /** Reference to the shadow root or light DOM root */\r\n private _root: HTMLElement | ShadowRoot | null = null;\r\n\r\n /** Flag to track if component has been initialized */\r\n private _initialized: boolean = false;\r\n\r\n /** Unique ID for this component instance (used for module cleanup) */\r\n private _componentId: string = `${tagName}-${Math.random()\r\n .toString(36)\r\n .slice(2)}`;\r\n\r\n /** Directive context for loops, conditionals, etc. */\r\n private _directives: DirectiveContext | null = null;\r\n\r\n /** Expression evaluator function */\r\n private _evaluator:\r\n | ((expr: string, ctx: Record<string, unknown>) => unknown)\r\n | null = null;\r\n\r\n /** Two-way binding updater function - syncs state changes to input elements */\r\n private _updateBoundInputs: ((changedKey?: string) => void) | null = null;\r\n\r\n /**\r\n * Holds prop values assigned as DOM properties (e.g. `el.items = [...]`)\r\n * before the component finished initializing its reactive state. Drained\r\n * into state once `_propsReady` is true. This is what lets complex props\r\n * (arrays/objects/functions) keep their type instead of being stringified\r\n * through an HTML attribute.\r\n */\r\n private _pendingProps: Map<string, unknown> = new Map();\r\n\r\n /** True once reactive state exists and property writes can flow into it. */\r\n private _propsReady: boolean = false;\r\n\r\n // =========================================================================\r\n // Lifecycle Callbacks (Web Component Spec)\r\n // =========================================================================\r\n\r\n constructor()\r\n {\r\n super();\r\n // Don't do DOM work here - wait for connectedCallback\r\n // This follows the custom elements spec best practice\r\n }\r\n\r\n /**\r\n * Called when the element is added to the DOM.\r\n * This is where we do our main initialization.\r\n */\r\n async connectedCallback(): Promise<void>\r\n {\r\n // Prevent double initialization (can happen with some frameworks)\r\n if (this._initialized) return;\r\n this._initialized = true;\r\n\r\n // Set component context for better error messages\r\n // This allows error handlers to know which component is being processed\r\n setComponentContext({\r\n tagName,\r\n sourcePath,\r\n instanceId: this._componentId,\r\n });\r\n\r\n // Preserve original light-DOM children (slotted/projected content) BEFORE\r\n // loadTemplate overwrites innerHTML. Scripts can access this via\r\n // `$host.__originalHTML` (full HTML string) or `$host.__originalChildren`\r\n // (a detached DocumentFragment) to implement slot-like projection.\r\n //\r\n // In shadow-DOM mode the light children are untouched (template goes into\r\n // the shadow root), but we still expose the same API for consistency so\r\n // component authors don't have to branch on rendering mode.\r\n const originalHTML = this.innerHTML;\r\n const originalChildren = document.createDocumentFragment();\r\n if (useShadowDOM)\r\n {\r\n // Shadow DOM: the template renders into the shadow root, so the host's\r\n // light-DOM children MUST stay in place for native <slot> projection to\r\n // work. Clone them into the fragment so the same API is still exposed.\r\n for (const child of Array.from(this.childNodes))\r\n {\r\n originalChildren.appendChild(child.cloneNode(true));\r\n }\r\n }\r\n else\r\n {\r\n // Light DOM: loadTemplate overwrites the host's innerHTML, so move the\r\n // original children out so scripts can re-project them manually.\r\n while (this.firstChild)\r\n {\r\n originalChildren.appendChild(this.firstChild);\r\n }\r\n }\r\n (this as any).__originalHTML = originalHTML;\r\n (this as any).__originalChildren = originalChildren;\r\n\r\n // Create shadow DOM or use light DOM\r\n // If the element was previously connected (e.g. moved through a\r\n // DocumentFragment by <lazy>), it may already have a shadow root.\r\n // attachShadow can only be called once per host, so reuse it.\r\n this._root = useShadowDOM\r\n ? (this.shadowRoot ?? this.attachShadow({ mode: \"open\" }))\r\n : this;\r\n\r\n // Parse template and find bindings\r\n const { bindings } = loadTemplate(this._root, template);\r\n\r\n // Load scoped styles\r\n loadStyles(this._root, styles, useShadowDOM);\r\n\r\n // Collect attribute values to override script defaults\r\n // ATTRIBUTES WIN over script variable defaults\r\n const attributeOverrides = this._getAttributeOverrides();\r\n\r\n // \"Upgrade\" any props that were assigned as DOM properties before the\r\n // element was upgraded/initialized (e.g. `el.items = [...]` set on a raw\r\n // element before its definition loaded). Such assignments create an own\r\n // property that shadows the prototype accessor; move them into the\r\n // pending map so they're treated like any other typed prop.\r\n for (const propName of allObservedAttributes)\r\n {\r\n // Never treat an internal component member (e.g. `state`) as a typed\r\n // prop — capturing/deleting it here would clobber the component's own\r\n // field once state initializes.\r\n if (RESERVED_INSTANCE_PROPS.has(propName)) continue;\r\n\r\n if (Object.prototype.hasOwnProperty.call(this, propName))\r\n {\r\n this._pendingProps.set(propName, (this as any)[propName]);\r\n delete (this as any)[propName];\r\n }\r\n\r\n // HTML lowercases attribute names, so a parent passing a typed prop via\r\n // a camelCase attribute (e.g. postList={...}) actually sets\r\n // `el.postlist`. Capture that lowercase own property and route it to\r\n // the canonical (camelCase) prop name so it lands in state correctly.\r\n const lowerName = propName.toLowerCase();\r\n if (\r\n lowerName !== propName &&\r\n Object.prototype.hasOwnProperty.call(this, lowerName)\r\n )\r\n {\r\n this._pendingProps.set(propName, (this as any)[lowerName]);\r\n delete (this as any)[lowerName];\r\n }\r\n }\r\n\r\n // Typed props passed via the DOM-property channel win over the stringy\r\n // attribute values (they carry the real array/object/function).\r\n for (const [propName, value] of this._pendingProps)\r\n {\r\n attributeOverrides[propName] = value;\r\n }\r\n\r\n // Filter out module scripts - they are handled separately\r\n const regularScripts = scripts.filter((s) => s.type !== \"module\");\r\n const hasModuleScripts = scripts.some((s) => s.type === \"module\");\r\n\r\n // Create refs Map EARLY so scripts can access $refs\r\n // Wrap in Proxy for cleaner dot notation access: $refs.inputEl instead of $refs.get(\"inputEl\")\r\n const earlyRefs = createRefsProxy(new Map<string, HTMLElement>());\r\n\r\n // Scan for $ref attributes and populate refs BEFORE running scripts\r\n // This allows scripts to immediately use $refs.elementName\r\n scanRefsOnly(this._root, earlyRefs);\r\n\r\n // Load external stylesheets (<link rel=\"stylesheet\">) FIRST\r\n // These are third-party CSS files (like highlight.js themes) that need\r\n // to be available for proper styling.\r\n // For Shadow DOM: injects CSS directly into shadow root (styles don't cross shadow boundary)\r\n // For light DOM: adds <link> to document head\r\n if (externalStyles && externalStyles.length > 0)\r\n {\r\n await loadExternalStyles(externalStyles, this._root, useShadowDOM);\r\n }\r\n\r\n // Load external scripts marked with 'external' attribute NEXT\r\n // These are third-party libraries (like highlight.js) that the inline\r\n // scripts may depend on. They need to load before inline scripts run.\r\n if (externalScripts.length > 0)\r\n {\r\n await loadPlainExternalScripts(externalScripts);\r\n }\r\n\r\n // Initialize reactive state and event handlers (for regular scripts)\r\n // Pass attribute overrides so they take precedence over defaults\r\n // Pass a callback that will update directives when state changes\r\n // DEFER bindings if we have module scripts (they need to load first)\r\n // Pass sourcePath so registerComponent resolves paths relative to this component\r\n // Pass componentId so event bus listeners can be cleaned up on disconnect\r\n // Pass earlyRefs so scripts can access $refs immediately\r\n // Pass templateBindings so auto-props are accessible in scripts\r\n this.state = await loadScripts(\r\n this._root,\r\n regularScripts,\r\n bindings,\r\n attributeOverrides,\r\n () => this._updateDirectives(),\r\n hasModuleScripts, // deferBindings = true if we have module scripts\r\n sourcePath, // componentUrl for correct path resolution\r\n this._componentId, // componentId for event bus cleanup\r\n earlyRefs, // refs for $refs access in scripts\r\n templateBindings, // auto-props from template bindings\r\n );\r\n\r\n // Reactive state now exists: property writes can flow straight into it.\r\n // Drain any props that arrived (via the DOM-property channel) while we\r\n // were awaiting script setup, then mark the channel live so future\r\n // `el.prop = value` assignments update state reactively.\r\n this._propsReady = true;\r\n if (this._pendingProps.size > 0)\r\n {\r\n for (const [propName, value] of this._pendingProps)\r\n {\r\n this.state[propName] = value;\r\n }\r\n this._pendingProps.clear();\r\n }\r\n\r\n // Register the onStateChange callback globally so external module scripts\r\n // can trigger UI updates when imported arrays are mutated.\r\n // This is used by the __wrapReactiveArray helper injected into external scripts.\r\n if (typeof globalThis !== \"undefined\")\r\n {\r\n if (!(globalThis as any).__ladrillosStateCallbacks)\r\n {\r\n (globalThis as any).__ladrillosStateCallbacks = new Map();\r\n }\r\n // The wrapper passes the state key its array is bound to (when known)\r\n // so mutations refresh that key's text/attribute bindings too, not\r\n // just directives. Keyless calls fall back to directive updates.\r\n (globalThis as any).__ladrillosStateCallbacks.set(\r\n this._componentId,\r\n (stateKey?: string) =>\r\n {\r\n const notify = (this.state as any)?.__notifyKeyChanged;\r\n if (stateKey && typeof notify === \"function\")\r\n {\r\n notify(stateKey);\r\n } else\r\n {\r\n this._updateDirectives();\r\n }\r\n },\r\n );\r\n }\r\n\r\n // Execute module scripts with runtime import rewriting\r\n // This handles <script type=\"module\"> with imports like:\r\n // import { foo } from \"./bar.js\"\r\n // Module scripts now contribute to reactive state!\r\n //\r\n // IMPORTANT: We pass this.state so module script functions write\r\n // directly to the reactive state. This makes `let x = 0; x++` work.\r\n // We also pass the onStateChange callback so imported arrays become reactive.\r\n if (sourcePath)\r\n {\r\n // Suspend per-key reactive binding updates while module scripts run.\r\n // Module scripts assign __state__.x one-by-one, but some bindings may\r\n // reference variables declared later in the same script. We apply all\r\n // bindings together once module execution finishes.\r\n (this.state as any).__suspendReactivity = true;\r\n try\r\n {\r\n const moduleState = await executeModuleScriptsWithReactivity(\r\n scripts,\r\n externalScripts,\r\n sourcePath,\r\n this._componentId,\r\n earlyRefs, // Pass refs so functions can capture the reference\r\n this.state, // Pass reactive state so functions write directly to it\r\n () => this._updateDirectives(), // Pass callback for imported array reactivity\r\n this, // Pass host element so $host is available in module scripts\r\n );\r\n\r\n // Mark state as having module scripts ONLY if there are actual module scripts\r\n // This affects how event handlers treat functions:\r\n // - Module scripts have reactive functions that should NOT be recreated\r\n // - Regular scripts need fresh function bindings each time\r\n if (hasModuleScripts || externalScripts.length > 0)\r\n {\r\n (this.state as any).__hasModuleScripts = true;\r\n }\r\n\r\n // Merge module script functions into reactive state\r\n // Variables are already in this.state (written directly by transformed code)\r\n // We just need to add the functions\r\n for (const [key, value] of Object.entries(moduleState))\r\n {\r\n if (typeof value === \"function\")\r\n {\r\n this.state[key] = value;\r\n }\r\n }\r\n } finally\r\n {\r\n (this.state as any).__suspendReactivity = false;\r\n }\r\n }\r\n\r\n // Now that ALL state is ready (regular + module scripts),\r\n // apply bindings and set up event handlers\r\n if (hasModuleScripts)\r\n {\r\n applyBindingsDeferred(this._root, bindings, this.state);\r\n }\r\n\r\n // Create expression evaluator for directives\r\n this._evaluator = createExpressionEvaluator();\r\n\r\n // Scan and process all directives ($for, $if, $show, $bind)\r\n // Use scanDirectivesWithRefs to reuse the earlyRefs Map we already populated\r\n // Note: scanRefsOnly was already called earlier, so refs are already in earlyRefs\r\n this._directives = scanDirectivesWithRefs(this._root, earlyRefs);\r\n\r\n // Also populate the global refs registry for external module scripts\r\n // This allows external .js files to access refs via the global registry\r\n if (typeof globalThis !== \"undefined\")\r\n {\r\n if (!(globalThis as any).__ladrillosRefs)\r\n {\r\n (globalThis as any).__ladrillosRefs = new Map();\r\n }\r\n // Get or create the refs Map for this component in the global registry\r\n let globalRefs = (globalThis as any).__ladrillosRefs.get(\r\n this._componentId,\r\n );\r\n if (!globalRefs)\r\n {\r\n globalRefs = new Map();\r\n (globalThis as any).__ladrillosRefs.set(\r\n this._componentId,\r\n globalRefs,\r\n );\r\n }\r\n // Copy all refs into the global registry\r\n for (const [key, value] of this._directives.refs)\r\n {\r\n globalRefs.set(key, value);\r\n }\r\n }\r\n\r\n // Expose refs on the component for external access\r\n (this as any).refs = this._directives.refs;\r\n // Also store on host element so event handlers can access them\r\n (this as any).__refs = this._directives.refs;\r\n\r\n // Initial directive rendering\r\n this._updateDirectives();\r\n\r\n // Set up two-way bindings ($bind)\r\n // Returns an updater function for state→input sync\r\n if (this._directives.twoWayBindings.length > 0)\r\n {\r\n this._updateBoundInputs = setupTwoWayBindings(\r\n this._directives.twoWayBindings,\r\n this.state,\r\n this._evaluator,\r\n );\r\n }\r\n\r\n // Dispatch custom event when component is ready\r\n this.dispatchEvent(\r\n new CustomEvent(\"ladrillos:ready\", {\r\n bubbles: true,\r\n composed: true, // Crosses shadow DOM boundary\r\n detail: { state: this.state, refs: this._directives.refs },\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * Called when the element is removed from the DOM.\r\n * Clean up event listeners, observers, etc.\r\n */\r\n disconnectedCallback(): void\r\n {\r\n // Clean up module script blob URLs to prevent memory leaks\r\n cleanupModuleScripts(this._componentId);\r\n\r\n // Clean up event bus listeners to prevent memory leaks\r\n cleanupComponentListeners(this._componentId);\r\n\r\n // Clean up batch scheduler registration to prevent memory leaks\r\n unregisterComponent(this._componentId);\r\n\r\n // Clean up global state change callback\r\n if (typeof globalThis !== \"undefined\")\r\n {\r\n (globalThis as any).__ladrillosStateCallbacks?.delete(\r\n this._componentId,\r\n );\r\n }\r\n\r\n this._initialized = false;\r\n this._propsReady = false;\r\n }\r\n\r\n /**\r\n * Called when an observed attribute changes.\r\n * Syncs HTML attributes with component reactive state.\r\n *\r\n * This enables:\r\n * element.setAttribute('count', '10') --> state.count = 10\r\n */\r\n attributeChangedCallback(\r\n name: string,\r\n oldValue: string | null,\r\n newValue: string | null,\r\n ): void\r\n {\r\n // Only process if value actually changed and component is initialized\r\n if (oldValue === newValue) return;\r\n\r\n // If not yet initialized, attributes will be read in connectedCallback\r\n if (!this._initialized) return;\r\n\r\n const parsed = this._parseAttributeValue(newValue);\r\n\r\n // Initialization has started but reactive state doesn't exist yet\r\n // (the async connectedCallback is still awaiting script setup).\r\n // Writing to `this.state` now would hit the placeholder object that\r\n // loadScripts replaces, silently losing the value. This happens when\r\n // a parent component's first binding pass evaluates an attribute\r\n // binding (e.g. name=\"{expr}\") on this child while the child is still\r\n // initializing. Stash it in the pending-props channel instead — it's\r\n // drained into reactive state right after state is created.\r\n if (!this._propsReady)\r\n {\r\n this._pendingProps.set(name, parsed);\r\n return;\r\n }\r\n\r\n // Sync attribute to reactive state\r\n // This triggers DOM updates automatically via the Proxy\r\n this.state[name] = parsed;\r\n }\r\n\r\n /**\r\n * Called when the element is moved to a new document.\r\n * Rare, but required for full spec compliance.\r\n */\r\n adoptedCallback(): void\r\n {\r\n // Re-initialize if needed when moved to a new document\r\n }\r\n\r\n // =========================================================================\r\n // Helper Methods\r\n // =========================================================================\r\n\r\n /**\r\n * Updates all directives when state changes.\r\n * Called by the reactive system on every state mutation.\r\n * Uses batch scheduling to coalesce multiple updates into one.\r\n */\r\n private _updateDirectives(): void\r\n {\r\n if (!this._directives || !this._evaluator) return;\r\n\r\n // Schedule the update to batch multiple state changes\r\n scheduleComponentUpdate(this._componentId, () =>\r\n {\r\n this._performDirectiveUpdates();\r\n });\r\n }\r\n\r\n /**\r\n * Actually performs the directive updates.\r\n * Called by the scheduler after batching.\r\n */\r\n private _performDirectiveUpdates(): void\r\n {\r\n if (!this._directives || !this._evaluator) return;\r\n\r\n // Update loops\r\n if (this._directives.loops.length > 0)\r\n {\r\n renderLoops(this._directives.loops, this.state, this._evaluator);\r\n }\r\n\r\n // Update conditionals\r\n if (this._directives.conditionals.length > 0)\r\n {\r\n updateConditionals(\r\n this._directives.conditionals,\r\n this.state,\r\n this._evaluator,\r\n );\r\n }\r\n\r\n // Update $show elements\r\n if (this._directives.showElements.length > 0)\r\n {\r\n updateShowElements(\r\n this._directives.showElements,\r\n this.state,\r\n this._evaluator,\r\n );\r\n }\r\n\r\n // Update two-way bound inputs (state→input sync)\r\n if (this._updateBoundInputs)\r\n {\r\n this._updateBoundInputs();\r\n }\r\n }\r\n\r\n /**\r\n * Collects all attribute values that can be used as state.\r\n * Collects ALL attributes (not just those matching declared variables).\r\n * This allows: <my-component count=\"5\"> without needing `let count` in script.\r\n */\r\n private _getAttributeOverrides(): Record<string, unknown>\r\n {\r\n const overrides: Record<string, unknown> = {};\r\n const skippedReserved: string[] = [];\r\n\r\n // Collect all attributes on the element\r\n for (const attr of Array.from(this.attributes))\r\n {\r\n // Skip standard HTML attributes UNLESS they're explicitly used in template bindings\r\n // This allows {title} in template to work with title=\"value\" attribute\r\n if (this._isReservedAttribute(attr.name))\r\n {\r\n // Track reserved attributes that look like they might be intended as state\r\n // (have a non-empty value that's not a standard HTML usage)\r\n if (attr.value && attr.value.trim() !== \"\")\r\n {\r\n skippedReserved.push(attr.name);\r\n }\r\n continue;\r\n }\r\n\r\n overrides[attr.name] = this._parseAttributeValue(attr.value);\r\n\r\n // HTML lowercases all attribute names, so a camelCase prop like\r\n // `isDisabled` can never be matched by an attribute. Mirror Vue's\r\n // convention: map kebab-case attributes to a camelCase alias so\r\n // <my-button is-disabled> resolves the script's `isDisabled` prop.\r\n if (attr.name.includes(\"-\"))\r\n {\r\n const camel = attr.name.replace(/-([a-z0-9])/g, (_, c) =>\r\n c.toUpperCase(),\r\n );\r\n if (camel !== attr.name && !(camel in overrides))\r\n {\r\n overrides[camel] = overrides[attr.name];\r\n }\r\n }\r\n }\r\n\r\n // Warn developers about reserved attributes that were skipped\r\n // (only if they're not in template bindings - those are intentional)\r\n const actuallySkipped = skippedReserved.filter(\r\n (name) => !templateBindings.includes(name),\r\n );\r\n if (actuallySkipped.length > 0)\r\n {\r\n const suggestions = actuallySkipped.map((name) =>\r\n {\r\n const alternatives: Record<string, string> = {\r\n title: \"heading\",\r\n class: \"className\",\r\n style: \"customStyle\",\r\n id: \"componentId\",\r\n hidden: \"isHidden\",\r\n };\r\n const alt =\r\n alternatives[name] ||\r\n `my${name.charAt(0).toUpperCase()}${name.slice(1)}`;\r\n return `\"${name}\" → try \"${alt}\"`;\r\n });\r\n\r\n warn(\r\n `Reserved HTML attribute(s) used on <${tagName}>: ${actuallySkipped\r\n .map((n) => `\"${n}\"`)\r\n .join(\", \")}.\\n` +\r\n ` These won't be available as component state because they're standard HTML attributes.\\n` +\r\n ` Suggestions: ${suggestions.join(\", \")}`,\r\n { tagName, sourcePath },\r\n );\r\n }\r\n\r\n return overrides;\r\n }\r\n\r\n /**\r\n * Checks if an attribute is a reserved HTML attribute that shouldn't\r\n * become component state.\r\n *\r\n * Exception: If the attribute is explicitly used in template bindings,\r\n * it's allowed (e.g., {title} in template makes title attribute valid).\r\n */\r\n private _isReservedAttribute(name: string): boolean\r\n {\r\n // If explicitly used in template bindings, allow it\r\n if (templateBindings.includes(name))\r\n {\r\n return false;\r\n }\r\n\r\n const reserved = [\r\n \"id\",\r\n \"class\",\r\n \"style\",\r\n \"slot\",\r\n \"part\",\r\n \"is\",\r\n \"tabindex\",\r\n \"title\",\r\n \"lang\",\r\n \"dir\",\r\n \"hidden\",\r\n \"draggable\",\r\n \"contenteditable\",\r\n ];\r\n return reserved.includes(name.toLowerCase()) || name.startsWith(\"data-\");\r\n }\r\n\r\n /**\r\n * Parses an attribute string value to the appropriate JS type.\r\n * Attributes are always strings, but we try to convert them.\r\n *\r\n * Conversions:\r\n * \"true\" / \"false\" -> boolean\r\n * \"42\" / \"3.14\" -> number\r\n * \"\" (empty) -> true (boolean attribute)\r\n * '[1,2,3]' / '{\"a\":1}' -> parsed JSON\r\n * anything else -> string\r\n *\r\n * Note: HTML entities are automatically decoded by the browser when\r\n * reading attribute values, so '&quot;' becomes '\"' before we see it.\r\n */\r\n private _parseAttributeValue(value: string | null): unknown\r\n {\r\n if (value === null) return null;\r\n if (value === \"\") return true; // Boolean attribute: <my-el disabled>\r\n if (value === \"true\") return true;\r\n if (value === \"false\") return false;\r\n\r\n // Try number conversion\r\n const num = Number(value);\r\n if (!isNaN(num) && value.trim() !== \"\") return num;\r\n\r\n // Try JSON parse for objects/arrays\r\n // The browser already decodes HTML entities (&quot; -> \") when we read the attribute\r\n try\r\n {\r\n const trimmed = value.trim();\r\n // Only try JSON parse if it looks like JSON (starts with [ or {)\r\n if (trimmed.startsWith(\"[\") || trimmed.startsWith(\"{\"))\r\n {\r\n return JSON.parse(trimmed);\r\n }\r\n } catch\r\n {\r\n // Not valid JSON, return as string\r\n }\r\n\r\n return value;\r\n }\r\n\r\n /**\r\n * Gets the component's root (shadow root or element itself).\r\n */\r\n get root(): HTMLElement | ShadowRoot | null\r\n {\r\n return this._root;\r\n }\r\n }\r\n\r\n // ===========================================================================\r\n // Reactive Property Accessors (typed prop channel)\r\n // ===========================================================================\r\n // Define getter/setter pairs on the prototype for every observed prop so a\r\n // parent can pass a complex value as a DOM property (e.g. `childEl.items =\r\n // [...]`) and have it land in the child's reactive state with its type\r\n // intact. Primitive props still flow through HTML attributes as before.\r\n //\r\n // Built-in DOM properties (id, title, hidden, className, ...) are skipped so\r\n // we never shadow native element behavior.\r\n for (const propName of allObservedAttributes)\r\n {\r\n // Skip internal component members (e.g. `state`): defining a prop accessor\r\n // with one of these names shadows the instance field and recurses.\r\n if (RESERVED_INSTANCE_PROPS.has(propName)) continue;\r\n if (propName in HTMLElement.prototype) continue;\r\n if (\r\n Object.prototype.hasOwnProperty.call(\r\n LadrillosWebComponent.prototype,\r\n propName,\r\n )\r\n )\r\n {\r\n continue;\r\n }\r\n\r\n Object.defineProperty(LadrillosWebComponent.prototype, propName, {\r\n configurable: true,\r\n enumerable: false,\r\n get(this: any): unknown\r\n {\r\n return this._propsReady\r\n ? this.state[propName]\r\n : this._pendingProps.get(propName);\r\n },\r\n set(this: any, value: unknown): void\r\n {\r\n if (this._propsReady)\r\n {\r\n // Live update — writes through the reactive state proxy and\r\n // re-renders the component.\r\n this.state[propName] = value;\r\n } else\r\n {\r\n // Assigned before init — stash and apply once state is ready.\r\n this._pendingProps.set(propName, value);\r\n }\r\n },\r\n });\r\n\r\n // HTML lowercases attribute names, so a parent passing a typed prop through\r\n // a camelCase attribute (postList={...}) sets `el.postlist`. Expose a\r\n // lowercase alias accessor that reads/writes the SAME canonical prop name,\r\n // so the value still lands in `state.postList`.\r\n const lowerProp = propName.toLowerCase();\r\n if (\r\n lowerProp !== propName &&\r\n !(lowerProp in HTMLElement.prototype) &&\r\n !Object.prototype.hasOwnProperty.call(\r\n LadrillosWebComponent.prototype,\r\n lowerProp,\r\n )\r\n )\r\n {\r\n Object.defineProperty(LadrillosWebComponent.prototype, lowerProp, {\r\n configurable: true,\r\n enumerable: false,\r\n get(this: any): unknown\r\n {\r\n return this._propsReady\r\n ? this.state[propName]\r\n : this._pendingProps.get(propName);\r\n },\r\n set(this: any, value: unknown): void\r\n {\r\n if (this._propsReady)\r\n {\r\n this.state[propName] = value;\r\n } else\r\n {\r\n this._pendingProps.set(propName, value);\r\n }\r\n },\r\n });\r\n }\r\n }\r\n\r\n return LadrillosWebComponent;\r\n}\r\n\r\n/**\r\n * Creates and registers a Web Component from a Ladrillos component.\r\n *\r\n * This is the main entry point that:\r\n * 1. Creates the component class\r\n * 2. Registers it with customElements.define\r\n */\r\nexport function createWebComponent(\r\n component: LadrillosComponent,\r\n useShadowDOM: boolean,\r\n): void\r\n{\r\n const { tagName } = component;\r\n\r\n // Only define if not already defined (prevents errors on hot reload)\r\n if (!customElements.get(tagName))\r\n {\r\n const ComponentClass = createWebComponentClass(component, useShadowDOM);\r\n customElements.define(tagName, ComponentClass);\r\n console.log(`🧩 Web component \"${tagName}\" registered.`);\r\n }\r\n}\r\n","/**\r\n * Lazy Placeholder Web Component\r\n *\r\n * A lightweight placeholder that observes for lazy loading triggers\r\n * and upgrades to the real component when activated.\r\n */\r\n\r\nimport { LadrillosComponent } from \"../../types\";\r\nimport { parseComponent } from \"../component/extract\";\r\nimport { fetchComponentSource } from \"../component/loader\";\r\nimport { createWebComponentClass } from \"../component/webcomponent\";\r\nimport { LazyStrategy } from \"./lazyStrategies\";\r\nimport { error, setComponentContext, ErrorCode } from \"../../utils/devWarnings\";\r\n\r\n/** Shared loading promises to dedupe fetches for same component */\r\nconst loadingPromises = new Map<string, Promise<LadrillosComponent>>();\r\n\r\n/** Components registry reference (injected from main Ladrillos instance) */\r\nlet componentsRegistry: Record<string, LadrillosComponent>;\r\n\r\n/** Loaded component data for creating instances */\r\ninterface LoadedComponentData\r\n{\r\n component: LadrillosComponent;\r\n useShadowDOM: boolean;\r\n}\r\nconst loadedComponents = new Map<string, LoadedComponentData>();\r\n\r\n/** Track which real components have been defined */\r\nconst definedRealComponents = new Set<string>();\r\n\r\n/** Pending lazy component configs */\r\ninterface LazyComponentConfig\r\n{\r\n name: string;\r\n absolutePath: string;\r\n useShadowDOM: boolean;\r\n strategy: LazyStrategy;\r\n}\r\n\r\nconst lazyConfigs = new Map<string, LazyComponentConfig>();\r\n\r\n/**\r\n * Get the internal tag name for the real component\r\n */\r\nfunction getRealTagName(name: string): string\r\n{\r\n return `${name}--loaded`;\r\n}\r\n\r\n/**\r\n * Initialize the lazy loading system with the components registry\r\n */\r\nexport function initLazyLoader(\r\n registry: Record<string, LadrillosComponent>\r\n): void\r\n{\r\n componentsRegistry = registry;\r\n}\r\n\r\n/**\r\n * Register a component for lazy loading\r\n */\r\nexport function registerLazyComponent(\r\n name: string,\r\n absolutePath: string,\r\n useShadowDOM: boolean,\r\n strategy: LazyStrategy\r\n): void\r\n{\r\n // Store config for lazy loading\r\n lazyConfigs.set(name, {\r\n name,\r\n absolutePath,\r\n useShadowDOM,\r\n strategy,\r\n });\r\n\r\n // Define a placeholder custom element\r\n if (!customElements.get(name))\r\n {\r\n customElements.define(name, createPlaceholderClass(name));\r\n }\r\n}\r\n\r\n/**\r\n * Load a lazy component (shared across all instances)\r\n */\r\nasync function loadLazyComponent(name: string): Promise<string>\r\n{\r\n const realTagName = getRealTagName(name);\r\n\r\n // Already loaded and defined?\r\n if (definedRealComponents.has(name))\r\n {\r\n return realTagName;\r\n }\r\n\r\n // Already loading? Return shared promise\r\n if (loadingPromises.has(name))\r\n {\r\n await loadingPromises.get(name)!;\r\n return realTagName;\r\n }\r\n\r\n const config = lazyConfigs.get(name);\r\n if (!config)\r\n {\r\n throw new Error(`Lazy component \"${name}\" not registered`);\r\n }\r\n\r\n // Create shared loading promise\r\n const loadPromise = (async () =>\r\n {\r\n const fetchResult = await fetchComponentSource(config.absolutePath);\r\n\r\n // Use the resolved path for correct relative path resolution in child components\r\n const component = await parseComponent(\r\n fetchResult.source,\r\n name,\r\n fetchResult.resolvedPath\r\n );\r\n\r\n // Store in registry\r\n componentsRegistry[name] = component;\r\n\r\n // Create and register the real component with a different tag name\r\n const ComponentClass = createWebComponentClass(\r\n component,\r\n config.useShadowDOM\r\n );\r\n\r\n // Define the real component with the internal tag name\r\n if (!customElements.get(realTagName))\r\n {\r\n customElements.define(realTagName, ComponentClass);\r\n }\r\n\r\n definedRealComponents.add(name);\r\n loadedComponents.set(name, {\r\n component,\r\n useShadowDOM: config.useShadowDOM,\r\n });\r\n\r\n return component;\r\n })();\r\n\r\n loadingPromises.set(name, loadPromise);\r\n\r\n try\r\n {\r\n await loadPromise;\r\n return realTagName;\r\n } finally\r\n {\r\n // Clean up loading promise after completion\r\n loadingPromises.delete(name);\r\n }\r\n}\r\n\r\n/**\r\n * Create a placeholder class for a lazy component\r\n */\r\nfunction createPlaceholderClass(componentName: string)\r\n{\r\n return class LazyPlaceholder extends HTMLElement\r\n {\r\n private teardown?: () => void;\r\n private isLoading = false;\r\n private isUpgraded = false;\r\n\r\n connectedCallback()\r\n {\r\n // Check for eager attribute - load immediately\r\n if (this.hasAttribute(\"eager\"))\r\n {\r\n this.triggerLoad();\r\n return;\r\n }\r\n\r\n const config = lazyConfigs.get(componentName);\r\n if (!config)\r\n {\r\n // Component already loaded, upgrade immediately\r\n this.triggerLoad();\r\n return;\r\n }\r\n\r\n // Start observing with the configured strategy\r\n this.teardown = config.strategy(() => this.triggerLoad(), this) as\r\n | (() => void)\r\n | undefined;\r\n }\r\n\r\n disconnectedCallback()\r\n {\r\n this.teardown?.();\r\n this.teardown = undefined;\r\n }\r\n\r\n private async triggerLoad()\r\n {\r\n if (this.isLoading || this.isUpgraded) return;\r\n this.isLoading = true;\r\n\r\n // Clean up observer\r\n this.teardown?.();\r\n this.teardown = undefined;\r\n\r\n try\r\n {\r\n const realTagName = await loadLazyComponent(componentName);\r\n this.isUpgraded = true;\r\n\r\n // Create real component instance and replace placeholder\r\n this.upgradeToRealComponent(realTagName);\r\n } catch (err)\r\n {\r\n const diagnostic = err instanceof Error ? err : new Error(String(err));\r\n error(\r\n \"Could not load the lazy component.\",\r\n { tagName: componentName },\r\n diagnostic,\r\n {\r\n code: ErrorCode.COMPONENT_LOAD_FAILED,\r\n hint: \"Check the registered component path and the original error shown below.\",\r\n },\r\n );\r\n this.isLoading = false;\r\n }\r\n }\r\n\r\n private upgradeToRealComponent(realTagName: string)\r\n {\r\n // Create real component using document.createElement (requires it to be defined)\r\n const realElement = document.createElement(realTagName);\r\n\r\n // Copy attributes (except internal ones)\r\n for (const attr of Array.from(this.attributes))\r\n {\r\n if (attr.name !== \"eager\" && attr.name !== \"tabindex\")\r\n {\r\n realElement.setAttribute(attr.name, attr.value);\r\n }\r\n }\r\n\r\n // Move original light-DOM children (slotted/projected content) to the\r\n // real element. These may be meaningful to the component (e.g. a\r\n // <code-block> wrapping a <template> the component reads in its script).\r\n // The real component's connectedCallback will snapshot these as\r\n // __originalHTML / __originalChildren before rendering its own template.\r\n while (this.firstChild)\r\n {\r\n realElement.appendChild(this.firstChild);\r\n }\r\n\r\n // Replace in DOM\r\n if (this.parentNode)\r\n {\r\n this.parentNode.replaceChild(realElement, this);\r\n } else\r\n {\r\n error(\r\n `No parent node for placeholder - cannot upgrade lazy component`,\r\n { tagName: componentName }\r\n );\r\n }\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Check if a component is registered for lazy loading\r\n */\r\nexport function isLazyComponent(name: string): boolean\r\n{\r\n return lazyConfigs.has(name) || definedRealComponents.has(name);\r\n}\r\n\r\n/**\r\n * Force load a lazy component (for programmatic loading)\r\n */\r\nexport async function forceLoadLazyComponent(\r\n name: string\r\n): Promise<LadrillosComponent | undefined>\r\n{\r\n if (lazyConfigs.has(name))\r\n {\r\n await loadLazyComponent(name);\r\n }\r\n return componentsRegistry[name];\r\n}\r\n\r\n/**\r\n * Get the real tag name for a loaded lazy component\r\n */\r\nexport function getLazyComponentTagName(name: string): string | undefined\r\n{\r\n if (definedRealComponents.has(name))\r\n {\r\n return getRealTagName(name);\r\n }\r\n return undefined;\r\n}\r\n","import { LadrillosComponent } from \"../types\";\r\nimport { parseComponent } from \"./component/extract\";\r\nimport { fetchComponentSource } from \"./component/loader\";\r\nimport { createWebComponent } from \"./component/webcomponent\";\r\nimport\r\n {\r\n LazyStrategy,\r\n defaultLazyStrategy,\r\n initLazyLoader,\r\n registerLazyComponent,\r\n forceLoadLazyComponent,\r\n } from \"./lazy\";\r\nimport\r\n {\r\n warn,\r\n error,\r\n ErrorCode,\r\n LadrillosError,\r\n } from \"../utils/devWarnings\";\r\n\r\n/**\r\n * Component registration configuration\r\n */\r\nexport interface ComponentConfig\r\n{\r\n name: string;\r\n path: string;\r\n useShadowDOM?: boolean;\r\n /**\r\n * Lazy loading configuration:\r\n * - `false` (default): Load immediately\r\n * - `true`: Lazy load using default strategy (visible with 100px margin)\r\n * - `LazyStrategy`: Custom lazy loading strategy\r\n */\r\n lazy?: boolean | LazyStrategy;\r\n}\r\n\r\n/**\r\n * Result of a batch component registration\r\n */\r\nexport interface RegisterComponentsResult\r\n{\r\n /** Components that registered successfully */\r\n success: string[];\r\n /** Components that failed with their errors */\r\n failed: Array<{ name: string; error: Error }>;\r\n /** Components that were skipped (already registered) */\r\n skipped: string[];\r\n}\r\n\r\nclass Ladrillos\r\n{\r\n components: Record<string, LadrillosComponent>;\r\n\r\n constructor()\r\n {\r\n this.components = {};\r\n // Initialize lazy loader with our components registry\r\n initLazyLoader(this.components);\r\n }\r\n\r\n async registerComponent(\r\n name: string,\r\n path: string,\r\n useShadowDOM: boolean = true,\r\n lazy: boolean | LazyStrategy = false,\r\n ): Promise<void>\r\n {\r\n // check if component is already registered\r\n if (this.components[name])\r\n {\r\n warn(\r\n `Component \"<${name}>\" is already registered.`,\r\n { tagName: name, sourcePath: path },\r\n {\r\n code: ErrorCode.COMPONENT_ALREADY_REGISTERED,\r\n hint: \"Remove the duplicate registration call or use a different component name.\",\r\n },\r\n );\r\n return;\r\n }\r\n\r\n const context = { tagName: name, sourcePath: path };\r\n\r\n if (!name?.trim() || !name.includes(\"-\"))\r\n {\r\n error(\r\n `Invalid component name \"${name || \"(empty)\"}\". Custom element names must contain a hyphen.`,\r\n context,\r\n undefined,\r\n {\r\n code: ErrorCode.INVALID_COMPONENT_NAME,\r\n hint: 'Use a lowercase name with a hyphen, such as \"user-card\".',\r\n },\r\n );\r\n return;\r\n }\r\n\r\n if (!path?.trim())\r\n {\r\n error(\"A component path is required.\", context, undefined, {\r\n code: ErrorCode.INVALID_COMPONENT_PATH,\r\n hint: \"Pass a URL or relative .html path as the second argument to registerComponent().\",\r\n });\r\n return;\r\n }\r\n\r\n try\r\n {\r\n // Resolve relative paths before loading so nested resources use the\r\n // component file as their base URL.\r\n const absolutePath = new URL(path, window.location.href).href;\r\n\r\n if (lazy)\r\n {\r\n const strategy = lazy === true ? defaultLazyStrategy : lazy;\r\n registerLazyComponent(name, absolutePath, useShadowDOM, strategy);\r\n return;\r\n }\r\n\r\n const fetchResult = await fetchComponentSource(absolutePath);\r\n // Use the resolved path (e.g., /components/search/index.html instead of /components/search)\r\n const component = await parseComponent(\r\n fetchResult.source,\r\n name,\r\n fetchResult.resolvedPath,\r\n );\r\n\r\n this.components[name] = component;\r\n\r\n createWebComponent(component, useShadowDOM);\r\n } catch (e)\r\n {\r\n const diagnostic = e instanceof LadrillosError ? e : null;\r\n error(\r\n \"Could not register the component.\",\r\n context,\r\n e,\r\n {\r\n code:\r\n diagnostic?.code ?? ErrorCode.COMPONENT_REGISTRATION_FAILED,\r\n hint:\r\n diagnostic?.hint ??\r\n \"Check the component template and the original error shown below.\",\r\n },\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Register multiple components at once with parallel fetching.\r\n *\r\n * Benefits over sequential registration:\r\n * - Parallel network requests via Promise.allSettled\r\n * - Early deduplication check (skips already registered)\r\n * - Batched custom element definitions\r\n * - Returns detailed results for error handling\r\n *\r\n * @example\r\n * ```js\r\n * // Array syntax\r\n * await ladrillos.registerComponents([\r\n * { name: 'my-header', path: './header.html' },\r\n * { name: 'my-footer', path: './footer.html', useShadowDOM: false }\r\n * ]);\r\n *\r\n * // Object syntax\r\n * await ladrillos.registerComponents({\r\n * 'my-header': './header.html',\r\n * 'my-footer': { path: './footer.html', useShadowDOM: false }\r\n * });\r\n * ```\r\n */\r\n async registerComponents(\r\n configs:\r\n | ComponentConfig[]\r\n | Record<string, string | Omit<ComponentConfig, \"name\">>,\r\n ): Promise<RegisterComponentsResult>\r\n {\r\n // Normalize input to array format\r\n const componentConfigs: ComponentConfig[] = Array.isArray(configs)\r\n ? configs\r\n : Object.entries(configs).map(([name, value]) =>\r\n typeof value === \"string\"\r\n ? { name, path: value }\r\n : { name, ...value },\r\n );\r\n\r\n const result: RegisterComponentsResult = {\r\n success: [],\r\n failed: [],\r\n skipped: [],\r\n };\r\n\r\n // Separate lazy and eager components\r\n const lazyComponents: Array<ComponentConfig & { absolutePath: string }> =\r\n [];\r\n const eagerComponents: Array<ComponentConfig & { absolutePath: string }> =\r\n [];\r\n\r\n for (const config of componentConfigs)\r\n {\r\n if (this.components[config.name])\r\n {\r\n result.skipped.push(config.name);\r\n continue;\r\n }\r\n\r\n // Resolve path once\r\n const absolutePath = new URL(config.path, window.location.href).href;\r\n const configWithPath = { ...config, absolutePath };\r\n\r\n if (config.lazy)\r\n {\r\n lazyComponents.push(configWithPath);\r\n } else\r\n {\r\n eagerComponents.push(configWithPath);\r\n }\r\n }\r\n\r\n // Register lazy components immediately (no network request yet)\r\n for (const config of lazyComponents)\r\n {\r\n try\r\n {\r\n const strategy =\r\n config.lazy === true\r\n ? defaultLazyStrategy\r\n : (config.lazy as LazyStrategy);\r\n const useShadowDOM = config.useShadowDOM ?? true;\r\n registerLazyComponent(\r\n config.name,\r\n config.absolutePath,\r\n useShadowDOM,\r\n strategy,\r\n );\r\n result.success.push(config.name);\r\n } catch (e)\r\n {\r\n result.failed.push({\r\n name: config.name,\r\n error: e instanceof Error ? e : new Error(String(e)),\r\n });\r\n }\r\n }\r\n\r\n // Process eager components with parallel fetching\r\n if (eagerComponents.length === 0)\r\n {\r\n return result;\r\n }\r\n\r\n // Parallel fetch all eager component sources\r\n const fetchResults = await Promise.allSettled(\r\n eagerComponents.map(async (config) =>\r\n {\r\n const result = await fetchComponentSource(config.absolutePath);\r\n return { config, result };\r\n }),\r\n );\r\n\r\n // Parse components in parallel\r\n const parseResults = await Promise.allSettled(\r\n fetchResults.map(async (fetchResult, index) =>\r\n {\r\n if (fetchResult.status === \"rejected\")\r\n {\r\n throw fetchResult.reason;\r\n }\r\n\r\n const { config, result } = fetchResult.value;\r\n\r\n // Use the resolved path for correct relative path resolution in child components\r\n const component = await parseComponent(\r\n result.source,\r\n config.name,\r\n result.resolvedPath,\r\n );\r\n return { config, component };\r\n }),\r\n );\r\n\r\n // Batch register all successfully parsed components\r\n for (let i = 0; i < parseResults.length; i++)\r\n {\r\n const parseResult = parseResults[i];\r\n const config = eagerComponents[i];\r\n\r\n if (parseResult.status === \"rejected\")\r\n {\r\n result.failed.push({\r\n name: config.name,\r\n error:\r\n parseResult.reason instanceof Error\r\n ? parseResult.reason\r\n : new Error(String(parseResult.reason)),\r\n });\r\n error(\r\n `Error registering component \"${config.name}\"`,\r\n { tagName: config.name, sourcePath: config.path },\r\n parseResult.reason,\r\n );\r\n continue;\r\n }\r\n\r\n const { component } = parseResult.value;\r\n const useShadowDOM = config.useShadowDOM ?? true;\r\n\r\n // Store in registry\r\n this.components[config.name] = component;\r\n\r\n // Define custom element\r\n try\r\n {\r\n createWebComponent(component, useShadowDOM);\r\n result.success.push(config.name);\r\n } catch (e)\r\n {\r\n result.failed.push({\r\n name: config.name,\r\n error: e instanceof Error ? e : new Error(String(e)),\r\n });\r\n // Remove from registry on failure\r\n delete this.components[config.name];\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Force load a lazy component programmatically.\r\n * Useful for preloading components before they're visible.\r\n */\r\n async loadLazyComponent(\r\n name: string,\r\n ): Promise<LadrillosComponent | undefined>\r\n {\r\n return forceLoadLazyComponent(name);\r\n }\r\n}\r\n\r\nexport const ladrillos = new Ladrillos();\r\n"],"mappings":"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"}