ladrillosjs 1.0.2 → 2.0.0-beta.1

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 (37) hide show
  1. package/README.md +533 -105
  2. package/dist/cache/functionCache.d.ts +15 -0
  3. package/dist/cache/index.d.ts +16 -0
  4. package/dist/core/componentParser.d.ts +29 -0
  5. package/dist/core/componentSource.d.ts +12 -0
  6. package/dist/core/css/cssParser.d.ts +3 -0
  7. package/dist/core/eventBus.d.ts +41 -0
  8. package/dist/core/html/htmlRenderer.d.ts +18 -0
  9. package/dist/core/html/htmlparser.d.ts +16 -0
  10. package/dist/core/js/scriptParser.d.ts +3 -0
  11. package/dist/core/main.d.ts +4 -26
  12. package/dist/core/webcomponent.d.ts +2 -2
  13. package/dist/index-CXHidyhO.js +8 -0
  14. package/dist/index-CXHidyhO.js.map +1 -0
  15. package/dist/index-VkDZJVOR.mjs +361 -0
  16. package/dist/index-VkDZJVOR.mjs.map +1 -0
  17. package/dist/index.d.ts +56 -6
  18. package/dist/ladrillosjs.cjs.js +2 -1
  19. package/dist/ladrillosjs.cjs.js.map +1 -0
  20. package/dist/ladrillosjs.es.js +12 -4
  21. package/dist/ladrillosjs.es.js.map +1 -0
  22. package/dist/ladrillosjs.umd.js +76 -18
  23. package/dist/ladrillosjs.umd.js.map +1 -0
  24. package/dist/types/LadrilloTypes.d.ts +47 -14
  25. package/dist/utils/logger.d.ts +14 -11
  26. package/dist/utils/regex.d.ts +2 -0
  27. package/dist/webcomponent-CJ3lZBZb.mjs +703 -0
  28. package/dist/webcomponent-CJ3lZBZb.mjs.map +1 -0
  29. package/dist/webcomponent-i9W7LUiv.js +70 -0
  30. package/dist/webcomponent-i9W7LUiv.js.map +1 -0
  31. package/package.json +8 -4
  32. package/dist/core/store.d.ts +0 -6
  33. package/dist/index-D_dHFObN.mjs +0 -215
  34. package/dist/index-X9YN_DbT.js +0 -3
  35. package/dist/utils/stringify.d.ts +0 -7
  36. package/dist/webcomponent-Cga3h8cx.js +0 -16
  37. package/dist/webcomponent-UTcwAakf.mjs +0 -769
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webcomponent-CJ3lZBZb.mjs","sources":["../src/core/css/cssParser.ts","../src/core/html/htmlparser.ts","../src/cache/functionCache.ts","../src/core/html/htmlRenderer.ts","../src/core/js/scriptParser.ts","../src/core/webcomponent.ts"],"sourcesContent":["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 {\r\n BindingDescriptor,\r\n TwoWayBindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { REGEX_PATTERNS } from \"../../utils/regex\";\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\nexport const loadTemplate = (\r\n host: HTMLElement | ShadowRoot,\r\n template: string\r\n): {\r\n bindings: BindingDescriptor[];\r\n twoWayBindings: TwoWayBindingDescriptor[];\r\n conditionals: ConditionalDescriptor[][];\r\n} => {\r\n host.innerHTML = template;\r\n\r\n const bindings = scanBindings(host);\r\n const twoWayBindings = scanTwoWayBindings(host);\r\n const conditionals = scanConditionals(host);\r\n\r\n return { bindings, twoWayBindings, conditionals };\r\n};\r\n\r\n/**\r\n * Traverses the DOM tree and collects all data binding expressions.\r\n * Looks for {property} placeholders in both text content and element attributes.\r\n */\r\nconst scanBindings = (host: HTMLElement | ShadowRoot): BindingDescriptor[] => {\r\n // TreeWalker efficiently traverses only text nodes\r\n const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, null);\r\n const bindings: BindingDescriptor[] = [];\r\n let node: Text | null;\r\n\r\n // Scan for text nodes with bindings\r\n // e.g. <p>{name}</p> or <span>{user.firstName}</span>\r\n while ((node = walker.nextNode() as Text | null)) {\r\n const matches = [...node.textContent.matchAll(REGEX_PATTERNS.bindings)];\r\n\r\n if (matches.length > 0) {\r\n // Store the original template text before any replacements\r\n const original = node.textContent;\r\n\r\n // Create one binding descriptor per node with all its placeholders\r\n const nodeBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n const isFunction = raw.includes(\"(\"); // Detect function calls like MyName(\"Peter\")\r\n\r\n // For functions, extract the function name as the path\r\n // For properties, split by dot notation\r\n const path = isFunction\r\n ? [raw.split(\"(\")[0].trim()] // Extract function name before (\r\n : raw.split(\".\").map((p) => p.trim());\r\n\r\n return { raw, path, isFunction };\r\n });\r\n\r\n bindings.push({ node, bindings: nodeBindings, original });\r\n }\r\n } // Scan for attributes with bindings\r\n // e.g. <img src=\"{imageUrl}\"> or <input value=\"{user.email}\">\r\n const elements = host.querySelectorAll(\"*\");\r\n elements.forEach((el) => {\r\n for (const attr of el.attributes) {\r\n // Skip conditional and special directive attributes\r\n if (\r\n attr.name === \"$if\" ||\r\n attr.name === \"$else-if\" ||\r\n attr.name === \"$else\" ||\r\n attr.name === \"$bind\"\r\n ) {\r\n continue;\r\n }\r\n\r\n const matches = [...attr.value.matchAll(REGEX_PATTERNS.bindings)];\r\n if (matches.length > 0) {\r\n // Store the original attribute value\r\n const original = attr.value;\r\n\r\n // Create one binding descriptor per attribute with all its placeholders\r\n const attrBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n const isFunction = raw.includes(\"(\");\r\n\r\n const path = isFunction\r\n ? [raw.split(\"(\")[0].trim()]\r\n : raw.split(\".\").map((p) => p.trim());\r\n\r\n return { raw, path, isFunction };\r\n });\r\n\r\n bindings.push({\r\n node: el as unknown as Text,\r\n bindings: attrBindings,\r\n original,\r\n isAttribute: true,\r\n attributeName: attr.name,\r\n });\r\n }\r\n }\r\n });\r\n\r\n return bindings;\r\n};\r\n\r\n/**\r\n * Scans for elements with $bind attribute for two-way data binding.\r\n * e.g. <input $bind=\"inputText\"> or <input $bind=\"person.name\">\r\n * Now also supports contenteditable elements: <div contenteditable $bind=\"text\">\r\n */\r\nconst scanTwoWayBindings = (\r\n host: HTMLElement | ShadowRoot\r\n): TwoWayBindingDescriptor[] => {\r\n const twoWayBindings: TwoWayBindingDescriptor[] = [];\r\n const elements = host.querySelectorAll(\"[\\\\$bind]\");\r\n\r\n elements.forEach((el) => {\r\n const bindValue = el.getAttribute(\"$bind\");\r\n if (!bindValue) return;\r\n\r\n const raw = bindValue.trim();\r\n const path = raw.split(\".\").map((p) => p.trim());\r\n\r\n // Support form inputs (input, textarea, select)\r\n if (\r\n el instanceof HTMLInputElement ||\r\n el instanceof HTMLTextAreaElement ||\r\n el instanceof HTMLSelectElement\r\n ) {\r\n twoWayBindings.push({\r\n element: el,\r\n path,\r\n raw,\r\n isContentEditable: false,\r\n });\r\n el.removeAttribute(\"$bind\");\r\n }\r\n // Support contenteditable elements\r\n else if (\r\n el instanceof HTMLElement &&\r\n (el.hasAttribute(\"contenteditable\") || el.isContentEditable)\r\n ) {\r\n twoWayBindings.push({\r\n element: el,\r\n path,\r\n raw,\r\n isContentEditable: true,\r\n });\r\n el.removeAttribute(\"$bind\");\r\n }\r\n });\r\n\r\n return twoWayBindings;\r\n};\r\n\r\n/**\r\n * Scans for elements with $if, $else-if, and $else attributes for conditional rendering.\r\n * Groups related conditionals together (if → else-if → else chains).\r\n * e.g. <div $if=\"isVisible\">...</div> or <div $else-if=\"count > 5\">...</div>\r\n */\r\nconst scanConditionals = (\r\n host: HTMLElement | ShadowRoot\r\n): ConditionalDescriptor[][] => {\r\n const allConditionals: ConditionalDescriptor[][] = [];\r\n const processedElements = new Set<Element>();\r\n\r\n // Find all $if elements (start of conditional chains)\r\n const ifElements = host.querySelectorAll(\"[\\\\$if]\");\r\n\r\n ifElements.forEach((element) => {\r\n if (processedElements.has(element)) return;\r\n\r\n const group: ConditionalDescriptor[] = [];\r\n let currentElement: Element | null = element;\r\n\r\n // Process the $if and all following $else-if and $else siblings\r\n while (currentElement) {\r\n const hasIf = currentElement.hasAttribute(\"$if\");\r\n const hasElseIf = currentElement.hasAttribute(\"$else-if\");\r\n const hasElse = currentElement.hasAttribute(\"$else\");\r\n\r\n if (!hasIf && !hasElseIf && !hasElse) break;\r\n\r\n processedElements.add(currentElement);\r\n\r\n let type: \"if\" | \"else-if\" | \"else\";\r\n let condition = \"\";\r\n\r\n if (hasIf) {\r\n type = \"if\";\r\n condition = currentElement.getAttribute(\"$if\") || \"\";\r\n currentElement.removeAttribute(\"$if\");\r\n } else if (hasElseIf) {\r\n type = \"else-if\";\r\n condition = currentElement.getAttribute(\"$else-if\") || \"\";\r\n currentElement.removeAttribute(\"$else-if\");\r\n } else {\r\n type = \"else\";\r\n currentElement.removeAttribute(\"$else\");\r\n }\r\n\r\n // Create a comment placeholder to mark the position\r\n const placeholder = document.createComment(\r\n `conditional:${type}:${condition}`\r\n );\r\n\r\n const parent = currentElement.parentElement || host;\r\n const nextSibling = currentElement.nextSibling;\r\n\r\n // Insert placeholder before the element\r\n parent.insertBefore(placeholder, currentElement);\r\n\r\n const descriptor: ConditionalDescriptor = {\r\n element: currentElement as Element,\r\n condition: condition.trim(),\r\n type,\r\n placeholder,\r\n group: [], // Will be set after the group is complete\r\n originalParent: parent as Element | ShadowRoot,\r\n nextSibling,\r\n };\r\n\r\n group.push(descriptor);\r\n\r\n // Move to the next sibling to check for $else-if or $else\r\n const next: Element | null = currentElement.nextElementSibling;\r\n\r\n // Remove element from DOM initially\r\n currentElement.remove();\r\n\r\n currentElement = next;\r\n\r\n // If next element isn't $else-if or $else, stop the chain\r\n if (\r\n next &&\r\n !next.hasAttribute(\"$else-if\") &&\r\n !next.hasAttribute(\"$else\")\r\n ) {\r\n break;\r\n }\r\n }\r\n\r\n // Set the group reference for all descriptors in this chain\r\n group.forEach((desc) => {\r\n desc.group = group;\r\n });\r\n\r\n allConditionals.push(group);\r\n });\r\n\r\n return allConditionals;\r\n};\r\n\r\n/**\r\n * Extracts variable names from conditional expressions.\r\n * Removes curly braces and extracts identifiers.\r\n * e.g., \"{sending}\" → [\"sending\"], \"{count > 5}\" → [\"count\"]\r\n */\r\nexport const extractConditionalVariables = (\r\n conditionalGroups: ConditionalDescriptor[][]\r\n): Set<string> => {\r\n const variables = new Set<string>();\r\n\r\n conditionalGroups.forEach((group) => {\r\n group.forEach((descriptor) => {\r\n let condition = descriptor.condition;\r\n\r\n // Remove curly braces: {sending} → sending\r\n condition = condition.replace(/\\{([^}]+)\\}/g, \"$1\");\r\n\r\n // Extract variable names (identifiers)\r\n // Match JavaScript identifiers but exclude keywords and literals\r\n const identifierRegex =\r\n /\\b([a-zA-Z_$][a-zA-Z0-9_$]*(?:\\.[a-zA-Z_$][a-zA-Z0-9_$]*)*)\\b/g;\r\n const keywords = new Set([\r\n \"true\",\r\n \"false\",\r\n \"null\",\r\n \"undefined\",\r\n \"typeof\",\r\n \"instanceof\",\r\n \"new\",\r\n \"return\",\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 ]);\r\n\r\n let match;\r\n while ((match = identifierRegex.exec(condition)) !== null) {\r\n const identifier = match[1];\r\n const rootVar = identifier.split(\".\")[0]; // Get root variable name\r\n\r\n // Skip keywords and literals\r\n if (!keywords.has(rootVar)) {\r\n variables.add(rootVar);\r\n }\r\n }\r\n });\r\n });\r\n\r\n return variables;\r\n};\r\n","/**\r\n * Cache for compiled function expressions used in template bindings.\r\n * Prevents memory leaks by reusing Function objects for identical expressions.\r\n * Example: {MyName(\"Peter\")} compiles once and is reused on every render.\r\n */\r\nconst functionCache = new Map<string, Function>();\r\nconst maxFunctionCacheSize = 100; // Functions are small, can cache more\r\n\r\n/**\r\n * Gets or creates a cached function for evaluating template expressions.\r\n * Uses LRU pattern to limit cache size and prevent unbounded growth.\r\n * @param expression - The JavaScript expression to compile (e.g., 'MyName(\"Peter\")')\r\n * @returns Compiled Function object that can be executed with a component context\r\n */\r\nexport const getCachedFunction = (expression: string): Function => {\r\n const cached = functionCache.get(expression);\r\n\r\n if (cached) {\r\n // LRU: Move to end (most recently used position)\r\n functionCache.delete(expression);\r\n functionCache.set(expression, cached);\r\n return cached;\r\n }\r\n\r\n // Cache miss: compile new function\r\n const compiledFunc = new Function(\r\n \"component\",\r\n `with(component) { return ${expression}; }`\r\n );\r\n\r\n // Check cache size and evict least recently used if needed\r\n if (functionCache.size >= maxFunctionCacheSize) {\r\n const firstKey = functionCache.keys().next().value;\r\n if (firstKey) {\r\n functionCache.delete(firstKey);\r\n }\r\n }\r\n\r\n // Add as most recently used\r\n functionCache.set(expression, compiledFunc);\r\n return compiledFunc;\r\n};\r\n\r\n/**\r\n * Clears the function cache. Useful for testing or memory management.\r\n */\r\nexport const clearFunctionCache = (): void => {\r\n functionCache.clear();\r\n};\r\n\r\n/**\r\n * Gets the current function cache size for debugging/monitoring.\r\n */\r\nexport const getFunctionCacheSize = (): number => {\r\n return functionCache.size;\r\n};\r\n","import {\r\n BindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { getCachedFunction } from \"../../cache/functionCache\";\r\n\r\n/**\r\n * Safely retrieves a nested value from an object using a path array.\r\n * Example: getValue({ user: { name: 'John' } }, ['user', 'name']) returns 'John'\r\n */\r\nconst getValue = (ctx: unknown, path: string[]): unknown => {\r\n return path.reduce<unknown>((acc: unknown, segment: string) => {\r\n // Stop traversal if we hit null/undefined or non-object\r\n if (acc == null || typeof acc !== \"object\") return undefined;\r\n return (acc as Record<string, unknown>)[segment];\r\n }, ctx);\r\n};\r\n\r\n/**\r\n * Safely sets a nested value in an object using a path array.\r\n * Example: setValue({ user: {} }, ['user', 'name'], 'John') sets user.name to 'John'\r\n * Creates intermediate objects if they don't exist.\r\n */\r\nexport const setValue = (ctx: any, path: string[], value: unknown): void => {\r\n if (path.length === 0) return;\r\n\r\n // Navigate to the parent object\r\n const lastKey = path[path.length - 1];\r\n const parentPath = path.slice(0, -1);\r\n\r\n let current = ctx;\r\n\r\n // Create intermediate objects if needed\r\n for (const segment of parentPath) {\r\n if (current[segment] === undefined || current[segment] === null) {\r\n current[segment] = {};\r\n }\r\n current = current[segment];\r\n }\r\n\r\n // Set the final value\r\n current[lastKey] = value;\r\n};\r\n\r\n/**\r\n * Updates all DOM bindings with values from the current state context.\r\n * Replaces {property.path} placeholders in text nodes and element attributes.\r\n * Always renders from the original template to support reactive updates.\r\n */\r\nexport const renderBindings = (\r\n bindings: BindingDescriptor[],\r\n context: unknown,\r\n component?: any\r\n): void => {\r\n for (const binding of bindings) {\r\n // Start with the original template\r\n let result = binding.original;\r\n\r\n // Replace all placeholders in this node\r\n for (const { raw, path, isFunction } of binding.bindings) {\r\n let value: unknown;\r\n\r\n if (isFunction) {\r\n // Execute function calls like MyName(\"Peter\")\r\n try {\r\n // Get the function from the component\r\n const funcName = path[0];\r\n const func = component?.[funcName];\r\n\r\n if (typeof func === \"function\") {\r\n // Use cached function to prevent memory leaks\r\n const evalFunc = getCachedFunction(raw);\r\n value = evalFunc(component);\r\n } else {\r\n value = undefined;\r\n }\r\n } catch (error) {\r\n console.error(`Error executing function binding {${raw}}:`, error);\r\n value = undefined;\r\n }\r\n } else {\r\n // Regular property access\r\n value = getValue(context, path);\r\n }\r\n\r\n if (value === undefined) continue;\r\n const replacement = String(value ?? \"\");\r\n\r\n // Replace this specific placeholder\r\n result = result.replace(`{${raw}}`, replacement);\r\n }\r\n\r\n // Apply the final result to the DOM\r\n if (binding.node.nodeType === Node.TEXT_NODE) {\r\n const textNode = binding.node as Text;\r\n const parentElement = textNode.parentElement;\r\n\r\n // Check if this looks like HTML content\r\n const isHTMLContent =\r\n result.trim().startsWith(\"<\") && result.includes(\">\");\r\n\r\n // If parent element exists and content is HTML, render as HTML\r\n if (parentElement && isHTMLContent) {\r\n parentElement.innerHTML = result;\r\n } else {\r\n // Otherwise, use textContent for security\r\n textNode.textContent = result;\r\n }\r\n } else {\r\n // Handle attribute bindings (e.g., <img src=\"{imageUrl}\">)\r\n const element = binding.node as unknown as Element;\r\n if (binding.isAttribute && binding.attributeName) {\r\n element.setAttribute(binding.attributeName, result);\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Evaluates a conditional expression in the context of the component.\r\n * Supports both simple boolean checks and complex expressions.\r\n * e.g. \"isVisible\", \"{isVisible}\", \"count > 5\", \"{count} > 5\"\r\n */\r\nconst evaluateCondition = (\r\n condition: string,\r\n context: unknown,\r\n component?: any\r\n): boolean => {\r\n if (!condition) return true; // $else has no condition\r\n\r\n // Remove curly braces if present: {sending} -> sending\r\n let processedCondition = condition.trim();\r\n\r\n // Replace all {variable} with just variable\r\n processedCondition = processedCondition.replace(/\\{([^}]+)\\}/g, \"$1\");\r\n\r\n try {\r\n // Replace variable references in the condition with their values\r\n // This is a simple approach - for production, consider a proper expression parser\r\n const func = new Function(\r\n \"context\",\r\n \"component\",\r\n `\r\n with (context) {\r\n try {\r\n return Boolean(${processedCondition});\r\n } catch (e) {\r\n return false;\r\n }\r\n }\r\n `\r\n );\r\n\r\n return func(context, component);\r\n } catch (error) {\r\n console.error(`Error evaluating condition \"${condition}\":`, error);\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Updates conditional rendering based on current state.\r\n * Shows/hides elements based on their $if, $else-if, $else conditions.\r\n */\r\nexport const renderConditionals = (\r\n conditionalGroups: ConditionalDescriptor[][],\r\n context: unknown,\r\n component?: any\r\n): void => {\r\n // Process each conditional group (if/else-if/else chain)\r\n for (const group of conditionalGroups) {\r\n let conditionMet = false;\r\n\r\n // Evaluate each condition in the group\r\n for (const descriptor of group) {\r\n const { element, condition, type, placeholder, originalParent } =\r\n descriptor;\r\n\r\n // Check if this condition should be rendered\r\n let shouldRender = false;\r\n\r\n if (type === \"else\") {\r\n // $else renders if no previous condition was met\r\n shouldRender = !conditionMet;\r\n } else if (!conditionMet) {\r\n // $if or $else-if: evaluate condition\r\n shouldRender = evaluateCondition(condition, context, component);\r\n if (shouldRender) conditionMet = true;\r\n }\r\n\r\n // Update DOM based on shouldRender\r\n const isInDOM = element.parentNode !== null;\r\n\r\n if (shouldRender && !isInDOM) {\r\n // Insert element after its placeholder\r\n placeholder.parentNode?.insertBefore(element, placeholder.nextSibling);\r\n } else if (!shouldRender && isInDOM) {\r\n // Remove element from DOM\r\n element.remove();\r\n }\r\n }\r\n }\r\n};\r\n","import {\r\n ScriptElement,\r\n BindingDescriptor,\r\n ExternalScriptElement,\r\n TwoWayBindingDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { eventBus } from \"../eventBus\";\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 * Injects $bind variables into the script scope and validates no conflicts exist.\r\n * Creates property descriptors that proxy to component.state for reactive access.\r\n */\r\nconst injectBindVariables = (\r\n scriptContent: string,\r\n twoWayBindings: TwoWayBindingDescriptor[]\r\n): {\r\n injectedCode: string;\r\n componentInjections: string;\r\n bindVarNames: Set<string>;\r\n errors: string[];\r\n} => {\r\n const bindVarNames = new Set<string>();\r\n const errors: string[] = [];\r\n\r\n // Extract all $bind variable names (root-level only, e.g., \"person\" from \"person.name\")\r\n twoWayBindings.forEach(({ path }) => {\r\n const rootVar = path[0];\r\n bindVarNames.add(rootVar);\r\n });\r\n\r\n // Check for conflicts - devs trying to redeclare $bind variables\r\n bindVarNames.forEach((varName) => {\r\n const redeclarationRegex = new RegExp(\r\n `(?:const|let|var)\\\\s+${varName}\\\\s*=`,\r\n \"g\"\r\n );\r\n\r\n if (redeclarationRegex.test(scriptContent)) {\r\n errors.push(\r\n `⚠️ Variable \"${varName}\" is already bound via $bind and cannot be redeclared. Remove the declaration or use a different variable name.`\r\n );\r\n }\r\n });\r\n\r\n // Create proxy getters/setters for each $bind variable in script scope\r\n const injections: string[] = [];\r\n const componentInjections: string[] = [];\r\n\r\n bindVarNames.forEach((varName) => {\r\n // Define on component object for event handler access via with(component)\r\n componentInjections.push(`\r\n if (!Object.getOwnPropertyDescriptor(component, '${varName}')) {\r\n Object.defineProperty(component, '${varName}', {\r\n get() { return this.state.${varName}; },\r\n set(val) { this.state.${varName} = val; },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n }\r\n `);\r\n });\r\n\r\n return {\r\n injectedCode: \"\", // No longer needed in script scope\r\n componentInjections: componentInjections.join(\"\\n\"),\r\n bindVarNames,\r\n errors,\r\n };\r\n};\r\n\r\n/**\r\n * Extracts variable declarations (const, let, var) from script content\r\n * that match the template bindings or conditionals, and returns code to bind them to state.\r\n * Only binds variables that are actually used in the template or conditionals.\r\n */\r\nconst extractStateBindings = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n conditionalVars: Set<string> = new Set()\r\n): { stateBindings: string[]; boundVarNames: Set<string> } => {\r\n const stateBindings: string[] = [];\r\n\r\n // Create a Set of all binding names used in the template for fast lookup\r\n const bindingNames = new Set<string>();\r\n bindings.forEach((binding) => {\r\n binding.bindings.forEach((b) => {\r\n // Extract the root property name (e.g., \"user.name\" → \"user\", \"count\" → \"count\")\r\n const rootName = b.path[0];\r\n bindingNames.add(rootName);\r\n });\r\n });\r\n\r\n // Add conditional variables to binding names\r\n conditionalVars.forEach((varName) => {\r\n bindingNames.add(varName);\r\n });\r\n\r\n // Match: const name = value; | let count = 0; | var items = [];\r\n const variableRegex = /(?:const|let|var)\\s+(\\w+)\\s*=\\s*([^;]+);?/g;\r\n\r\n let match;\r\n while ((match = variableRegex.exec(scriptContent)) !== null) {\r\n const varName = match[1];\r\n\r\n // Only auto-bind if this variable is used in a template binding\r\n if (bindingNames.has(varName)) {\r\n stateBindings.push(`component.state.${varName} = ${varName};`);\r\n }\r\n }\r\n\r\n return { stateBindings, boundVarNames: bindingNames };\r\n};\r\n\r\n/**\r\n * Transforms script content to redirect bound variable assignments to state.\r\n * Handles assignments, increments, decrements, and compound assignments.\r\n * Examples:\r\n * - \"name = value\" → \"component.state.name = value\"\r\n * - \"count++\" → \"component.state.count++\"\r\n * - \"count += 5\" → \"component.state.count += 5\"\r\n * This makes reactivity transparent - users don't need to know about state.\r\n */\r\nconst transformBoundAssignments = (\r\n scriptContent: string,\r\n boundVarNames: Set<string>\r\n): string => {\r\n if (boundVarNames.size === 0) return scriptContent;\r\n\r\n let transformed = scriptContent;\r\n\r\n boundVarNames.forEach((varName) => {\r\n // 1. Transform increment/decrement: count++ or count-- or ++count or --count\r\n const incrementRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.)\\\\b(\\\\+\\\\+|\\\\-\\\\-)${varName}\\\\b|\\\\b${varName}(\\\\+\\\\+|\\\\-\\\\-)`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(incrementRegex, (match) => {\r\n if (match.startsWith(\"++\") || match.startsWith(\"--\")) {\r\n // Prefix: ++count or --count\r\n const op = match.substring(0, 2);\r\n return `${op}component.state.${varName}`;\r\n } else {\r\n // Postfix: count++ or count--\r\n const op = match.substring(match.length - 2);\r\n return `component.state.${varName}${op}`;\r\n }\r\n });\r\n\r\n // 2. Transform compound assignments: count += 5, count -= 3, count *= 2, etc.\r\n const compoundRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.)\\\\b${varName}\\\\s*(\\\\+=|\\\\-=|\\\\*=|\\\\/=|%=|\\\\*\\\\*=|<<=|>>=|>>>=|&=|\\\\|=|\\\\^=)`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(\r\n compoundRegex,\r\n `component.state.${varName}$1`\r\n );\r\n\r\n // 3. Transform simple assignments: name = value\r\n // Must come last to avoid interfering with compound assignments\r\n const assignmentRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.|\\\\+|\\\\-|\\\\*|\\\\/|%|<|>|&|\\\\||\\\\^)\\\\b${varName}\\\\s*=\\\\s*([^=])`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(\r\n assignmentRegex,\r\n `component.state.${varName} = $1`\r\n );\r\n });\r\n\r\n return transformed;\r\n};\r\n\r\n/**\r\n * Processes script content: extracts functions, binds state variables, and transforms assignments.\r\n * This is the core script processing logic that can be reused for both inline and external scripts.\r\n * @param scriptContent - The raw script content to process\r\n * @param bindings - Template bindings to determine which variables should be reactive\r\n * @param twoWayBindings - Two-way bound variables from $bind attributes\r\n * @param host - The host element or shadow root (for querySelector)\r\n * @param componentHost - The component element to execute the script on\r\n * @param conditionalVars - Variables used in conditional expressions ($if, $else-if)\r\n */\r\nconst processScript = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[],\r\n host: HTMLElement | ShadowRoot,\r\n componentHost: HTMLElement,\r\n conditionalVars: Set<string> = new Set()\r\n): void => {\r\n try {\r\n // Inject $bind variables and check for conflicts\r\n const { injectedCode, componentInjections, bindVarNames, errors } =\r\n injectBindVariables(scriptContent, twoWayBindings);\r\n\r\n // Log errors if any conflicts found\r\n if (errors.length > 0) {\r\n console.error(\"❌ $bind Variable Conflicts Detected:\");\r\n errors.forEach((err) => console.error(err));\r\n }\r\n\r\n // Extract function names from the script content\r\n const functionRegex =\r\n /function\\s+(\\w+)|const\\s+(\\w+)\\s*=\\s*(?:\\([^)]*\\)|[\\w\\s]*)\\s*=>/g;\r\n const functionNames: string[] = [];\r\n let match;\r\n\r\n while ((match = functionRegex.exec(scriptContent)) !== null) {\r\n const functionName = match[1] || match[2];\r\n if (functionName) {\r\n functionNames.push(functionName);\r\n }\r\n }\r\n\r\n // Auto-attach detected functions\r\n // Wrap functions to bind them to component and maintain variable access\r\n const attachFunctions = functionNames\r\n .map(\r\n (name) =>\r\n `component.${name} = typeof ${name} !== 'undefined' ? ${name}.bind(component) : undefined;`\r\n )\r\n .join(\"\\n \");\r\n\r\n // Extract and auto-bind variables to state (only those used in template bindings or conditionals)\r\n const { stateBindings, boundVarNames } = extractStateBindings(\r\n scriptContent,\r\n bindings,\r\n conditionalVars\r\n );\r\n\r\n // Merge bindVarNames with boundVarNames for transformation\r\n const allBoundVars = new Set([...boundVarNames, ...bindVarNames]);\r\n\r\n const attachStateBindings = stateBindings.join(\"\\n \");\r\n\r\n // Transform the script to make bound variable assignments reactive\r\n const transformedContent = transformBoundAssignments(\r\n scriptContent,\r\n allBoundVars\r\n );\r\n\r\n // Create a wrapper that captures functions and variables in component scope\r\n const wrappedScript = `\r\n (function() {\r\n // Create component scope with direct access to state\r\n const component = this;\r\n const $state = component.state;\r\n \r\n // Define $bind variables on component object for event handler access\r\n ${componentInjections}\r\n \r\n // Provide framework utilities with $ prefix to avoid naming conflicts\r\n const $setState = (updates) => component.setState(updates);\r\n \r\n // Event bus methods for component communication\r\n const $emit = (eventName, data) => arguments[2].emit(eventName, data);\r\n const $listen = (eventName, callback) => {\r\n const unsubscribe = arguments[2].listen(eventName, callback);\r\n // Store unsubscribe function for cleanup on disconnect\r\n if (!component.__eventUnsubscribers) {\r\n component.__eventUnsubscribers = [];\r\n }\r\n component.__eventUnsubscribers.push(unsubscribe);\r\n return unsubscribe;\r\n };\r\n \r\n // Also attach to component for event handler access\r\n component.$emit = $emit;\r\n component.$listen = $listen;\r\n \r\n // Override querySelector/querySelectorAll to query within the component's host\r\n const host = arguments[1];\r\n const $querySelector = (selector) => host.querySelector(selector);\r\n const $querySelectorAll = (selector) => host.querySelectorAll(selector);\r\n \r\n // Execute script content within component scope so $bind variables are accessible\r\n with(component) {\r\n ${transformedContent}\r\n \r\n // Auto-bind variables to component state (e.g., const name = \"value\" → this.state.name = \"value\")\r\n ${attachStateBindings}\r\n \r\n // Auto-attach all detected functions to component for onclick access\r\n ${attachFunctions}\r\n }\r\n }).call(arguments[0], arguments[0], arguments[1], arguments[2])\r\n `;\r\n\r\n const executor = new Function(wrappedScript);\r\n executor(componentHost, host, eventBus);\r\n } catch (error) {\r\n console.error(\"Script execution failed:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Processes inline event handlers (onclick, onkeyup, oninput, etc.) to bind them to the component context.\r\n * Removes inline event attributes and converts them to proper event listeners\r\n * that have access to the component scope.\r\n * @param host - The host element or shadow root\r\n * @param componentHost - The component element\r\n */\r\nconst processEventHandlers = (\r\n host: HTMLElement | ShadowRoot,\r\n componentHost: HTMLElement\r\n): void => {\r\n // All standard DOM events that can be handled as attributes\r\n const eventTypes = [\r\n \"click\",\r\n \"dblclick\",\r\n \"mousedown\",\r\n \"mouseup\",\r\n \"mouseover\",\r\n \"mouseout\",\r\n \"mousemove\",\r\n \"mouseenter\",\r\n \"mouseleave\",\r\n \"keydown\",\r\n \"keyup\",\r\n \"keypress\",\r\n \"focus\",\r\n \"blur\",\r\n \"change\",\r\n \"input\",\r\n \"submit\",\r\n \"reset\",\r\n \"scroll\",\r\n \"resize\",\r\n \"load\",\r\n \"unload\",\r\n \"touchstart\",\r\n \"touchend\",\r\n \"touchmove\",\r\n \"touchcancel\",\r\n \"dragstart\",\r\n \"drag\",\r\n \"dragend\",\r\n \"dragenter\",\r\n \"dragover\",\r\n \"dragleave\",\r\n \"drop\",\r\n ];\r\n\r\n // Add a WeakSet to track processed elements\r\n const processedElements = new WeakSet<Element>();\r\n\r\n eventTypes.forEach((eventType) => {\r\n const attributeName = `on${eventType}`;\r\n const elements =\r\n host instanceof ShadowRoot\r\n ? host.querySelectorAll(`[${attributeName}]`)\r\n : componentHost.querySelectorAll(`[${attributeName}]`);\r\n\r\n elements.forEach((element) => {\r\n // Create a unique key for this element + event combination\r\n const key = `${attributeName}`;\r\n if ((element as any)[`__processed_${key}`]) return; // Skip if already processed\r\n\r\n const handlerCode = element.getAttribute(attributeName);\r\n if (handlerCode) {\r\n element.removeAttribute(attributeName);\r\n (element as HTMLElement).addEventListener(\r\n eventType,\r\n function (this: HTMLElement, event: Event) {\r\n const func = new Function(\r\n \"event\",\r\n \"component\",\r\n `\r\n with(component) {\r\n ${handlerCode}\r\n }\r\n `\r\n );\r\n func.call(this, event, componentHost);\r\n }\r\n );\r\n\r\n // Mark as processed for this specific event\r\n (element as any)[`__processed_${key}`] = true;\r\n }\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Transforms a module script to make variable bindings reactive.\r\n * Detects variables used in template bindings and wraps assignments to update component state.\r\n * @param scriptContent - The module script content\r\n * @param bindings - Template bindings to determine which variables should be reactive\r\n * @param componentId - The component ID for accessing the context\r\n * @returns Transformed script content\r\n */\r\nconst transformModuleScript = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n componentId: string\r\n): string => {\r\n // Extract variable names used in bindings\r\n const bindingVarNames = new Set<string>();\r\n bindings.forEach((binding) => {\r\n binding.bindings.forEach((b) => {\r\n if (!b.isFunction) {\r\n const rootName = b.path[0];\r\n bindingVarNames.add(rootName);\r\n }\r\n });\r\n });\r\n\r\n if (bindingVarNames.size === 0) {\r\n return scriptContent; // No transformations needed\r\n }\r\n\r\n // Add helper code at the beginning to get component context\r\n const helperCode = `\r\n// Auto-generated: Get component context for reactive bindings\r\nconst __getContext = () => window.__ladrilloContexts?.get('${componentId}');\r\nconst __component = __getContext()?.element;\r\n`;\r\n\r\n let transformed = scriptContent;\r\n\r\n // Transform variable declarations to initialize state\r\n bindingVarNames.forEach((varName) => {\r\n // Match: let varName = value; or const varName = value;\r\n const declRegex = new RegExp(\r\n `(let|const|var)\\\\s+${varName}\\\\s*=\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(declRegex, (match, keyword, value) => {\r\n return `${keyword} ${varName} = ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform assignments: varName = value\r\n // Make sure we don't match declarations (let/const/var) or object properties (obj.varName)\r\n const assignRegex = new RegExp(\r\n `(?<!let\\\\s|const\\\\s|var\\\\s|\\\\.)\\\\b${varName}\\\\s*=\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(assignRegex, (match, value) => {\r\n return `${varName} = ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform increment/decrement operators\r\n const incDecRegex = new RegExp(`\\\\b${varName}(\\\\+\\\\+|\\\\-\\\\-)`, \"g\");\r\n\r\n transformed = transformed.replace(incDecRegex, (match, op) => {\r\n return `${varName}${op};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform compound assignments\r\n const compoundRegex = new RegExp(\r\n `\\\\b${varName}\\\\s*(\\\\+=|\\\\-=|\\\\*=|\\\\/=)\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(compoundRegex, (match, op, value) => {\r\n return `${varName} ${op} ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n });\r\n\r\n return helperCode + transformed;\r\n};\r\n\r\nexport const loadScripts = async (\r\n host: HTMLElement | ShadowRoot,\r\n scripts: ScriptElement[],\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[] = [],\r\n conditionalVars: Set<string> = new Set()\r\n) => {\r\n if (!scripts?.length) return;\r\n\r\n const componentHost = getHostElement(host);\r\n\r\n for (const scriptDefinition of scripts) {\r\n if (scriptDefinition.content) {\r\n processScript(\r\n scriptDefinition.content,\r\n bindings,\r\n twoWayBindings,\r\n host,\r\n componentHost,\r\n conditionalVars\r\n );\r\n }\r\n }\r\n\r\n // Process all event handlers to bind them to the component\r\n processEventHandlers(host, componentHost);\r\n};\r\n\r\n/**\r\n * Loads a global external script (e.g., from CDN) and returns a promise that resolves when loaded.\r\n * Prevents duplicate script tags by checking if the script is already loaded.\r\n * @param src - The script URL\r\n * @param type - The script type (e.g., 'module', 'text/javascript')\r\n * @returns Promise that resolves when the script is loaded\r\n */\r\nconst loadGlobalScript = (src: string, type: string | null): Promise<void> => {\r\n return new Promise((resolve, reject) => {\r\n // Check if script is already loaded and ready\r\n const existingScript = document.querySelector(\r\n `script[src=\"${src}\"]`\r\n ) as HTMLScriptElement;\r\n if (existingScript) {\r\n // If script already loaded, check if it's ready\r\n if (existingScript.dataset.loaded === \"true\") {\r\n resolve();\r\n return;\r\n }\r\n\r\n // If it's loading, wait for it\r\n existingScript.addEventListener(\"load\", () => resolve(), { once: true });\r\n existingScript.addEventListener(\r\n \"error\",\r\n () => reject(new Error(`Failed to load external script: ${src}`)),\r\n { once: true }\r\n );\r\n return;\r\n }\r\n\r\n const script = document.createElement(\"script\");\r\n script.src = src;\r\n if (type) {\r\n script.type = type;\r\n }\r\n\r\n script.onload = () => {\r\n script.dataset.loaded = \"true\";\r\n resolve();\r\n };\r\n script.onerror = () =>\r\n reject(new Error(`Failed to load external script: ${src}`));\r\n\r\n document.head.appendChild(script);\r\n });\r\n};\r\n\r\nexport const loadExternalScripts = async (\r\n host: HTMLElement | ShadowRoot,\r\n externalScripts: ExternalScriptElement[],\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[] = [],\r\n conditionalVars: Set<string> = new Set(),\r\n componentSourcePath?: string\r\n) => {\r\n const componentHost = getHostElement(host);\r\n\r\n for (const s of externalScripts) {\r\n // Resolve script URL relative to the component's HTML file location\r\n // Convert relative path to absolute URL if needed\r\n let baseURL: string;\r\n if (componentSourcePath) {\r\n // If it's already an absolute URL, use it directly\r\n if (\r\n componentSourcePath.startsWith(\"http://\") ||\r\n componentSourcePath.startsWith(\"https://\")\r\n ) {\r\n baseURL = componentSourcePath;\r\n } else {\r\n // Convert relative path to absolute URL using window.location\r\n // Ensure the base URL ends with the component path including filename\r\n // so that relative paths like '../js/app.js' resolve correctly\r\n const fullComponentURL = new URL(\r\n componentSourcePath,\r\n window.location.href\r\n ).href;\r\n baseURL = fullComponentURL;\r\n }\r\n } else {\r\n baseURL = window.location.href;\r\n }\r\n\r\n const scriptURL = new URL(s.src, baseURL).href;\r\n\r\n if (s.external) {\r\n // Inject script tag to document for external CDN scripts (e.g., highlight.js, three.js)\r\n // These scripts load globally and don't need component-specific processing\r\n await loadGlobalScript(scriptURL, s.type);\r\n } else if (s.type === \"module\") {\r\n // For module scripts, load them normally as ES modules\r\n // The bind attribute is a signal that the user wants reactive bindings,\r\n // but ES modules can't be transformed the same way as regular scripts\r\n // So we store the context and let the module use helper functions\r\n const componentId = componentHost.tagName.toLowerCase();\r\n\r\n if (!(window as any).__ladrilloContexts) {\r\n (window as any).__ladrilloContexts = new Map();\r\n }\r\n\r\n // Store the component context so the module can access it\r\n (window as any).__ladrilloContexts.set(componentId, {\r\n host,\r\n shadowRoot: host instanceof ShadowRoot ? host : null,\r\n element: componentHost,\r\n state: (componentHost as any).state,\r\n setState: (componentHost as any).setState?.bind(componentHost),\r\n });\r\n\r\n // Load the module script normally\r\n const script = document.createElement(\"script\");\r\n script.type = \"module\";\r\n script.src = scriptURL;\r\n script.setAttribute(\"data-component\", componentId);\r\n document.head.appendChild(script);\r\n } else {\r\n // Fetch and process local non-module scripts through reactive processing\r\n await fetch(scriptURL)\r\n .then((response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n }\r\n const contentType = response.headers.get(\"content-type\");\r\n if (\r\n contentType &&\r\n !contentType.includes(\"javascript\") &&\r\n !contentType.includes(\"text/plain\")\r\n ) {\r\n throw new Error(`Expected JavaScript but got ${contentType}`);\r\n }\r\n return response.text();\r\n })\r\n .then((scriptContent) => {\r\n // Reuse the same processing logic as inline scripts\r\n processScript(\r\n scriptContent,\r\n bindings,\r\n twoWayBindings,\r\n host,\r\n componentHost,\r\n conditionalVars\r\n );\r\n })\r\n .catch((error) => {\r\n console.error(`Failed to load external script: ${s.src}`, error);\r\n });\r\n }\r\n }\r\n\r\n // Process all event handlers to bind them to the component\r\n processEventHandlers(host, componentHost);\r\n};\r\n","import {\r\n BindingDescriptor,\r\n LadrillosComponent,\r\n TwoWayBindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../types/LadrilloTypes\";\r\nimport { logger } from \"../utils/logger\";\r\nimport { loadStyles } from \"./css/cssParser\";\r\nimport { loadTemplate, extractConditionalVariables } from \"./html/htmlparser\";\r\nimport {\r\n renderBindings,\r\n setValue,\r\n renderConditionals,\r\n} from \"./html/htmlRenderer\";\r\nimport { loadExternalScripts, loadScripts } from \"./js/scriptParser\";\r\n\r\nexport const defineWebComponent = (\r\n component: LadrillosComponent,\r\n useShadowDOM: boolean\r\n) => {\r\n const { tagName, template, scripts, externalScripts, styles, sourcePath } =\r\n component;\r\n\r\n class ComponentElement extends HTMLElement {\r\n state: any;\r\n #bindings: BindingDescriptor[] = [];\r\n #twoWayBindings: TwoWayBindingDescriptor[] = [];\r\n #conditionals: ConditionalDescriptor[][] = [];\r\n #twoWayBindingCleanups: Array<() => void> = [];\r\n #sourcePath: string | undefined = sourcePath;\r\n\r\n constructor() {\r\n super();\r\n if (useShadowDOM) this.attachShadow({ mode: \"open\" });\r\n\r\n const internalState: any = {};\r\n\r\n // Wrap state in a Proxy to detect changes and trigger re-renders\r\n this.state = new Proxy(internalState, {\r\n set: (target, prop, value) => {\r\n const prev = target[prop as keyof typeof target];\r\n // Skip update if value hasn't changed (avoids unnecessary re-renders)\r\n if (Object.is(prev, value)) return true;\r\n\r\n target[prop as keyof typeof target] = value;\r\n\r\n // Auto-create property descriptor on component for direct access in with() scope\r\n if (!Object.getOwnPropertyDescriptor(this, prop)) {\r\n Object.defineProperty(this, prop, {\r\n get() {\r\n return this.state[prop];\r\n },\r\n set(val) {\r\n this.state[prop] = val;\r\n },\r\n enumerable: true,\r\n configurable: true,\r\n });\r\n }\r\n\r\n // Re-render all bindings with the updated state\r\n renderBindings(this.#bindings, this.state, this);\r\n // Re-render conditionals\r\n renderConditionals(this.#conditionals, this.state, this);\r\n // Update two-way bound elements\r\n this.#updateTwoWayBindings();\r\n return true;\r\n },\r\n });\r\n }\r\n /**\r\n * Updates component state with one or more key-value pairs\r\n * @param updates - Object containing state updates\r\n * @example\r\n * component.setState({ count: 5, name: 'John' })\r\n */\r\n setState(updates: Record<string, any>): void {\r\n Object.assign(this.state, updates);\r\n }\r\n\r\n static #parseAttributeValue(raw: string | null) {\r\n if (raw === null || raw === \"\") return null;\r\n if (raw === \"undefined\") return undefined;\r\n try {\r\n return JSON.parse(raw);\r\n } catch {\r\n return raw;\r\n }\r\n }\r\n\r\n // Invoked when element is added to the DOM\r\n async connectedCallback() {\r\n const host = useShadowDOM ? this.shadowRoot! : this;\r\n\r\n // Parse template and collect all data binding locations\r\n const { bindings, twoWayBindings, conditionals } = loadTemplate(\r\n host,\r\n template\r\n );\r\n this.#bindings = bindings;\r\n this.#twoWayBindings = twoWayBindings;\r\n this.#conditionals = conditionals;\r\n\r\n // Extract variables used in conditional expressions\r\n const conditionalVars = extractConditionalVariables(conditionals);\r\n\r\n // Inject component styles\r\n loadStyles(host, styles, useShadowDOM);\r\n\r\n // Sync initial state from HTML attributes (e.g., <my-component name=\"value\">)\r\n this._initializeStateFromAttributes();\r\n\r\n // Setup two-way bindings\r\n this._setupTwoWayBindings();\r\n\r\n // Load external scripts first (e.g., CDN libraries like highlight.js)\r\n // so they're available when inline scripts execute\r\n await loadExternalScripts(\r\n host,\r\n externalScripts,\r\n this.#bindings,\r\n this.#twoWayBindings,\r\n conditionalVars,\r\n this.#sourcePath\r\n );\r\n\r\n // Execute component scripts (event handlers, methods, etc.)\r\n // Pass conditional variables so they get mapped to state\r\n await loadScripts(\r\n host,\r\n scripts,\r\n this.#bindings,\r\n this.#twoWayBindings,\r\n conditionalVars\r\n );\r\n\r\n // Perform initial render with current state values (after scripts are ready)\r\n renderBindings(this.#bindings, this.state, this);\r\n renderConditionals(this.#conditionals, this.state, this);\r\n\r\n // Set up MutationObserver to watch for attribute changes\r\n this._setupAttributeObserver();\r\n }\r\n\r\n // Invoked when element is removed from the DOM\r\n disconnectedCallback() {\r\n // Clean up MutationObserver\r\n if ((this as any).__attributeObserver) {\r\n (this as any).__attributeObserver.disconnect();\r\n (this as any).__attributeObserver = null;\r\n }\r\n\r\n // Clean up two-way binding event listeners\r\n this.#twoWayBindingCleanups.forEach((cleanup) => {\r\n try {\r\n cleanup();\r\n } catch (error) {\r\n console.error(\"Error cleaning up two-way binding:\", error);\r\n }\r\n });\r\n this.#twoWayBindingCleanups = [];\r\n\r\n // Clean up EventBus subscriptions\r\n const unsubscribers = (this as any).__eventUnsubscribers;\r\n if (unsubscribers && Array.isArray(unsubscribers)) {\r\n unsubscribers.forEach((unsub: () => void) => {\r\n try {\r\n unsub();\r\n } catch (error) {\r\n console.error(\"Error unsubscribing from event:\", error);\r\n }\r\n });\r\n (this as any).__eventUnsubscribers = [];\r\n }\r\n }\r\n\r\n // Set up observer to watch for attribute changes\r\n _setupAttributeObserver() {\r\n const observer = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n if (mutation.type === \"attributes\" && mutation.attributeName) {\r\n const newValue = this.getAttribute(mutation.attributeName);\r\n this._handleAttributeChange(mutation.attributeName, newValue);\r\n }\r\n });\r\n });\r\n\r\n observer.observe(this, {\r\n attributes: true,\r\n attributeOldValue: true,\r\n });\r\n\r\n (this as any).__attributeObserver = observer;\r\n }\r\n\r\n // initializes the state from the attributes\r\n _initializeStateFromAttributes() {\r\n this.getAttributeNames().forEach((name) => {\r\n const raw = this.getAttribute(name);\r\n this._handleAttributeChange(name, raw);\r\n });\r\n }\r\n\r\n // Invoked when attributes are changed.\r\n _handleAttributeChange(name: string, raw: string | null) {\r\n if (name) {\r\n // remove \"this.state.\" prefix if it exists\r\n const STATE_PREFIX = \"this.state.\";\r\n if (name.startsWith(STATE_PREFIX)) {\r\n name = name.slice(STATE_PREFIX.length);\r\n }\r\n }\r\n const value = ComponentElement.#parseAttributeValue(raw);\r\n this.state[name] = value;\r\n }\r\n\r\n // Setup two-way data bindings for input elements with $bind\r\n _setupTwoWayBindings() {\r\n this.#twoWayBindings.forEach(\r\n ({ element, path, raw, isContentEditable }) => {\r\n // Initialize state property if it doesn't exist\r\n const currentValue = this._getNestedValue(path);\r\n if (currentValue === undefined) {\r\n setValue(this.state, path, \"\");\r\n }\r\n\r\n if (isContentEditable) {\r\n // Handle contenteditable elements\r\n const contentEditableEl = element as HTMLElement;\r\n\r\n // Initial sync from state to element\r\n contentEditableEl.textContent = this._getNestedValue(path) ?? \"\";\r\n\r\n // Listen for input changes and update state\r\n const handleInput = (e: Event) => {\r\n const target = e.target as HTMLElement;\r\n const newValue = target.textContent || \"\";\r\n\r\n // Update state using setValue to handle nested paths\r\n setValue(this.state, path, newValue);\r\n };\r\n\r\n contentEditableEl.addEventListener(\"input\", handleInput);\r\n\r\n // Store cleanup function\r\n const cleanup = () => {\r\n contentEditableEl.removeEventListener(\"input\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanup);\r\n } else {\r\n // Handle form input elements\r\n const inputEl = element as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n\r\n // Initial sync from state to element\r\n inputEl.value = this._getNestedValue(path) ?? \"\";\r\n\r\n // Listen for input changes and update state\r\n const handleInput = (e: Event) => {\r\n const target = e.target as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n const newValue = target.value;\r\n\r\n // Update state using setValue to handle nested paths\r\n setValue(this.state, path, newValue);\r\n };\r\n\r\n inputEl.addEventListener(\"input\", handleInput);\r\n\r\n // Store cleanup function for 'input' listener\r\n const cleanupInput = () => {\r\n inputEl.removeEventListener(\"input\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanupInput);\r\n\r\n // For select and certain input types, also listen to 'change'\r\n if (\r\n inputEl instanceof HTMLSelectElement ||\r\n (inputEl instanceof HTMLInputElement &&\r\n [\"checkbox\", \"radio\", \"file\"].includes(inputEl.type))\r\n ) {\r\n inputEl.addEventListener(\"change\", handleInput);\r\n\r\n // Store cleanup function for 'change' listener\r\n const cleanupChange = () => {\r\n inputEl.removeEventListener(\"change\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanupChange);\r\n }\r\n }\r\n }\r\n );\r\n }\r\n\r\n // Update two-way bound elements when state changes\r\n #updateTwoWayBindings() {\r\n this.#twoWayBindings.forEach(({ element, path, isContentEditable }) => {\r\n const value = this._getNestedValue(path);\r\n\r\n if (isContentEditable) {\r\n const contentEditableEl = element as HTMLElement;\r\n if (contentEditableEl.textContent !== value) {\r\n contentEditableEl.textContent = value ?? \"\";\r\n }\r\n } else {\r\n const inputEl = element as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n if (inputEl.value !== value) {\r\n inputEl.value = value ?? \"\";\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Helper to get nested value from state\r\n _getNestedValue(path: string[]): any {\r\n return path.reduce((acc, key) => {\r\n return acc?.[key];\r\n }, this.state);\r\n }\r\n }\r\n\r\n customElements.define(tagName, ComponentElement);\r\n logger.log(`Web component defined: <${tagName}></${tagName}>`);\r\n};\r\n"],"names":["loadStyles","target","cssText","useShadowDOM","styleEl","loadTemplate","host","template","bindings","scanBindings","twoWayBindings","scanTwoWayBindings","conditionals","scanConditionals","walker","node","matches","REGEX_PATTERNS","original","nodeBindings","match","raw","isFunction","path","p","el","attr","attrBindings","bindValue","allConditionals","processedElements","element","group","currentElement","hasIf","hasElseIf","hasElse","type","condition","placeholder","parent","nextSibling","descriptor","next","desc","extractConditionalVariables","conditionalGroups","variables","identifierRegex","keywords","rootVar","functionCache","maxFunctionCacheSize","getCachedFunction","expression","cached","compiledFunc","firstKey","getValue","ctx","acc","segment","setValue","value","lastKey","parentPath","current","renderBindings","context","component","binding","result","funcName","error","replacement","textNode","parentElement","isHTMLContent","evaluateCondition","processedCondition","renderConditionals","conditionMet","originalParent","shouldRender","isInDOM","_a","getHostElement","injectBindVariables","scriptContent","bindVarNames","errors","varName","componentInjections","extractStateBindings","conditionalVars","stateBindings","bindingNames","b","rootName","variableRegex","transformBoundAssignments","boundVarNames","transformed","incrementRegex","op","compoundRegex","assignmentRegex","processScript","componentHost","injectedCode","err","functionRegex","functionNames","functionName","attachFunctions","name","allBoundVars","attachStateBindings","transformedContent","wrappedScript","eventBus","processEventHandlers","eventType","attributeName","key","handlerCode","event","loadScripts","_0","_1","_2","_3","__async","scripts","scriptDefinition","loadGlobalScript","src","resolve","reject","existingScript","script","loadExternalScripts","externalScripts","componentSourcePath","s","baseURL","scriptURL","componentId","response","contentType","defineWebComponent","tagName","styles","sourcePath","_ComponentElement","__privateAdd","_ComponentElement_instances","_bindings","_twoWayBindings","_conditionals","_twoWayBindingCleanups","_sourcePath","internalState","prop","prev","val","__privateGet","__privateMethod","updateTwoWayBindings_fn","updates","__privateSet","cleanup","unsubscribers","unsub","observer","mutations","mutation","newValue","STATE_PREFIX","_ComponentElement_static","parseAttributeValue_fn","isContentEditable","contentEditableEl","handleInput","e","inputEl","_b","cleanupInput","cleanupChange","ComponentElement","logger"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ "use strict";var H=t=>{throw TypeError(t)};var F=(t,s,n)=>s.has(t)||H("Cannot "+n);var E=(t,s,n)=>(F(t,s,"read from private field"),n?n.call(t):s.get(t)),A=(t,s,n)=>s.has(t)?H("Cannot add the same private member more than once"):s instanceof WeakSet?s.add(t):s.set(t,n),R=(t,s,n,e)=>(F(t,s,"write to private field"),e?e.call(t,n):s.set(t,n),n),O=(t,s,n)=>(F(t,s,"access private method"),n);var L=(t,s,n)=>new Promise((e,r)=>{var o=l=>{try{c(n.next(l))}catch(d){r(d)}},i=l=>{try{c(n.throw(l))}catch(d){r(d)}},c=l=>l.done?e(l.value):Promise.resolve(l.value).then(o,i);c((n=n.apply(t,s)).next())});Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const V=require("./index-CXHidyhO.js"),K=(t,s,n)=>{if(!s)return;const e=document.createElement("style");e.textContent=s,n?t.appendChild(e):document.head.appendChild(e)},Q=(t,s)=>{t.innerHTML=s;const n=Y(t),e=tt(t),r=et(t);return{bindings:n,twoWayBindings:e,conditionals:r}},Y=t=>{const s=document.createTreeWalker(t,NodeFilter.SHOW_TEXT,null),n=[];let e;for(;e=s.nextNode();){const o=[...e.textContent.matchAll(V.REGEX_PATTERNS.bindings)];if(o.length>0){const i=e.textContent,c=o.map(l=>{const d=l[1].trim(),u=d.includes("("),b=u?[d.split("(")[0].trim()]:d.split(".").map(f=>f.trim());return{raw:d,path:b,isFunction:u}});n.push({node:e,bindings:c,original:i})}}return t.querySelectorAll("*").forEach(o=>{for(const i of o.attributes){if(i.name==="$if"||i.name==="$else-if"||i.name==="$else"||i.name==="$bind")continue;const c=[...i.value.matchAll(V.REGEX_PATTERNS.bindings)];if(c.length>0){const l=i.value,d=c.map(u=>{const b=u[1].trim(),f=b.includes("("),w=f?[b.split("(")[0].trim()]:b.split(".").map(v=>v.trim());return{raw:b,path:w,isFunction:f}});n.push({node:o,bindings:d,original:l,isAttribute:!0,attributeName:i.name})}}}),n},tt=t=>{const s=[];return t.querySelectorAll("[\\$bind]").forEach(e=>{const r=e.getAttribute("$bind");if(!r)return;const o=r.trim(),i=o.split(".").map(c=>c.trim());e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement?(s.push({element:e,path:i,raw:o,isContentEditable:!1}),e.removeAttribute("$bind")):e instanceof HTMLElement&&(e.hasAttribute("contenteditable")||e.isContentEditable)&&(s.push({element:e,path:i,raw:o,isContentEditable:!0}),e.removeAttribute("$bind"))}),s},et=t=>{const s=[],n=new Set;return t.querySelectorAll("[\\$if]").forEach(r=>{if(n.has(r))return;const o=[];let i=r;for(;i;){const c=i.hasAttribute("$if"),l=i.hasAttribute("$else-if"),d=i.hasAttribute("$else");if(!c&&!l&&!d)break;n.add(i);let u,b="";c?(u="if",b=i.getAttribute("$if")||"",i.removeAttribute("$if")):l?(u="else-if",b=i.getAttribute("$else-if")||"",i.removeAttribute("$else-if")):(u="else",i.removeAttribute("$else"));const f=document.createComment(`conditional:${u}:${b}`),w=i.parentElement||t,v=i.nextSibling;w.insertBefore(f,i);const $={element:i,condition:b.trim(),type:u,placeholder:f,group:[],originalParent:w,nextSibling:v};o.push($);const m=i.nextElementSibling;if(i.remove(),i=m,m&&!m.hasAttribute("$else-if")&&!m.hasAttribute("$else"))break}o.forEach(c=>{c.group=o}),s.push(o)}),s},nt=t=>{const s=new Set;return t.forEach(n=>{n.forEach(e=>{let r=e.condition;r=r.replace(/\{([^}]+)\}/g,"$1");const o=/\b([a-zA-Z_$][a-zA-Z0-9_$]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$]*)*)\b/g,i=new Set(["true","false","null","undefined","typeof","instanceof","new","return","if","else","for","while","do","switch","case","break","continue"]);let c;for(;(c=o.exec(r))!==null;){const d=c[1].split(".")[0];i.has(d)||s.add(d)}})}),s},_=new Map,st=100,ot=t=>{const s=_.get(t);if(s)return _.delete(t),_.set(t,s),s;const n=new Function("component",`with(component) { return ${t}; }`);if(_.size>=st){const e=_.keys().next().value;e&&_.delete(e)}return _.set(t,n),n},it=(t,s)=>s.reduce((n,e)=>{if(!(n==null||typeof n!="object"))return n[e]},t),W=(t,s,n)=>{if(s.length===0)return;const e=s[s.length-1],r=s.slice(0,-1);let o=t;for(const i of r)(o[i]===void 0||o[i]===null)&&(o[i]={}),o=o[i];o[e]=n},q=(t,s,n)=>{for(const e of t){let r=e.original;for(const{raw:o,path:i,isFunction:c}of e.bindings){let l;if(c)try{const u=i[0];typeof(n==null?void 0:n[u])=="function"?l=ot(o)(n):l=void 0}catch(u){console.error(`Error executing function binding {${o}}:`,u),l=void 0}else l=it(s,i);if(l===void 0)continue;const d=String(l!=null?l:"");r=r.replace(`{${o}}`,d)}if(e.node.nodeType===Node.TEXT_NODE){const o=e.node,i=o.parentElement,c=r.trim().startsWith("<")&&r.includes(">");i&&c?i.innerHTML=r:o.textContent=r}else{const o=e.node;e.isAttribute&&e.attributeName&&o.setAttribute(e.attributeName,r)}}},rt=(t,s,n)=>{if(!t)return!0;let e=t.trim();e=e.replace(/\{([^}]+)\}/g,"$1");try{return new Function("context","component",`
2
+ with (context) {
3
+ try {
4
+ return Boolean(${e});
5
+ } catch (e) {
6
+ return false;
7
+ }
8
+ }
9
+ `)(s,n)}catch(r){return console.error(`Error evaluating condition "${t}":`,r),!1}},M=(t,s,n)=>{var e;for(const r of t){let o=!1;for(const i of r){const{element:c,condition:l,type:d,placeholder:u,originalParent:b}=i;let f=!1;d==="else"?f=!o:o||(f=rt(l,s,n),f&&(o=!0));const w=c.parentNode!==null;f&&!w?(e=u.parentNode)==null||e.insertBefore(c,u.nextSibling):!f&&w&&c.remove()}}},I=t=>t instanceof ShadowRoot?t.host:t,ct=(t,s)=>{const n=new Set,e=[];s.forEach(({path:o})=>{const i=o[0];n.add(i)}),n.forEach(o=>{new RegExp(`(?:const|let|var)\\s+${o}\\s*=`,"g").test(t)&&e.push(`⚠️ Variable "${o}" is already bound via $bind and cannot be redeclared. Remove the declaration or use a different variable name.`)});const r=[];return n.forEach(o=>{r.push(`
10
+ if (!Object.getOwnPropertyDescriptor(component, '${o}')) {
11
+ Object.defineProperty(component, '${o}', {
12
+ get() { return this.state.${o}; },
13
+ set(val) { this.state.${o} = val; },
14
+ enumerable: true,
15
+ configurable: true
16
+ });
17
+ }
18
+ `)}),{injectedCode:"",componentInjections:r.join(`
19
+ `),bindVarNames:n,errors:e}},at=(t,s,n=new Set)=>{const e=[],r=new Set;s.forEach(c=>{c.bindings.forEach(l=>{const d=l.path[0];r.add(d)})}),n.forEach(c=>{r.add(c)});const o=/(?:const|let|var)\s+(\w+)\s*=\s*([^;]+);?/g;let i;for(;(i=o.exec(t))!==null;){const c=i[1];r.has(c)&&e.push(`component.state.${c} = ${c};`)}return{stateBindings:e,boundVarNames:r}},lt=(t,s)=>{if(s.size===0)return t;let n=t;return s.forEach(e=>{const r=new RegExp(`(?<!const\\s|let\\s|var\\s|\\.)\\b(\\+\\+|\\-\\-)${e}\\b|\\b${e}(\\+\\+|\\-\\-)`,"g");n=n.replace(r,c=>{if(c.startsWith("++")||c.startsWith("--"))return`${c.substring(0,2)}component.state.${e}`;{const l=c.substring(c.length-2);return`component.state.${e}${l}`}});const o=new RegExp(`(?<!const\\s|let\\s|var\\s|\\.)\\b${e}\\s*(\\+=|\\-=|\\*=|\\/=|%=|\\*\\*=|<<=|>>=|>>>=|&=|\\|=|\\^=)`,"g");n=n.replace(o,`component.state.${e}$1`);const i=new RegExp(`(?<!const\\s|let\\s|var\\s|\\.|\\+|\\-|\\*|\\/|%|<|>|&|\\||\\^)\\b${e}\\s*=\\s*([^=])`,"g");n=n.replace(i,`component.state.${e} = $1`)}),n},P=(t,s,n,e,r,o=new Set)=>{try{const{injectedCode:i,componentInjections:c,bindVarNames:l,errors:d}=ct(t,n);d.length>0&&(console.error("❌ $bind Variable Conflicts Detected:"),d.forEach(a=>console.error(a)));const u=/function\s+(\w+)|const\s+(\w+)\s*=\s*(?:\([^)]*\)|[\w\s]*)\s*=>/g,b=[];let f;for(;(f=u.exec(t))!==null;){const a=f[1]||f[2];a&&b.push(a)}const w=b.map(a=>`component.${a} = typeof ${a} !== 'undefined' ? ${a}.bind(component) : undefined;`).join(`
20
+ `),{stateBindings:v,boundVarNames:$}=at(t,s,o),m=new Set([...$,...l]),X=v.join(`
21
+ `),C=lt(t,m),Z=`
22
+ (function() {
23
+ // Create component scope with direct access to state
24
+ const component = this;
25
+ const $state = component.state;
26
+
27
+ // Define $bind variables on component object for event handler access
28
+ ${c}
29
+
30
+ // Provide framework utilities with $ prefix to avoid naming conflicts
31
+ const $setState = (updates) => component.setState(updates);
32
+
33
+ // Event bus methods for component communication
34
+ const $emit = (eventName, data) => arguments[2].emit(eventName, data);
35
+ const $listen = (eventName, callback) => {
36
+ const unsubscribe = arguments[2].listen(eventName, callback);
37
+ // Store unsubscribe function for cleanup on disconnect
38
+ if (!component.__eventUnsubscribers) {
39
+ component.__eventUnsubscribers = [];
40
+ }
41
+ component.__eventUnsubscribers.push(unsubscribe);
42
+ return unsubscribe;
43
+ };
44
+
45
+ // Also attach to component for event handler access
46
+ component.$emit = $emit;
47
+ component.$listen = $listen;
48
+
49
+ // Override querySelector/querySelectorAll to query within the component's host
50
+ const host = arguments[1];
51
+ const $querySelector = (selector) => host.querySelector(selector);
52
+ const $querySelectorAll = (selector) => host.querySelectorAll(selector);
53
+
54
+ // Execute script content within component scope so $bind variables are accessible
55
+ with(component) {
56
+ ${C}
57
+
58
+ // Auto-bind variables to component state (e.g., const name = "value" → this.state.name = "value")
59
+ ${X}
60
+
61
+ // Auto-attach all detected functions to component for onclick access
62
+ ${w}
63
+ }
64
+ }).call(arguments[0], arguments[0], arguments[1], arguments[2])
65
+ `;new Function(Z)(r,e,V.eventBus)}catch(i){console.error("Script execution failed:",i)}},U=(t,s)=>{["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","keydown","keyup","keypress","focus","blur","change","input","submit","reset","scroll","resize","load","unload","touchstart","touchend","touchmove","touchcancel","dragstart","drag","dragend","dragenter","dragover","dragleave","drop"].forEach(e=>{const r=`on${e}`;(t instanceof ShadowRoot?t.querySelectorAll(`[${r}]`):s.querySelectorAll(`[${r}]`)).forEach(i=>{const c=`${r}`;if(i[`__processed_${c}`])return;const l=i.getAttribute(r);l&&(i.removeAttribute(r),i.addEventListener(e,function(d){new Function("event","component",`
66
+ with(component) {
67
+ ${l}
68
+ }
69
+ `).call(this,d,s)}),i[`__processed_${c}`]=!0)})})},ut=(o,i,c,...l)=>L(null,[o,i,c,...l],function*(t,s,n,e=[],r=new Set){if(!(s!=null&&s.length))return;const d=I(t);for(const u of s)u.content&&P(u.content,n,e,t,d,r);U(t,d)}),dt=(t,s)=>new Promise((n,e)=>{const r=document.querySelector(`script[src="${t}"]`);if(r){if(r.dataset.loaded==="true"){n();return}r.addEventListener("load",()=>n(),{once:!0}),r.addEventListener("error",()=>e(new Error(`Failed to load external script: ${t}`)),{once:!0});return}const o=document.createElement("script");o.src=t,s&&(o.type=s),o.onload=()=>{o.dataset.loaded="true",n()},o.onerror=()=>e(new Error(`Failed to load external script: ${t}`)),document.head.appendChild(o)}),ft=(i,c,l,...d)=>L(null,[i,c,l,...d],function*(t,s,n,e=[],r=new Set,o){var b;const u=I(t);for(const f of s){let w;o?o.startsWith("http://")||o.startsWith("https://")?w=o:w=new URL(o,window.location.href).href:w=window.location.href;const v=new URL(f.src,w).href;if(f.external)yield dt(v,f.type);else if(f.type==="module"){const $=u.tagName.toLowerCase();window.__ladrilloContexts||(window.__ladrilloContexts=new Map),window.__ladrilloContexts.set($,{host:t,shadowRoot:t instanceof ShadowRoot?t:null,element:u,state:u.state,setState:(b=u.setState)==null?void 0:b.bind(u)});const m=document.createElement("script");m.type="module",m.src=v,m.setAttribute("data-component",$),document.head.appendChild(m)}else yield fetch(v).then($=>{if(!$.ok)throw new Error(`HTTP ${$.status}: ${$.statusText}`);const m=$.headers.get("content-type");if(m&&!m.includes("javascript")&&!m.includes("text/plain"))throw new Error(`Expected JavaScript but got ${m}`);return $.text()}).then($=>{P($,n,e,t,u,r)}).catch($=>{console.error(`Failed to load external script: ${f.src}`,$)})}U(t,u)}),ht=(t,s)=>{var d,u,b,f,w,v,z,m,D;const{tagName:n,template:e,scripts:r,externalScripts:o,styles:i,sourcePath:c}=t,C=class C extends HTMLElement{constructor(){super();A(this,m);A(this,d,[]);A(this,u,[]);A(this,b,[]);A(this,f,[]);A(this,w,c);s&&this.attachShadow({mode:"open"});const a={};this.state=new Proxy(a,{set:(h,p,g)=>{const y=h[p];return Object.is(y,g)||(h[p]=g,Object.getOwnPropertyDescriptor(this,p)||Object.defineProperty(this,p,{get(){return this.state[p]},set(N){this.state[p]=N},enumerable:!0,configurable:!0}),q(E(this,d),this.state,this),M(E(this,b),this.state,this),O(this,m,D).call(this)),!0}})}setState(a){Object.assign(this.state,a)}connectedCallback(){return L(this,null,function*(){const a=s?this.shadowRoot:this,{bindings:h,twoWayBindings:p,conditionals:g}=Q(a,e);R(this,d,h),R(this,u,p),R(this,b,g);const y=nt(g);K(a,i,s),this._initializeStateFromAttributes(),this._setupTwoWayBindings(),yield ft(a,o,E(this,d),E(this,u),y,E(this,w)),yield ut(a,r,E(this,d),E(this,u),y),q(E(this,d),this.state,this),M(E(this,b),this.state,this),this._setupAttributeObserver()})}disconnectedCallback(){this.__attributeObserver&&(this.__attributeObserver.disconnect(),this.__attributeObserver=null),E(this,f).forEach(h=>{try{h()}catch(p){console.error("Error cleaning up two-way binding:",p)}}),R(this,f,[]);const a=this.__eventUnsubscribers;a&&Array.isArray(a)&&(a.forEach(h=>{try{h()}catch(p){console.error("Error unsubscribing from event:",p)}}),this.__eventUnsubscribers=[])}_setupAttributeObserver(){const a=new MutationObserver(h=>{h.forEach(p=>{if(p.type==="attributes"&&p.attributeName){const g=this.getAttribute(p.attributeName);this._handleAttributeChange(p.attributeName,g)}})});a.observe(this,{attributes:!0,attributeOldValue:!0}),this.__attributeObserver=a}_initializeStateFromAttributes(){this.getAttributeNames().forEach(a=>{const h=this.getAttribute(a);this._handleAttributeChange(a,h)})}_handleAttributeChange(a,h){var g;if(a){const y="this.state.";a.startsWith(y)&&(a=a.slice(y.length))}const p=O(g=C,v,z).call(g,h);this.state[a]=p}_setupTwoWayBindings(){E(this,u).forEach(({element:a,path:h,raw:p,isContentEditable:g})=>{var N,j;if(this._getNestedValue(h)===void 0&&W(this.state,h,""),g){const S=a;S.textContent=(N=this._getNestedValue(h))!=null?N:"";const x=T=>{const k=T.target.textContent||"";W(this.state,h,k)};S.addEventListener("input",x);const B=()=>{S.removeEventListener("input",x)};E(this,f).push(B)}else{const S=a;S.value=(j=this._getNestedValue(h))!=null?j:"";const x=T=>{const k=T.target.value;W(this.state,h,k)};S.addEventListener("input",x);const B=()=>{S.removeEventListener("input",x)};if(E(this,f).push(B),S instanceof HTMLSelectElement||S instanceof HTMLInputElement&&["checkbox","radio","file"].includes(S.type)){S.addEventListener("change",x);const T=()=>{S.removeEventListener("change",x)};E(this,f).push(T)}}})}_getNestedValue(a){return a.reduce((h,p)=>h==null?void 0:h[p],this.state)}};d=new WeakMap,u=new WeakMap,b=new WeakMap,f=new WeakMap,w=new WeakMap,v=new WeakSet,z=function(a){if(a===null||a==="")return null;if(a!=="undefined")try{return JSON.parse(a)}catch(h){return a}},m=new WeakSet,D=function(){E(this,u).forEach(({element:a,path:h,isContentEditable:p})=>{const g=this._getNestedValue(h);if(p){const y=a;y.textContent!==g&&(y.textContent=g!=null?g:"")}else{const y=a;y.value!==g&&(y.value=g!=null?g:"")}})},A(C,v);let l=C;customElements.define(n,l),V.logger.log(`Web component defined: <${n}></${n}>`)};exports.defineWebComponent=ht;
70
+ //# sourceMappingURL=webcomponent-i9W7LUiv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webcomponent-i9W7LUiv.js","sources":["../src/core/css/cssParser.ts","../src/core/html/htmlparser.ts","../src/cache/functionCache.ts","../src/core/html/htmlRenderer.ts","../src/core/js/scriptParser.ts","../src/core/webcomponent.ts"],"sourcesContent":["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 {\r\n BindingDescriptor,\r\n TwoWayBindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { REGEX_PATTERNS } from \"../../utils/regex\";\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\nexport const loadTemplate = (\r\n host: HTMLElement | ShadowRoot,\r\n template: string\r\n): {\r\n bindings: BindingDescriptor[];\r\n twoWayBindings: TwoWayBindingDescriptor[];\r\n conditionals: ConditionalDescriptor[][];\r\n} => {\r\n host.innerHTML = template;\r\n\r\n const bindings = scanBindings(host);\r\n const twoWayBindings = scanTwoWayBindings(host);\r\n const conditionals = scanConditionals(host);\r\n\r\n return { bindings, twoWayBindings, conditionals };\r\n};\r\n\r\n/**\r\n * Traverses the DOM tree and collects all data binding expressions.\r\n * Looks for {property} placeholders in both text content and element attributes.\r\n */\r\nconst scanBindings = (host: HTMLElement | ShadowRoot): BindingDescriptor[] => {\r\n // TreeWalker efficiently traverses only text nodes\r\n const walker = document.createTreeWalker(host, NodeFilter.SHOW_TEXT, null);\r\n const bindings: BindingDescriptor[] = [];\r\n let node: Text | null;\r\n\r\n // Scan for text nodes with bindings\r\n // e.g. <p>{name}</p> or <span>{user.firstName}</span>\r\n while ((node = walker.nextNode() as Text | null)) {\r\n const matches = [...node.textContent.matchAll(REGEX_PATTERNS.bindings)];\r\n\r\n if (matches.length > 0) {\r\n // Store the original template text before any replacements\r\n const original = node.textContent;\r\n\r\n // Create one binding descriptor per node with all its placeholders\r\n const nodeBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n const isFunction = raw.includes(\"(\"); // Detect function calls like MyName(\"Peter\")\r\n\r\n // For functions, extract the function name as the path\r\n // For properties, split by dot notation\r\n const path = isFunction\r\n ? [raw.split(\"(\")[0].trim()] // Extract function name before (\r\n : raw.split(\".\").map((p) => p.trim());\r\n\r\n return { raw, path, isFunction };\r\n });\r\n\r\n bindings.push({ node, bindings: nodeBindings, original });\r\n }\r\n } // Scan for attributes with bindings\r\n // e.g. <img src=\"{imageUrl}\"> or <input value=\"{user.email}\">\r\n const elements = host.querySelectorAll(\"*\");\r\n elements.forEach((el) => {\r\n for (const attr of el.attributes) {\r\n // Skip conditional and special directive attributes\r\n if (\r\n attr.name === \"$if\" ||\r\n attr.name === \"$else-if\" ||\r\n attr.name === \"$else\" ||\r\n attr.name === \"$bind\"\r\n ) {\r\n continue;\r\n }\r\n\r\n const matches = [...attr.value.matchAll(REGEX_PATTERNS.bindings)];\r\n if (matches.length > 0) {\r\n // Store the original attribute value\r\n const original = attr.value;\r\n\r\n // Create one binding descriptor per attribute with all its placeholders\r\n const attrBindings = matches.map((match) => {\r\n const raw = match[1].trim();\r\n const isFunction = raw.includes(\"(\");\r\n\r\n const path = isFunction\r\n ? [raw.split(\"(\")[0].trim()]\r\n : raw.split(\".\").map((p) => p.trim());\r\n\r\n return { raw, path, isFunction };\r\n });\r\n\r\n bindings.push({\r\n node: el as unknown as Text,\r\n bindings: attrBindings,\r\n original,\r\n isAttribute: true,\r\n attributeName: attr.name,\r\n });\r\n }\r\n }\r\n });\r\n\r\n return bindings;\r\n};\r\n\r\n/**\r\n * Scans for elements with $bind attribute for two-way data binding.\r\n * e.g. <input $bind=\"inputText\"> or <input $bind=\"person.name\">\r\n * Now also supports contenteditable elements: <div contenteditable $bind=\"text\">\r\n */\r\nconst scanTwoWayBindings = (\r\n host: HTMLElement | ShadowRoot\r\n): TwoWayBindingDescriptor[] => {\r\n const twoWayBindings: TwoWayBindingDescriptor[] = [];\r\n const elements = host.querySelectorAll(\"[\\\\$bind]\");\r\n\r\n elements.forEach((el) => {\r\n const bindValue = el.getAttribute(\"$bind\");\r\n if (!bindValue) return;\r\n\r\n const raw = bindValue.trim();\r\n const path = raw.split(\".\").map((p) => p.trim());\r\n\r\n // Support form inputs (input, textarea, select)\r\n if (\r\n el instanceof HTMLInputElement ||\r\n el instanceof HTMLTextAreaElement ||\r\n el instanceof HTMLSelectElement\r\n ) {\r\n twoWayBindings.push({\r\n element: el,\r\n path,\r\n raw,\r\n isContentEditable: false,\r\n });\r\n el.removeAttribute(\"$bind\");\r\n }\r\n // Support contenteditable elements\r\n else if (\r\n el instanceof HTMLElement &&\r\n (el.hasAttribute(\"contenteditable\") || el.isContentEditable)\r\n ) {\r\n twoWayBindings.push({\r\n element: el,\r\n path,\r\n raw,\r\n isContentEditable: true,\r\n });\r\n el.removeAttribute(\"$bind\");\r\n }\r\n });\r\n\r\n return twoWayBindings;\r\n};\r\n\r\n/**\r\n * Scans for elements with $if, $else-if, and $else attributes for conditional rendering.\r\n * Groups related conditionals together (if → else-if → else chains).\r\n * e.g. <div $if=\"isVisible\">...</div> or <div $else-if=\"count > 5\">...</div>\r\n */\r\nconst scanConditionals = (\r\n host: HTMLElement | ShadowRoot\r\n): ConditionalDescriptor[][] => {\r\n const allConditionals: ConditionalDescriptor[][] = [];\r\n const processedElements = new Set<Element>();\r\n\r\n // Find all $if elements (start of conditional chains)\r\n const ifElements = host.querySelectorAll(\"[\\\\$if]\");\r\n\r\n ifElements.forEach((element) => {\r\n if (processedElements.has(element)) return;\r\n\r\n const group: ConditionalDescriptor[] = [];\r\n let currentElement: Element | null = element;\r\n\r\n // Process the $if and all following $else-if and $else siblings\r\n while (currentElement) {\r\n const hasIf = currentElement.hasAttribute(\"$if\");\r\n const hasElseIf = currentElement.hasAttribute(\"$else-if\");\r\n const hasElse = currentElement.hasAttribute(\"$else\");\r\n\r\n if (!hasIf && !hasElseIf && !hasElse) break;\r\n\r\n processedElements.add(currentElement);\r\n\r\n let type: \"if\" | \"else-if\" | \"else\";\r\n let condition = \"\";\r\n\r\n if (hasIf) {\r\n type = \"if\";\r\n condition = currentElement.getAttribute(\"$if\") || \"\";\r\n currentElement.removeAttribute(\"$if\");\r\n } else if (hasElseIf) {\r\n type = \"else-if\";\r\n condition = currentElement.getAttribute(\"$else-if\") || \"\";\r\n currentElement.removeAttribute(\"$else-if\");\r\n } else {\r\n type = \"else\";\r\n currentElement.removeAttribute(\"$else\");\r\n }\r\n\r\n // Create a comment placeholder to mark the position\r\n const placeholder = document.createComment(\r\n `conditional:${type}:${condition}`\r\n );\r\n\r\n const parent = currentElement.parentElement || host;\r\n const nextSibling = currentElement.nextSibling;\r\n\r\n // Insert placeholder before the element\r\n parent.insertBefore(placeholder, currentElement);\r\n\r\n const descriptor: ConditionalDescriptor = {\r\n element: currentElement as Element,\r\n condition: condition.trim(),\r\n type,\r\n placeholder,\r\n group: [], // Will be set after the group is complete\r\n originalParent: parent as Element | ShadowRoot,\r\n nextSibling,\r\n };\r\n\r\n group.push(descriptor);\r\n\r\n // Move to the next sibling to check for $else-if or $else\r\n const next: Element | null = currentElement.nextElementSibling;\r\n\r\n // Remove element from DOM initially\r\n currentElement.remove();\r\n\r\n currentElement = next;\r\n\r\n // If next element isn't $else-if or $else, stop the chain\r\n if (\r\n next &&\r\n !next.hasAttribute(\"$else-if\") &&\r\n !next.hasAttribute(\"$else\")\r\n ) {\r\n break;\r\n }\r\n }\r\n\r\n // Set the group reference for all descriptors in this chain\r\n group.forEach((desc) => {\r\n desc.group = group;\r\n });\r\n\r\n allConditionals.push(group);\r\n });\r\n\r\n return allConditionals;\r\n};\r\n\r\n/**\r\n * Extracts variable names from conditional expressions.\r\n * Removes curly braces and extracts identifiers.\r\n * e.g., \"{sending}\" → [\"sending\"], \"{count > 5}\" → [\"count\"]\r\n */\r\nexport const extractConditionalVariables = (\r\n conditionalGroups: ConditionalDescriptor[][]\r\n): Set<string> => {\r\n const variables = new Set<string>();\r\n\r\n conditionalGroups.forEach((group) => {\r\n group.forEach((descriptor) => {\r\n let condition = descriptor.condition;\r\n\r\n // Remove curly braces: {sending} → sending\r\n condition = condition.replace(/\\{([^}]+)\\}/g, \"$1\");\r\n\r\n // Extract variable names (identifiers)\r\n // Match JavaScript identifiers but exclude keywords and literals\r\n const identifierRegex =\r\n /\\b([a-zA-Z_$][a-zA-Z0-9_$]*(?:\\.[a-zA-Z_$][a-zA-Z0-9_$]*)*)\\b/g;\r\n const keywords = new Set([\r\n \"true\",\r\n \"false\",\r\n \"null\",\r\n \"undefined\",\r\n \"typeof\",\r\n \"instanceof\",\r\n \"new\",\r\n \"return\",\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 ]);\r\n\r\n let match;\r\n while ((match = identifierRegex.exec(condition)) !== null) {\r\n const identifier = match[1];\r\n const rootVar = identifier.split(\".\")[0]; // Get root variable name\r\n\r\n // Skip keywords and literals\r\n if (!keywords.has(rootVar)) {\r\n variables.add(rootVar);\r\n }\r\n }\r\n });\r\n });\r\n\r\n return variables;\r\n};\r\n","/**\r\n * Cache for compiled function expressions used in template bindings.\r\n * Prevents memory leaks by reusing Function objects for identical expressions.\r\n * Example: {MyName(\"Peter\")} compiles once and is reused on every render.\r\n */\r\nconst functionCache = new Map<string, Function>();\r\nconst maxFunctionCacheSize = 100; // Functions are small, can cache more\r\n\r\n/**\r\n * Gets or creates a cached function for evaluating template expressions.\r\n * Uses LRU pattern to limit cache size and prevent unbounded growth.\r\n * @param expression - The JavaScript expression to compile (e.g., 'MyName(\"Peter\")')\r\n * @returns Compiled Function object that can be executed with a component context\r\n */\r\nexport const getCachedFunction = (expression: string): Function => {\r\n const cached = functionCache.get(expression);\r\n\r\n if (cached) {\r\n // LRU: Move to end (most recently used position)\r\n functionCache.delete(expression);\r\n functionCache.set(expression, cached);\r\n return cached;\r\n }\r\n\r\n // Cache miss: compile new function\r\n const compiledFunc = new Function(\r\n \"component\",\r\n `with(component) { return ${expression}; }`\r\n );\r\n\r\n // Check cache size and evict least recently used if needed\r\n if (functionCache.size >= maxFunctionCacheSize) {\r\n const firstKey = functionCache.keys().next().value;\r\n if (firstKey) {\r\n functionCache.delete(firstKey);\r\n }\r\n }\r\n\r\n // Add as most recently used\r\n functionCache.set(expression, compiledFunc);\r\n return compiledFunc;\r\n};\r\n\r\n/**\r\n * Clears the function cache. Useful for testing or memory management.\r\n */\r\nexport const clearFunctionCache = (): void => {\r\n functionCache.clear();\r\n};\r\n\r\n/**\r\n * Gets the current function cache size for debugging/monitoring.\r\n */\r\nexport const getFunctionCacheSize = (): number => {\r\n return functionCache.size;\r\n};\r\n","import {\r\n BindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { getCachedFunction } from \"../../cache/functionCache\";\r\n\r\n/**\r\n * Safely retrieves a nested value from an object using a path array.\r\n * Example: getValue({ user: { name: 'John' } }, ['user', 'name']) returns 'John'\r\n */\r\nconst getValue = (ctx: unknown, path: string[]): unknown => {\r\n return path.reduce<unknown>((acc: unknown, segment: string) => {\r\n // Stop traversal if we hit null/undefined or non-object\r\n if (acc == null || typeof acc !== \"object\") return undefined;\r\n return (acc as Record<string, unknown>)[segment];\r\n }, ctx);\r\n};\r\n\r\n/**\r\n * Safely sets a nested value in an object using a path array.\r\n * Example: setValue({ user: {} }, ['user', 'name'], 'John') sets user.name to 'John'\r\n * Creates intermediate objects if they don't exist.\r\n */\r\nexport const setValue = (ctx: any, path: string[], value: unknown): void => {\r\n if (path.length === 0) return;\r\n\r\n // Navigate to the parent object\r\n const lastKey = path[path.length - 1];\r\n const parentPath = path.slice(0, -1);\r\n\r\n let current = ctx;\r\n\r\n // Create intermediate objects if needed\r\n for (const segment of parentPath) {\r\n if (current[segment] === undefined || current[segment] === null) {\r\n current[segment] = {};\r\n }\r\n current = current[segment];\r\n }\r\n\r\n // Set the final value\r\n current[lastKey] = value;\r\n};\r\n\r\n/**\r\n * Updates all DOM bindings with values from the current state context.\r\n * Replaces {property.path} placeholders in text nodes and element attributes.\r\n * Always renders from the original template to support reactive updates.\r\n */\r\nexport const renderBindings = (\r\n bindings: BindingDescriptor[],\r\n context: unknown,\r\n component?: any\r\n): void => {\r\n for (const binding of bindings) {\r\n // Start with the original template\r\n let result = binding.original;\r\n\r\n // Replace all placeholders in this node\r\n for (const { raw, path, isFunction } of binding.bindings) {\r\n let value: unknown;\r\n\r\n if (isFunction) {\r\n // Execute function calls like MyName(\"Peter\")\r\n try {\r\n // Get the function from the component\r\n const funcName = path[0];\r\n const func = component?.[funcName];\r\n\r\n if (typeof func === \"function\") {\r\n // Use cached function to prevent memory leaks\r\n const evalFunc = getCachedFunction(raw);\r\n value = evalFunc(component);\r\n } else {\r\n value = undefined;\r\n }\r\n } catch (error) {\r\n console.error(`Error executing function binding {${raw}}:`, error);\r\n value = undefined;\r\n }\r\n } else {\r\n // Regular property access\r\n value = getValue(context, path);\r\n }\r\n\r\n if (value === undefined) continue;\r\n const replacement = String(value ?? \"\");\r\n\r\n // Replace this specific placeholder\r\n result = result.replace(`{${raw}}`, replacement);\r\n }\r\n\r\n // Apply the final result to the DOM\r\n if (binding.node.nodeType === Node.TEXT_NODE) {\r\n const textNode = binding.node as Text;\r\n const parentElement = textNode.parentElement;\r\n\r\n // Check if this looks like HTML content\r\n const isHTMLContent =\r\n result.trim().startsWith(\"<\") && result.includes(\">\");\r\n\r\n // If parent element exists and content is HTML, render as HTML\r\n if (parentElement && isHTMLContent) {\r\n parentElement.innerHTML = result;\r\n } else {\r\n // Otherwise, use textContent for security\r\n textNode.textContent = result;\r\n }\r\n } else {\r\n // Handle attribute bindings (e.g., <img src=\"{imageUrl}\">)\r\n const element = binding.node as unknown as Element;\r\n if (binding.isAttribute && binding.attributeName) {\r\n element.setAttribute(binding.attributeName, result);\r\n }\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Evaluates a conditional expression in the context of the component.\r\n * Supports both simple boolean checks and complex expressions.\r\n * e.g. \"isVisible\", \"{isVisible}\", \"count > 5\", \"{count} > 5\"\r\n */\r\nconst evaluateCondition = (\r\n condition: string,\r\n context: unknown,\r\n component?: any\r\n): boolean => {\r\n if (!condition) return true; // $else has no condition\r\n\r\n // Remove curly braces if present: {sending} -> sending\r\n let processedCondition = condition.trim();\r\n\r\n // Replace all {variable} with just variable\r\n processedCondition = processedCondition.replace(/\\{([^}]+)\\}/g, \"$1\");\r\n\r\n try {\r\n // Replace variable references in the condition with their values\r\n // This is a simple approach - for production, consider a proper expression parser\r\n const func = new Function(\r\n \"context\",\r\n \"component\",\r\n `\r\n with (context) {\r\n try {\r\n return Boolean(${processedCondition});\r\n } catch (e) {\r\n return false;\r\n }\r\n }\r\n `\r\n );\r\n\r\n return func(context, component);\r\n } catch (error) {\r\n console.error(`Error evaluating condition \"${condition}\":`, error);\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Updates conditional rendering based on current state.\r\n * Shows/hides elements based on their $if, $else-if, $else conditions.\r\n */\r\nexport const renderConditionals = (\r\n conditionalGroups: ConditionalDescriptor[][],\r\n context: unknown,\r\n component?: any\r\n): void => {\r\n // Process each conditional group (if/else-if/else chain)\r\n for (const group of conditionalGroups) {\r\n let conditionMet = false;\r\n\r\n // Evaluate each condition in the group\r\n for (const descriptor of group) {\r\n const { element, condition, type, placeholder, originalParent } =\r\n descriptor;\r\n\r\n // Check if this condition should be rendered\r\n let shouldRender = false;\r\n\r\n if (type === \"else\") {\r\n // $else renders if no previous condition was met\r\n shouldRender = !conditionMet;\r\n } else if (!conditionMet) {\r\n // $if or $else-if: evaluate condition\r\n shouldRender = evaluateCondition(condition, context, component);\r\n if (shouldRender) conditionMet = true;\r\n }\r\n\r\n // Update DOM based on shouldRender\r\n const isInDOM = element.parentNode !== null;\r\n\r\n if (shouldRender && !isInDOM) {\r\n // Insert element after its placeholder\r\n placeholder.parentNode?.insertBefore(element, placeholder.nextSibling);\r\n } else if (!shouldRender && isInDOM) {\r\n // Remove element from DOM\r\n element.remove();\r\n }\r\n }\r\n }\r\n};\r\n","import {\r\n ScriptElement,\r\n BindingDescriptor,\r\n ExternalScriptElement,\r\n TwoWayBindingDescriptor,\r\n} from \"../../types/LadrilloTypes\";\r\nimport { eventBus } from \"../eventBus\";\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 * Injects $bind variables into the script scope and validates no conflicts exist.\r\n * Creates property descriptors that proxy to component.state for reactive access.\r\n */\r\nconst injectBindVariables = (\r\n scriptContent: string,\r\n twoWayBindings: TwoWayBindingDescriptor[]\r\n): {\r\n injectedCode: string;\r\n componentInjections: string;\r\n bindVarNames: Set<string>;\r\n errors: string[];\r\n} => {\r\n const bindVarNames = new Set<string>();\r\n const errors: string[] = [];\r\n\r\n // Extract all $bind variable names (root-level only, e.g., \"person\" from \"person.name\")\r\n twoWayBindings.forEach(({ path }) => {\r\n const rootVar = path[0];\r\n bindVarNames.add(rootVar);\r\n });\r\n\r\n // Check for conflicts - devs trying to redeclare $bind variables\r\n bindVarNames.forEach((varName) => {\r\n const redeclarationRegex = new RegExp(\r\n `(?:const|let|var)\\\\s+${varName}\\\\s*=`,\r\n \"g\"\r\n );\r\n\r\n if (redeclarationRegex.test(scriptContent)) {\r\n errors.push(\r\n `⚠️ Variable \"${varName}\" is already bound via $bind and cannot be redeclared. Remove the declaration or use a different variable name.`\r\n );\r\n }\r\n });\r\n\r\n // Create proxy getters/setters for each $bind variable in script scope\r\n const injections: string[] = [];\r\n const componentInjections: string[] = [];\r\n\r\n bindVarNames.forEach((varName) => {\r\n // Define on component object for event handler access via with(component)\r\n componentInjections.push(`\r\n if (!Object.getOwnPropertyDescriptor(component, '${varName}')) {\r\n Object.defineProperty(component, '${varName}', {\r\n get() { return this.state.${varName}; },\r\n set(val) { this.state.${varName} = val; },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n }\r\n `);\r\n });\r\n\r\n return {\r\n injectedCode: \"\", // No longer needed in script scope\r\n componentInjections: componentInjections.join(\"\\n\"),\r\n bindVarNames,\r\n errors,\r\n };\r\n};\r\n\r\n/**\r\n * Extracts variable declarations (const, let, var) from script content\r\n * that match the template bindings or conditionals, and returns code to bind them to state.\r\n * Only binds variables that are actually used in the template or conditionals.\r\n */\r\nconst extractStateBindings = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n conditionalVars: Set<string> = new Set()\r\n): { stateBindings: string[]; boundVarNames: Set<string> } => {\r\n const stateBindings: string[] = [];\r\n\r\n // Create a Set of all binding names used in the template for fast lookup\r\n const bindingNames = new Set<string>();\r\n bindings.forEach((binding) => {\r\n binding.bindings.forEach((b) => {\r\n // Extract the root property name (e.g., \"user.name\" → \"user\", \"count\" → \"count\")\r\n const rootName = b.path[0];\r\n bindingNames.add(rootName);\r\n });\r\n });\r\n\r\n // Add conditional variables to binding names\r\n conditionalVars.forEach((varName) => {\r\n bindingNames.add(varName);\r\n });\r\n\r\n // Match: const name = value; | let count = 0; | var items = [];\r\n const variableRegex = /(?:const|let|var)\\s+(\\w+)\\s*=\\s*([^;]+);?/g;\r\n\r\n let match;\r\n while ((match = variableRegex.exec(scriptContent)) !== null) {\r\n const varName = match[1];\r\n\r\n // Only auto-bind if this variable is used in a template binding\r\n if (bindingNames.has(varName)) {\r\n stateBindings.push(`component.state.${varName} = ${varName};`);\r\n }\r\n }\r\n\r\n return { stateBindings, boundVarNames: bindingNames };\r\n};\r\n\r\n/**\r\n * Transforms script content to redirect bound variable assignments to state.\r\n * Handles assignments, increments, decrements, and compound assignments.\r\n * Examples:\r\n * - \"name = value\" → \"component.state.name = value\"\r\n * - \"count++\" → \"component.state.count++\"\r\n * - \"count += 5\" → \"component.state.count += 5\"\r\n * This makes reactivity transparent - users don't need to know about state.\r\n */\r\nconst transformBoundAssignments = (\r\n scriptContent: string,\r\n boundVarNames: Set<string>\r\n): string => {\r\n if (boundVarNames.size === 0) return scriptContent;\r\n\r\n let transformed = scriptContent;\r\n\r\n boundVarNames.forEach((varName) => {\r\n // 1. Transform increment/decrement: count++ or count-- or ++count or --count\r\n const incrementRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.)\\\\b(\\\\+\\\\+|\\\\-\\\\-)${varName}\\\\b|\\\\b${varName}(\\\\+\\\\+|\\\\-\\\\-)`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(incrementRegex, (match) => {\r\n if (match.startsWith(\"++\") || match.startsWith(\"--\")) {\r\n // Prefix: ++count or --count\r\n const op = match.substring(0, 2);\r\n return `${op}component.state.${varName}`;\r\n } else {\r\n // Postfix: count++ or count--\r\n const op = match.substring(match.length - 2);\r\n return `component.state.${varName}${op}`;\r\n }\r\n });\r\n\r\n // 2. Transform compound assignments: count += 5, count -= 3, count *= 2, etc.\r\n const compoundRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.)\\\\b${varName}\\\\s*(\\\\+=|\\\\-=|\\\\*=|\\\\/=|%=|\\\\*\\\\*=|<<=|>>=|>>>=|&=|\\\\|=|\\\\^=)`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(\r\n compoundRegex,\r\n `component.state.${varName}$1`\r\n );\r\n\r\n // 3. Transform simple assignments: name = value\r\n // Must come last to avoid interfering with compound assignments\r\n const assignmentRegex = new RegExp(\r\n `(?<!const\\\\s|let\\\\s|var\\\\s|\\\\.|\\\\+|\\\\-|\\\\*|\\\\/|%|<|>|&|\\\\||\\\\^)\\\\b${varName}\\\\s*=\\\\s*([^=])`,\r\n \"g\"\r\n );\r\n transformed = transformed.replace(\r\n assignmentRegex,\r\n `component.state.${varName} = $1`\r\n );\r\n });\r\n\r\n return transformed;\r\n};\r\n\r\n/**\r\n * Processes script content: extracts functions, binds state variables, and transforms assignments.\r\n * This is the core script processing logic that can be reused for both inline and external scripts.\r\n * @param scriptContent - The raw script content to process\r\n * @param bindings - Template bindings to determine which variables should be reactive\r\n * @param twoWayBindings - Two-way bound variables from $bind attributes\r\n * @param host - The host element or shadow root (for querySelector)\r\n * @param componentHost - The component element to execute the script on\r\n * @param conditionalVars - Variables used in conditional expressions ($if, $else-if)\r\n */\r\nconst processScript = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[],\r\n host: HTMLElement | ShadowRoot,\r\n componentHost: HTMLElement,\r\n conditionalVars: Set<string> = new Set()\r\n): void => {\r\n try {\r\n // Inject $bind variables and check for conflicts\r\n const { injectedCode, componentInjections, bindVarNames, errors } =\r\n injectBindVariables(scriptContent, twoWayBindings);\r\n\r\n // Log errors if any conflicts found\r\n if (errors.length > 0) {\r\n console.error(\"❌ $bind Variable Conflicts Detected:\");\r\n errors.forEach((err) => console.error(err));\r\n }\r\n\r\n // Extract function names from the script content\r\n const functionRegex =\r\n /function\\s+(\\w+)|const\\s+(\\w+)\\s*=\\s*(?:\\([^)]*\\)|[\\w\\s]*)\\s*=>/g;\r\n const functionNames: string[] = [];\r\n let match;\r\n\r\n while ((match = functionRegex.exec(scriptContent)) !== null) {\r\n const functionName = match[1] || match[2];\r\n if (functionName) {\r\n functionNames.push(functionName);\r\n }\r\n }\r\n\r\n // Auto-attach detected functions\r\n // Wrap functions to bind them to component and maintain variable access\r\n const attachFunctions = functionNames\r\n .map(\r\n (name) =>\r\n `component.${name} = typeof ${name} !== 'undefined' ? ${name}.bind(component) : undefined;`\r\n )\r\n .join(\"\\n \");\r\n\r\n // Extract and auto-bind variables to state (only those used in template bindings or conditionals)\r\n const { stateBindings, boundVarNames } = extractStateBindings(\r\n scriptContent,\r\n bindings,\r\n conditionalVars\r\n );\r\n\r\n // Merge bindVarNames with boundVarNames for transformation\r\n const allBoundVars = new Set([...boundVarNames, ...bindVarNames]);\r\n\r\n const attachStateBindings = stateBindings.join(\"\\n \");\r\n\r\n // Transform the script to make bound variable assignments reactive\r\n const transformedContent = transformBoundAssignments(\r\n scriptContent,\r\n allBoundVars\r\n );\r\n\r\n // Create a wrapper that captures functions and variables in component scope\r\n const wrappedScript = `\r\n (function() {\r\n // Create component scope with direct access to state\r\n const component = this;\r\n const $state = component.state;\r\n \r\n // Define $bind variables on component object for event handler access\r\n ${componentInjections}\r\n \r\n // Provide framework utilities with $ prefix to avoid naming conflicts\r\n const $setState = (updates) => component.setState(updates);\r\n \r\n // Event bus methods for component communication\r\n const $emit = (eventName, data) => arguments[2].emit(eventName, data);\r\n const $listen = (eventName, callback) => {\r\n const unsubscribe = arguments[2].listen(eventName, callback);\r\n // Store unsubscribe function for cleanup on disconnect\r\n if (!component.__eventUnsubscribers) {\r\n component.__eventUnsubscribers = [];\r\n }\r\n component.__eventUnsubscribers.push(unsubscribe);\r\n return unsubscribe;\r\n };\r\n \r\n // Also attach to component for event handler access\r\n component.$emit = $emit;\r\n component.$listen = $listen;\r\n \r\n // Override querySelector/querySelectorAll to query within the component's host\r\n const host = arguments[1];\r\n const $querySelector = (selector) => host.querySelector(selector);\r\n const $querySelectorAll = (selector) => host.querySelectorAll(selector);\r\n \r\n // Execute script content within component scope so $bind variables are accessible\r\n with(component) {\r\n ${transformedContent}\r\n \r\n // Auto-bind variables to component state (e.g., const name = \"value\" → this.state.name = \"value\")\r\n ${attachStateBindings}\r\n \r\n // Auto-attach all detected functions to component for onclick access\r\n ${attachFunctions}\r\n }\r\n }).call(arguments[0], arguments[0], arguments[1], arguments[2])\r\n `;\r\n\r\n const executor = new Function(wrappedScript);\r\n executor(componentHost, host, eventBus);\r\n } catch (error) {\r\n console.error(\"Script execution failed:\", error);\r\n }\r\n};\r\n\r\n/**\r\n * Processes inline event handlers (onclick, onkeyup, oninput, etc.) to bind them to the component context.\r\n * Removes inline event attributes and converts them to proper event listeners\r\n * that have access to the component scope.\r\n * @param host - The host element or shadow root\r\n * @param componentHost - The component element\r\n */\r\nconst processEventHandlers = (\r\n host: HTMLElement | ShadowRoot,\r\n componentHost: HTMLElement\r\n): void => {\r\n // All standard DOM events that can be handled as attributes\r\n const eventTypes = [\r\n \"click\",\r\n \"dblclick\",\r\n \"mousedown\",\r\n \"mouseup\",\r\n \"mouseover\",\r\n \"mouseout\",\r\n \"mousemove\",\r\n \"mouseenter\",\r\n \"mouseleave\",\r\n \"keydown\",\r\n \"keyup\",\r\n \"keypress\",\r\n \"focus\",\r\n \"blur\",\r\n \"change\",\r\n \"input\",\r\n \"submit\",\r\n \"reset\",\r\n \"scroll\",\r\n \"resize\",\r\n \"load\",\r\n \"unload\",\r\n \"touchstart\",\r\n \"touchend\",\r\n \"touchmove\",\r\n \"touchcancel\",\r\n \"dragstart\",\r\n \"drag\",\r\n \"dragend\",\r\n \"dragenter\",\r\n \"dragover\",\r\n \"dragleave\",\r\n \"drop\",\r\n ];\r\n\r\n // Add a WeakSet to track processed elements\r\n const processedElements = new WeakSet<Element>();\r\n\r\n eventTypes.forEach((eventType) => {\r\n const attributeName = `on${eventType}`;\r\n const elements =\r\n host instanceof ShadowRoot\r\n ? host.querySelectorAll(`[${attributeName}]`)\r\n : componentHost.querySelectorAll(`[${attributeName}]`);\r\n\r\n elements.forEach((element) => {\r\n // Create a unique key for this element + event combination\r\n const key = `${attributeName}`;\r\n if ((element as any)[`__processed_${key}`]) return; // Skip if already processed\r\n\r\n const handlerCode = element.getAttribute(attributeName);\r\n if (handlerCode) {\r\n element.removeAttribute(attributeName);\r\n (element as HTMLElement).addEventListener(\r\n eventType,\r\n function (this: HTMLElement, event: Event) {\r\n const func = new Function(\r\n \"event\",\r\n \"component\",\r\n `\r\n with(component) {\r\n ${handlerCode}\r\n }\r\n `\r\n );\r\n func.call(this, event, componentHost);\r\n }\r\n );\r\n\r\n // Mark as processed for this specific event\r\n (element as any)[`__processed_${key}`] = true;\r\n }\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Transforms a module script to make variable bindings reactive.\r\n * Detects variables used in template bindings and wraps assignments to update component state.\r\n * @param scriptContent - The module script content\r\n * @param bindings - Template bindings to determine which variables should be reactive\r\n * @param componentId - The component ID for accessing the context\r\n * @returns Transformed script content\r\n */\r\nconst transformModuleScript = (\r\n scriptContent: string,\r\n bindings: BindingDescriptor[],\r\n componentId: string\r\n): string => {\r\n // Extract variable names used in bindings\r\n const bindingVarNames = new Set<string>();\r\n bindings.forEach((binding) => {\r\n binding.bindings.forEach((b) => {\r\n if (!b.isFunction) {\r\n const rootName = b.path[0];\r\n bindingVarNames.add(rootName);\r\n }\r\n });\r\n });\r\n\r\n if (bindingVarNames.size === 0) {\r\n return scriptContent; // No transformations needed\r\n }\r\n\r\n // Add helper code at the beginning to get component context\r\n const helperCode = `\r\n// Auto-generated: Get component context for reactive bindings\r\nconst __getContext = () => window.__ladrilloContexts?.get('${componentId}');\r\nconst __component = __getContext()?.element;\r\n`;\r\n\r\n let transformed = scriptContent;\r\n\r\n // Transform variable declarations to initialize state\r\n bindingVarNames.forEach((varName) => {\r\n // Match: let varName = value; or const varName = value;\r\n const declRegex = new RegExp(\r\n `(let|const|var)\\\\s+${varName}\\\\s*=\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(declRegex, (match, keyword, value) => {\r\n return `${keyword} ${varName} = ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform assignments: varName = value\r\n // Make sure we don't match declarations (let/const/var) or object properties (obj.varName)\r\n const assignRegex = new RegExp(\r\n `(?<!let\\\\s|const\\\\s|var\\\\s|\\\\.)\\\\b${varName}\\\\s*=\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(assignRegex, (match, value) => {\r\n return `${varName} = ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform increment/decrement operators\r\n const incDecRegex = new RegExp(`\\\\b${varName}(\\\\+\\\\+|\\\\-\\\\-)`, \"g\");\r\n\r\n transformed = transformed.replace(incDecRegex, (match, op) => {\r\n return `${varName}${op};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n\r\n // Transform compound assignments\r\n const compoundRegex = new RegExp(\r\n `\\\\b${varName}\\\\s*(\\\\+=|\\\\-=|\\\\*=|\\\\/=)\\\\s*([^;]+);`,\r\n \"g\"\r\n );\r\n\r\n transformed = transformed.replace(compoundRegex, (match, op, value) => {\r\n return `${varName} ${op} ${value};\\nif (__component?.setState) __component.setState({ ${varName}: ${varName} });`;\r\n });\r\n });\r\n\r\n return helperCode + transformed;\r\n};\r\n\r\nexport const loadScripts = async (\r\n host: HTMLElement | ShadowRoot,\r\n scripts: ScriptElement[],\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[] = [],\r\n conditionalVars: Set<string> = new Set()\r\n) => {\r\n if (!scripts?.length) return;\r\n\r\n const componentHost = getHostElement(host);\r\n\r\n for (const scriptDefinition of scripts) {\r\n if (scriptDefinition.content) {\r\n processScript(\r\n scriptDefinition.content,\r\n bindings,\r\n twoWayBindings,\r\n host,\r\n componentHost,\r\n conditionalVars\r\n );\r\n }\r\n }\r\n\r\n // Process all event handlers to bind them to the component\r\n processEventHandlers(host, componentHost);\r\n};\r\n\r\n/**\r\n * Loads a global external script (e.g., from CDN) and returns a promise that resolves when loaded.\r\n * Prevents duplicate script tags by checking if the script is already loaded.\r\n * @param src - The script URL\r\n * @param type - The script type (e.g., 'module', 'text/javascript')\r\n * @returns Promise that resolves when the script is loaded\r\n */\r\nconst loadGlobalScript = (src: string, type: string | null): Promise<void> => {\r\n return new Promise((resolve, reject) => {\r\n // Check if script is already loaded and ready\r\n const existingScript = document.querySelector(\r\n `script[src=\"${src}\"]`\r\n ) as HTMLScriptElement;\r\n if (existingScript) {\r\n // If script already loaded, check if it's ready\r\n if (existingScript.dataset.loaded === \"true\") {\r\n resolve();\r\n return;\r\n }\r\n\r\n // If it's loading, wait for it\r\n existingScript.addEventListener(\"load\", () => resolve(), { once: true });\r\n existingScript.addEventListener(\r\n \"error\",\r\n () => reject(new Error(`Failed to load external script: ${src}`)),\r\n { once: true }\r\n );\r\n return;\r\n }\r\n\r\n const script = document.createElement(\"script\");\r\n script.src = src;\r\n if (type) {\r\n script.type = type;\r\n }\r\n\r\n script.onload = () => {\r\n script.dataset.loaded = \"true\";\r\n resolve();\r\n };\r\n script.onerror = () =>\r\n reject(new Error(`Failed to load external script: ${src}`));\r\n\r\n document.head.appendChild(script);\r\n });\r\n};\r\n\r\nexport const loadExternalScripts = async (\r\n host: HTMLElement | ShadowRoot,\r\n externalScripts: ExternalScriptElement[],\r\n bindings: BindingDescriptor[],\r\n twoWayBindings: TwoWayBindingDescriptor[] = [],\r\n conditionalVars: Set<string> = new Set(),\r\n componentSourcePath?: string\r\n) => {\r\n const componentHost = getHostElement(host);\r\n\r\n for (const s of externalScripts) {\r\n // Resolve script URL relative to the component's HTML file location\r\n // Convert relative path to absolute URL if needed\r\n let baseURL: string;\r\n if (componentSourcePath) {\r\n // If it's already an absolute URL, use it directly\r\n if (\r\n componentSourcePath.startsWith(\"http://\") ||\r\n componentSourcePath.startsWith(\"https://\")\r\n ) {\r\n baseURL = componentSourcePath;\r\n } else {\r\n // Convert relative path to absolute URL using window.location\r\n // Ensure the base URL ends with the component path including filename\r\n // so that relative paths like '../js/app.js' resolve correctly\r\n const fullComponentURL = new URL(\r\n componentSourcePath,\r\n window.location.href\r\n ).href;\r\n baseURL = fullComponentURL;\r\n }\r\n } else {\r\n baseURL = window.location.href;\r\n }\r\n\r\n const scriptURL = new URL(s.src, baseURL).href;\r\n\r\n if (s.external) {\r\n // Inject script tag to document for external CDN scripts (e.g., highlight.js, three.js)\r\n // These scripts load globally and don't need component-specific processing\r\n await loadGlobalScript(scriptURL, s.type);\r\n } else if (s.type === \"module\") {\r\n // For module scripts, load them normally as ES modules\r\n // The bind attribute is a signal that the user wants reactive bindings,\r\n // but ES modules can't be transformed the same way as regular scripts\r\n // So we store the context and let the module use helper functions\r\n const componentId = componentHost.tagName.toLowerCase();\r\n\r\n if (!(window as any).__ladrilloContexts) {\r\n (window as any).__ladrilloContexts = new Map();\r\n }\r\n\r\n // Store the component context so the module can access it\r\n (window as any).__ladrilloContexts.set(componentId, {\r\n host,\r\n shadowRoot: host instanceof ShadowRoot ? host : null,\r\n element: componentHost,\r\n state: (componentHost as any).state,\r\n setState: (componentHost as any).setState?.bind(componentHost),\r\n });\r\n\r\n // Load the module script normally\r\n const script = document.createElement(\"script\");\r\n script.type = \"module\";\r\n script.src = scriptURL;\r\n script.setAttribute(\"data-component\", componentId);\r\n document.head.appendChild(script);\r\n } else {\r\n // Fetch and process local non-module scripts through reactive processing\r\n await fetch(scriptURL)\r\n .then((response) => {\r\n if (!response.ok) {\r\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n }\r\n const contentType = response.headers.get(\"content-type\");\r\n if (\r\n contentType &&\r\n !contentType.includes(\"javascript\") &&\r\n !contentType.includes(\"text/plain\")\r\n ) {\r\n throw new Error(`Expected JavaScript but got ${contentType}`);\r\n }\r\n return response.text();\r\n })\r\n .then((scriptContent) => {\r\n // Reuse the same processing logic as inline scripts\r\n processScript(\r\n scriptContent,\r\n bindings,\r\n twoWayBindings,\r\n host,\r\n componentHost,\r\n conditionalVars\r\n );\r\n })\r\n .catch((error) => {\r\n console.error(`Failed to load external script: ${s.src}`, error);\r\n });\r\n }\r\n }\r\n\r\n // Process all event handlers to bind them to the component\r\n processEventHandlers(host, componentHost);\r\n};\r\n","import {\r\n BindingDescriptor,\r\n LadrillosComponent,\r\n TwoWayBindingDescriptor,\r\n ConditionalDescriptor,\r\n} from \"../types/LadrilloTypes\";\r\nimport { logger } from \"../utils/logger\";\r\nimport { loadStyles } from \"./css/cssParser\";\r\nimport { loadTemplate, extractConditionalVariables } from \"./html/htmlparser\";\r\nimport {\r\n renderBindings,\r\n setValue,\r\n renderConditionals,\r\n} from \"./html/htmlRenderer\";\r\nimport { loadExternalScripts, loadScripts } from \"./js/scriptParser\";\r\n\r\nexport const defineWebComponent = (\r\n component: LadrillosComponent,\r\n useShadowDOM: boolean\r\n) => {\r\n const { tagName, template, scripts, externalScripts, styles, sourcePath } =\r\n component;\r\n\r\n class ComponentElement extends HTMLElement {\r\n state: any;\r\n #bindings: BindingDescriptor[] = [];\r\n #twoWayBindings: TwoWayBindingDescriptor[] = [];\r\n #conditionals: ConditionalDescriptor[][] = [];\r\n #twoWayBindingCleanups: Array<() => void> = [];\r\n #sourcePath: string | undefined = sourcePath;\r\n\r\n constructor() {\r\n super();\r\n if (useShadowDOM) this.attachShadow({ mode: \"open\" });\r\n\r\n const internalState: any = {};\r\n\r\n // Wrap state in a Proxy to detect changes and trigger re-renders\r\n this.state = new Proxy(internalState, {\r\n set: (target, prop, value) => {\r\n const prev = target[prop as keyof typeof target];\r\n // Skip update if value hasn't changed (avoids unnecessary re-renders)\r\n if (Object.is(prev, value)) return true;\r\n\r\n target[prop as keyof typeof target] = value;\r\n\r\n // Auto-create property descriptor on component for direct access in with() scope\r\n if (!Object.getOwnPropertyDescriptor(this, prop)) {\r\n Object.defineProperty(this, prop, {\r\n get() {\r\n return this.state[prop];\r\n },\r\n set(val) {\r\n this.state[prop] = val;\r\n },\r\n enumerable: true,\r\n configurable: true,\r\n });\r\n }\r\n\r\n // Re-render all bindings with the updated state\r\n renderBindings(this.#bindings, this.state, this);\r\n // Re-render conditionals\r\n renderConditionals(this.#conditionals, this.state, this);\r\n // Update two-way bound elements\r\n this.#updateTwoWayBindings();\r\n return true;\r\n },\r\n });\r\n }\r\n /**\r\n * Updates component state with one or more key-value pairs\r\n * @param updates - Object containing state updates\r\n * @example\r\n * component.setState({ count: 5, name: 'John' })\r\n */\r\n setState(updates: Record<string, any>): void {\r\n Object.assign(this.state, updates);\r\n }\r\n\r\n static #parseAttributeValue(raw: string | null) {\r\n if (raw === null || raw === \"\") return null;\r\n if (raw === \"undefined\") return undefined;\r\n try {\r\n return JSON.parse(raw);\r\n } catch {\r\n return raw;\r\n }\r\n }\r\n\r\n // Invoked when element is added to the DOM\r\n async connectedCallback() {\r\n const host = useShadowDOM ? this.shadowRoot! : this;\r\n\r\n // Parse template and collect all data binding locations\r\n const { bindings, twoWayBindings, conditionals } = loadTemplate(\r\n host,\r\n template\r\n );\r\n this.#bindings = bindings;\r\n this.#twoWayBindings = twoWayBindings;\r\n this.#conditionals = conditionals;\r\n\r\n // Extract variables used in conditional expressions\r\n const conditionalVars = extractConditionalVariables(conditionals);\r\n\r\n // Inject component styles\r\n loadStyles(host, styles, useShadowDOM);\r\n\r\n // Sync initial state from HTML attributes (e.g., <my-component name=\"value\">)\r\n this._initializeStateFromAttributes();\r\n\r\n // Setup two-way bindings\r\n this._setupTwoWayBindings();\r\n\r\n // Load external scripts first (e.g., CDN libraries like highlight.js)\r\n // so they're available when inline scripts execute\r\n await loadExternalScripts(\r\n host,\r\n externalScripts,\r\n this.#bindings,\r\n this.#twoWayBindings,\r\n conditionalVars,\r\n this.#sourcePath\r\n );\r\n\r\n // Execute component scripts (event handlers, methods, etc.)\r\n // Pass conditional variables so they get mapped to state\r\n await loadScripts(\r\n host,\r\n scripts,\r\n this.#bindings,\r\n this.#twoWayBindings,\r\n conditionalVars\r\n );\r\n\r\n // Perform initial render with current state values (after scripts are ready)\r\n renderBindings(this.#bindings, this.state, this);\r\n renderConditionals(this.#conditionals, this.state, this);\r\n\r\n // Set up MutationObserver to watch for attribute changes\r\n this._setupAttributeObserver();\r\n }\r\n\r\n // Invoked when element is removed from the DOM\r\n disconnectedCallback() {\r\n // Clean up MutationObserver\r\n if ((this as any).__attributeObserver) {\r\n (this as any).__attributeObserver.disconnect();\r\n (this as any).__attributeObserver = null;\r\n }\r\n\r\n // Clean up two-way binding event listeners\r\n this.#twoWayBindingCleanups.forEach((cleanup) => {\r\n try {\r\n cleanup();\r\n } catch (error) {\r\n console.error(\"Error cleaning up two-way binding:\", error);\r\n }\r\n });\r\n this.#twoWayBindingCleanups = [];\r\n\r\n // Clean up EventBus subscriptions\r\n const unsubscribers = (this as any).__eventUnsubscribers;\r\n if (unsubscribers && Array.isArray(unsubscribers)) {\r\n unsubscribers.forEach((unsub: () => void) => {\r\n try {\r\n unsub();\r\n } catch (error) {\r\n console.error(\"Error unsubscribing from event:\", error);\r\n }\r\n });\r\n (this as any).__eventUnsubscribers = [];\r\n }\r\n }\r\n\r\n // Set up observer to watch for attribute changes\r\n _setupAttributeObserver() {\r\n const observer = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n if (mutation.type === \"attributes\" && mutation.attributeName) {\r\n const newValue = this.getAttribute(mutation.attributeName);\r\n this._handleAttributeChange(mutation.attributeName, newValue);\r\n }\r\n });\r\n });\r\n\r\n observer.observe(this, {\r\n attributes: true,\r\n attributeOldValue: true,\r\n });\r\n\r\n (this as any).__attributeObserver = observer;\r\n }\r\n\r\n // initializes the state from the attributes\r\n _initializeStateFromAttributes() {\r\n this.getAttributeNames().forEach((name) => {\r\n const raw = this.getAttribute(name);\r\n this._handleAttributeChange(name, raw);\r\n });\r\n }\r\n\r\n // Invoked when attributes are changed.\r\n _handleAttributeChange(name: string, raw: string | null) {\r\n if (name) {\r\n // remove \"this.state.\" prefix if it exists\r\n const STATE_PREFIX = \"this.state.\";\r\n if (name.startsWith(STATE_PREFIX)) {\r\n name = name.slice(STATE_PREFIX.length);\r\n }\r\n }\r\n const value = ComponentElement.#parseAttributeValue(raw);\r\n this.state[name] = value;\r\n }\r\n\r\n // Setup two-way data bindings for input elements with $bind\r\n _setupTwoWayBindings() {\r\n this.#twoWayBindings.forEach(\r\n ({ element, path, raw, isContentEditable }) => {\r\n // Initialize state property if it doesn't exist\r\n const currentValue = this._getNestedValue(path);\r\n if (currentValue === undefined) {\r\n setValue(this.state, path, \"\");\r\n }\r\n\r\n if (isContentEditable) {\r\n // Handle contenteditable elements\r\n const contentEditableEl = element as HTMLElement;\r\n\r\n // Initial sync from state to element\r\n contentEditableEl.textContent = this._getNestedValue(path) ?? \"\";\r\n\r\n // Listen for input changes and update state\r\n const handleInput = (e: Event) => {\r\n const target = e.target as HTMLElement;\r\n const newValue = target.textContent || \"\";\r\n\r\n // Update state using setValue to handle nested paths\r\n setValue(this.state, path, newValue);\r\n };\r\n\r\n contentEditableEl.addEventListener(\"input\", handleInput);\r\n\r\n // Store cleanup function\r\n const cleanup = () => {\r\n contentEditableEl.removeEventListener(\"input\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanup);\r\n } else {\r\n // Handle form input elements\r\n const inputEl = element as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n\r\n // Initial sync from state to element\r\n inputEl.value = this._getNestedValue(path) ?? \"\";\r\n\r\n // Listen for input changes and update state\r\n const handleInput = (e: Event) => {\r\n const target = e.target as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n const newValue = target.value;\r\n\r\n // Update state using setValue to handle nested paths\r\n setValue(this.state, path, newValue);\r\n };\r\n\r\n inputEl.addEventListener(\"input\", handleInput);\r\n\r\n // Store cleanup function for 'input' listener\r\n const cleanupInput = () => {\r\n inputEl.removeEventListener(\"input\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanupInput);\r\n\r\n // For select and certain input types, also listen to 'change'\r\n if (\r\n inputEl instanceof HTMLSelectElement ||\r\n (inputEl instanceof HTMLInputElement &&\r\n [\"checkbox\", \"radio\", \"file\"].includes(inputEl.type))\r\n ) {\r\n inputEl.addEventListener(\"change\", handleInput);\r\n\r\n // Store cleanup function for 'change' listener\r\n const cleanupChange = () => {\r\n inputEl.removeEventListener(\"change\", handleInput);\r\n };\r\n this.#twoWayBindingCleanups.push(cleanupChange);\r\n }\r\n }\r\n }\r\n );\r\n }\r\n\r\n // Update two-way bound elements when state changes\r\n #updateTwoWayBindings() {\r\n this.#twoWayBindings.forEach(({ element, path, isContentEditable }) => {\r\n const value = this._getNestedValue(path);\r\n\r\n if (isContentEditable) {\r\n const contentEditableEl = element as HTMLElement;\r\n if (contentEditableEl.textContent !== value) {\r\n contentEditableEl.textContent = value ?? \"\";\r\n }\r\n } else {\r\n const inputEl = element as\r\n | HTMLInputElement\r\n | HTMLTextAreaElement\r\n | HTMLSelectElement;\r\n if (inputEl.value !== value) {\r\n inputEl.value = value ?? \"\";\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Helper to get nested value from state\r\n _getNestedValue(path: string[]): any {\r\n return path.reduce((acc, key) => {\r\n return acc?.[key];\r\n }, this.state);\r\n }\r\n }\r\n\r\n customElements.define(tagName, ComponentElement);\r\n logger.log(`Web component defined: <${tagName}></${tagName}>`);\r\n};\r\n"],"names":["loadStyles","target","cssText","useShadowDOM","styleEl","loadTemplate","host","template","bindings","scanBindings","twoWayBindings","scanTwoWayBindings","conditionals","scanConditionals","walker","node","matches","REGEX_PATTERNS","original","nodeBindings","match","raw","isFunction","path","p","el","attr","attrBindings","bindValue","allConditionals","processedElements","element","group","currentElement","hasIf","hasElseIf","hasElse","type","condition","placeholder","parent","nextSibling","descriptor","next","desc","extractConditionalVariables","conditionalGroups","variables","identifierRegex","keywords","rootVar","functionCache","maxFunctionCacheSize","getCachedFunction","expression","cached","compiledFunc","firstKey","getValue","ctx","acc","segment","setValue","value","lastKey","parentPath","current","renderBindings","context","component","binding","result","funcName","error","replacement","textNode","parentElement","isHTMLContent","evaluateCondition","processedCondition","renderConditionals","conditionMet","originalParent","shouldRender","isInDOM","_a","getHostElement","injectBindVariables","scriptContent","bindVarNames","errors","varName","componentInjections","extractStateBindings","conditionalVars","stateBindings","bindingNames","b","rootName","variableRegex","transformBoundAssignments","boundVarNames","transformed","incrementRegex","op","compoundRegex","assignmentRegex","processScript","componentHost","injectedCode","err","functionRegex","functionNames","functionName","attachFunctions","name","allBoundVars","attachStateBindings","transformedContent","wrappedScript","eventBus","processEventHandlers","eventType","attributeName","key","handlerCode","event","loadScripts","_0","_1","_2","_3","__async","scripts","scriptDefinition","loadGlobalScript","src","resolve","reject","existingScript","script","loadExternalScripts","externalScripts","componentSourcePath","s","baseURL","scriptURL","componentId","response","contentType","defineWebComponent","tagName","styles","sourcePath","_ComponentElement","__privateAdd","_ComponentElement_instances","_bindings","_twoWayBindings","_conditionals","_twoWayBindingCleanups","_sourcePath","internalState","prop","prev","val","__privateGet","__privateMethod","updateTwoWayBindings_fn","updates","__privateSet","cleanup","unsubscribers","unsub","observer","mutations","mutation","newValue","STATE_PREFIX","_ComponentElement_static","parseAttributeValue_fn","isContentEditable","contentEditableEl","handleInput","e","inputEl","_b","cleanupInput","cleanupChange","ComponentElement","logger"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ladrillosjs",
3
- "version": "1.0.2",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "A lightweight, zero-dependency web component framework for building modular web applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,13 +11,13 @@
11
11
  ],
12
12
  "types": "dist/index.d.ts",
13
13
  "main": "./dist/ladrillosjs.cjs.js",
14
- "module": "./src/index.js",
14
+ "module": "./src/index.ts",
15
15
  "browser": "./dist/ladrillosjs.umd.js",
16
16
  "unpkg": "./dist/ladrillosjs.umd.js",
17
17
  "exports": {
18
18
  ".": {
19
19
  "browser": "./dist/ladrillosjs.umd.js",
20
- "import": "./src/index.js",
20
+ "import": "./src/index.ts",
21
21
  "require": "./dist/ladrillosjs.cjs.js"
22
22
  }
23
23
  },
@@ -35,11 +35,15 @@
35
35
  ],
36
36
  "author": "Daniel Rubio",
37
37
  "license": "MIT",
38
+ "engines": {
39
+ "node": ">=20.19.0 || >=22.12.0"
40
+ },
38
41
  "devDependencies": {
42
+ "@types/node": "^24.0.6",
39
43
  "@vitest/coverage-v8": "^3.1.2",
40
44
  "jsdom": "^26.1.0",
41
45
  "typescript": "^5.8.3",
42
- "vite": "^6.2.5",
46
+ "vite": "^7.1.9",
43
47
  "vitest": "^3.1.2"
44
48
  }
45
49
  }
@@ -1,6 +0,0 @@
1
- export function createStore(initialState?: {}): {
2
- getState(): {};
3
- setState(partial: any): void;
4
- subscribe(fn: any): () => boolean;
5
- reset(): void;
6
- };