coralite 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -279,10 +279,10 @@ Before submitting a Pull Request, navigate to the core package and ensure your c
279
279
  cd packages/coralite
280
280
 
281
281
  # Run the unit test suite
282
- pnpm run test-unit
282
+ pnpm run test:unit
283
283
 
284
284
  # Run the end-to-end test suite
285
- pnpm run test-e2e
285
+ pnpm run test:e2e
286
286
 
287
287
  # Run the performance benchmarks (highly recommended if modifying the AST or Plugin core)
288
288
  pnpm run bench
@@ -1 +1 @@
1
- {"version":3,"file":"coralite-element.d.ts","sourceRoot":"","sources":["../../lib/coralite-element.js"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,8BAJW,GAAG,QACH,WAAS,MAAM,GACb,GAAG,CAmBf;AAimBD;;;;;;;;;;;GAWG;AACH,6CATW,wBAAwB,kBACxB,WAAS,IAAI,UAErB;IAAyE,uBAAuB,GAAxF,KAAK,CAAC,iDAAiD,CAAC;IACQ,sBAAsB,GAAtF,KAAK,CAAC,gDAAgD,CAAC;IACC,cAAc,GAAtE,KAAK,CAAC,wCAAwC,CAAC;CACvD,kBAAQ,MAAO,IAAI,GACT,OAAO,eAAe,CA+BlC;AAxoBD;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH;IAOI;;;;OAIG;IACH,4BAHU,eAAe,GAAC,IAAI,CAGF;IAE5B;;;;OAIG;IACH,uBAHU,MAAM,GAAC,IAAI,CAGE;IAEvB;;;;OAIG;IACH,kBAHU,MAAO,IAAI,CAGH;IAElB;;;;OAIG;IACH,qBAHU,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAG1D;IAEnB;;;;OAIG;IACH,4BAHU,OAAO,CAGY;IAE7B;;;;OAIG;IACH,iCAHU,MAAM,GAAC,IAAI,CAGY;IAEjC;;;OAGG;IACH,qBAHU,gBAAgB,GAAC,IAAI,CAGV;IAErB;;;;OAIG;IACH,gCAHU,WAAS,IAAI,CAGS;IAEhC;;;;OAIG;IACH,mCAHU;YAAQ,MAAM,GAAE,eAAe;KAAC,GAAC,IAAI,CAGZ;IAEnC;;;;;;;;OAQG;IACH,kBAPU;QACL,uBAAuB,EAAE,KAAK,CAAC,iDAAiD,CAAC,CAAC;QAClF,sBAAsB,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChF,cAAc,EAAE,KAAK,CAAC,wCAAwC,CAAC,CAAA;KAChE,CAOH;IAED;;;OAGG;IACH,kBAFU,wBAAwB,GAAC,IAAI,CAEX;IAE5B;;;;OAIG;IACH,0BAHU,MAAO,IAAI,CAGK;IAG5B;;;;OAIG;IACH,0BAsDC;IAED;;;;;OAKG;IACH,sCAkBC;IAED;;;;;;;OAOG;IACH,+BAJW,MAAM,UACN,MAAM,GAAC,IAAI,UACX,MAAM,GAAC,IAAI,QAWrB;IAED;;;;;;OAMG;IACH,oBA0EC;IAED;;;;;;OAMG;IACH,6BAYC;IAED;;;;;OAKG;IACH,oBAHW,MAAM,EAAE,GACN,IAAI,GAAC,IAAI,CAYrB;IAED;;;;OAIG;IACH,uBAiCC;IAED;;;;OAIG;IACH,wBASC;IAED;;;;;;;OAOG;IACH,mBA2GC;IAED;;;;OAIG;IACH,sBAqCC;IAED;;;;;;OAMG;IACH,cAqCC;CACF;;;;;iBA3lBa,MAAM;;;;mBACN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAhEV,oBAAoB;sEAApB,oBAAoB;8DAApB,oBAAoB"}
1
+ {"version":3,"file":"coralite-element.d.ts","sourceRoot":"","sources":["../../lib/coralite-element.js"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,8BAJW,GAAG,QACH,WAAS,MAAM,GACb,GAAG,CAmBf;AA6mBD;;;;;;;;;;;GAWG;AACH,6CATW,wBAAwB,kBACxB,WAAS,IAAI,UAErB;IAAyE,uBAAuB,GAAxF,KAAK,CAAC,iDAAiD,CAAC;IACQ,sBAAsB,GAAtF,KAAK,CAAC,gDAAgD,CAAC;IACC,cAAc,GAAtE,KAAK,CAAC,wCAAwC,CAAC;CACvD,kBAAQ,MAAO,IAAI,GACT,OAAO,eAAe,CA+BlC;AAppBD;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH;IAOI;;;;OAIG;IACH,4BAHU,eAAe,GAAC,IAAI,CAGF;IAE5B;;;;OAIG;IACH,uBAHU,MAAM,GAAC,IAAI,CAGE;IAEvB;;;;OAIG;IACH,kBAHU,MAAO,IAAI,CAGH;IAElB;;;;OAIG;IACH,qBAHU,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAG1D;IAEnB;;;;OAIG;IACH,4BAHU,OAAO,CAGY;IAE7B;;;;OAIG;IACH,iCAHU,MAAM,GAAC,IAAI,CAGY;IAEjC;;;OAGG;IACH,qBAHU,gBAAgB,GAAC,IAAI,CAGV;IAErB;;;;OAIG;IACH,gCAHU,WAAS,IAAI,CAGS;IAEhC;;;;OAIG;IACH,mCAHU;YAAQ,MAAM,GAAE,eAAe;KAAC,GAAC,IAAI,CAGZ;IAEnC;;;;;;;;OAQG;IACH,kBAPU;QACL,uBAAuB,EAAE,KAAK,CAAC,iDAAiD,CAAC,CAAC;QAClF,sBAAsB,EAAE,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChF,cAAc,EAAE,KAAK,CAAC,wCAAwC,CAAC,CAAA;KAChE,CAOH;IAED;;;OAGG;IACH,kBAFU,wBAAwB,GAAC,IAAI,CAEX;IAE5B;;;;OAIG;IACH,0BAHU,MAAO,IAAI,CAGK;IAG5B;;;;OAIG;IACH,0BAsDC;IAED;;;;;OAKG;IACH,sCAkBC;IAED;;;;;;;OAOG;IACH,+BAJW,MAAM,UACN,MAAM,GAAC,IAAI,UACX,MAAM,GAAC,IAAI,QAWrB;IAED;;;;;;OAMG;IACH,oBA0EC;IAED;;;;;;OAMG;IACH,6BAYC;IAED;;;;;OAKG;IACH,oBAHW,MAAM,EAAE,GACN,IAAI,GAAC,IAAI,CAYrB;IAED;;;;OAIG;IACH,uBAiCC;IAED;;;;OAIG;IACH,wBASC;IAED;;;;;;;OAOG;IACH,mBAiHC;IAED;;;;OAIG;IACH,sBAqCC;IAED;;;;;;OAMG;IACH,cA2CC;CACF;;;;;iBAvmBa,MAAM;;;;mBACN,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uEAhEV,oBAAoB;sEAApB,oBAAoB;8DAApB,oBAAoB"}
@@ -446,6 +446,9 @@ var CoraliteElement = class extends HTMLElement {
446
446
  options: this.componentOptions
447
447
  });
448
448
  }
449
+ if (window.__coralite__ && window.__coralite__.lifecycle) {
450
+ window.__coralite__.lifecycle._markInstanceRendered(this);
451
+ }
449
452
  };
450
453
  if (hasPromise) {
451
454
  const keys = Object.keys(evaluatedTokens);
@@ -531,11 +534,14 @@ var CoraliteElement = class extends HTMLElement {
531
534
  }
532
535
  if (this.componentOptions.client) {
533
536
  try {
534
- this.componentOptions.client(localContext);
537
+ await this.componentOptions.client(localContext);
535
538
  } catch (error) {
536
539
  console.error(`Coralite Error: Component "${this.componentOptions.componentId}" script failed:`, error);
537
540
  }
538
541
  }
542
+ if (window.__coralite__ && window.__coralite__.lifecycle) {
543
+ window.__coralite__.lifecycle._markInstanceReady(this);
544
+ }
539
545
  }
540
546
  };
541
547
  function createCoraliteClass(options, contextGetter = null, hooks = {}, hydrationData = null) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../lib/utils/errors.js", "../../lib/utils/core.js", "../../lib/utils/client/inject.js", "../../lib/coralite-element.js"],
4
- "sourcesContent": ["\n/**\n * @import { CoraliteErrorData } from '../../types/index.js'\n */\n\n/**\n * Base error class for all Coralite-related errors.\n */\nexport class CoraliteError extends Error {\n /**\n * @param {string} message - The error message.\n * @param {Object} [options] - Additional options for the error.\n * @param {string} [options.componentId] - The ID of the component where the error occurred.\n * @param {string} [options.filePath] - The path to the file where the error occurred.\n * @param {string} [options.instanceId] - The unique ID of the component instance.\n * @param {string} [options.pagePath] - The path to the page being rendered.\n * @param {string} [options.path] - The path to the data property where the error occurred.\n * @param {number} [options.line] - The line number where the error occurred.\n * @param {number} [options.column] - The column number where the error occurred.\n * @param {string} [options.stackFile] - The file name from the stack trace.\n * @param {Error} [options.cause] - The original error that caused this error.\n */\n constructor (message, options = {}) {\n super(message, options)\n this.name = 'CoraliteError'\n this.isCoraliteError = true\n this.componentId = options.componentId\n this.filePath = options.filePath\n this.instanceId = options.instanceId\n this.pagePath = options.pagePath\n this.path = options.path\n this.line = options.line\n this.column = options.column\n this.stackFile = options.stackFile\n\n // Polyfill cause if necessary (node version differences)\n if (options.cause && !this.cause) {\n this.cause = options.cause\n }\n }\n}\n\n/**\n * Default error handler.\n * @param {CoraliteErrorData} data - The data object containing error details.\n */\nexport function defaultOnError ({ level, message, error }) {\n if (level === 'ERR') {\n if (error) {\n throw error\n }\n throw new CoraliteError(message)\n } else if (level === 'WARN') {\n console.warn(message)\n } else {\n console.log(message)\n }\n}\n\n/**\n * Handles errors using an optional callback or the default handler.\n * @param {Object} options - The options for handling the error.\n * @param {Function} [options.onErrorCallback] - The optional custom error callback function.\n * @param {CoraliteErrorData} options.data - The error data to be handled.\n */\nexport function handleError ({ onErrorCallback, data }) {\n const error = data.error\n if (error && 'isCoraliteError' in error && error.isCoraliteError) {\n const coraliteError = error\n // @ts-ignore\n data.componentId = data.componentId || coraliteError.componentId\n // @ts-ignore\n data.filePath = data.filePath || coraliteError.filePath\n // @ts-ignore\n data.instanceId = data.instanceId || coraliteError.instanceId\n // @ts-ignore\n data.pagePath = data.pagePath || coraliteError.pagePath\n // @ts-ignore\n data.path = data.path || coraliteError.path\n // @ts-ignore\n data.line = data.line || coraliteError.line\n // @ts-ignore\n data.column = data.column || coraliteError.column\n // @ts-ignore\n data.stackFile = data.stackFile || coraliteError.stackFile\n }\n\n if (onErrorCallback) {\n onErrorCallback(data)\n } else {\n defaultOnError(data)\n }\n}\n", "import { CoraliteError } from './errors.js'\n\n/**\n * @import {\n * CoraliteModule,\n * CoraliteComponent,\n * CoraliteComponentResult,\n * } from '../../types/index.js'\n */\n\nconst KEBAB_REGEX = /[-|:]([a-z])/g\n\n/**\n * Converts a kebab-case string to camelCase\n * @param {string} str - The kebab-case string to convert\n * @returns {string} - The camelCase version of the string\n */\nexport function kebabToCamel (str) {\n // replace each dash followed by a letter with the uppercase version of the letter\n return str.replace(KEBAB_REGEX, function (match, letter) {\n return letter.toUpperCase()\n })\n}\n\n/**\n * Converts all keys in an object from kebab-case to camelCase\n * @template T\n * @param {Record<string, T>} object - The object with kebab-case keys\n * @returns {Record<string, T>} - A new object with camelCase keys\n */\nexport function cleanKeys (object) {\n /** @type {Record<string, T>} */\n const result = {}\n\n for (const [key, value] of Object.entries(object)) {\n result[key] = value\n\n const camelKey = kebabToCamel(key)\n if (camelKey !== key) {\n result[camelKey] = value\n }\n }\n\n return result\n}\n\n/**\n * Recursively clones an object or array and normalizes any function state\n * it finds into a string representation that preserves standard function syntax,\n * bypassing ES6 shorthand method serialization issues.\n * @param {any} target - The object or array to normalize.\n * @param {Function} [transform] - Optional transform function for each node.\n * @param {WeakMap} [seen=new WeakMap()] - Map of seen objects to handle circular references.\n * @returns {any} A deeply cloned object with normalized functions.\n */\nexport function normalizeObjectFunctions (target, transform = null, seen = new WeakMap()) {\n if (typeof transform === 'function') {\n const transformed = transform(target)\n if (transformed !== target) {\n return transformed\n }\n }\n\n if (typeof target !== 'object' || target === null) {\n return target\n }\n\n if (seen.has(target)) {\n return seen.get(target)\n }\n\n if (Array.isArray(target)) {\n const arr = []\n seen.set(target, arr)\n for (let i = 0; i < target.length; i++) {\n arr.push(normalizeObjectFunctions(target[i], transform, seen))\n }\n return arr\n }\n\n const obj = {}\n seen.set(target, obj)\n for (const key in target) {\n if (Object.hasOwn(target, key)) {\n if (typeof target[key] === 'function') {\n const normalizedString = normalizeFunction(target[key])\n const originalFunction = target[key]\n\n const wrapper = function () {\n return originalFunction.apply(this, arguments)\n }\n wrapper.toString = () => normalizedString\n obj[key] = wrapper\n } else {\n obj[key] = normalizeObjectFunctions(target[key], transform, seen)\n }\n }\n }\n\n return obj\n}\n\n/**\n * Checks whether the given object is an object and has at least one own key.\n * @param {any} obj - The object to check.\n * @returns {boolean} True if the object is truthy and has keys, otherwise false.\n */\nexport function hasObjectKeys (obj) {\n return obj && typeof obj === 'object' && Object.keys(obj).length > 0\n}\n\n/**\n * Merges two arrays, returning a new array with unique items.\n * Uses JSON.stringify for deep comparison of object elements, preserving object uniqueness correctly.\n * @param {Array<any>} [arr1] - The first array.\n * @param {Array<any>} [arr2] - The second array.\n * @returns {Array<any>} A new array with unique values from both input arrays.\n */\nexport function mergeUniqueObjects (arr1, arr2) {\n const all = [...(arr1 || []), ...(arr2 || [])]\n const seen = new Set()\n return all.filter(item => {\n const key = typeof item === 'object' ? JSON.stringify(item) : item\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n\n/**\n * Normalizes function declarations to ensure consistent formatting.\n * Converts shorthand method syntax to full function declarations where needed,\n * while preserving arrow functions and existing full declarations.\n *\n * @param {Function} func - The function to normalize\n * @returns {string} The normalized function string representation\n */\nexport function normalizeFunction (func) {\n const original = func.toString().trim()\n\n const firstBrace = original.indexOf('{')\n const firstArrow = original.indexOf('=>')\n\n const isArrow = firstArrow !== -1 && (firstBrace === -1 || firstArrow < firstBrace)\n\n if (isArrow) {\n return original\n }\n\n // For non-arrows, extract header to check for shorthand\n const header = firstBrace !== -1 ? original.slice(0, firstBrace).trim() : original\n\n const isStandard = header.startsWith('function') || header.startsWith('async function')\n\n if (isStandard) {\n return original\n }\n\n // Handle Method Shorthand\n if (header.startsWith('async ')) {\n if (header.startsWith('async get ') || header.startsWith('async set ')) {\n return original\n }\n\n return original.replace(/^async\\s+([$\\w]+)\\s*\\(/, 'async function(')\n } else {\n if (header.startsWith('get ') || header.startsWith('set ')) {\n return original\n }\n\n return original.replace(/^([$\\w]+)\\s*\\(/, 'function(')\n }\n}\n\n\n/**\n * Recursively clones an AST node and its children, ensuring that\n * inner references (like parents and slots) point to the newly cloned nodes.\n *\n * @param {Map<Object, Object>} nodeMap - A map tracking original nodes to their newly cloned counterparts.\n * @param {Object} node - The current AST node being cloned.\n * @param {Object} [parent] - The parent node reference to assign to the clone.\n * @returns {Object} The newly cloned node.\n */\nexport function cloneNode (nodeMap, node, parent) {\n const newNode = Object.create(Object.getPrototypeOf(node))\n\n // Copy all own enumerable properties\n Object.assign(newNode, node)\n\n if (parent) {\n newNode.parent = parent\n }\n\n if (newNode.attribs) {\n newNode.attribs = { ...newNode.attribs }\n }\n\n // Register in map\n nodeMap.set(node, newNode)\n\n // Recursively clone children\n if (node.children) {\n const children = node.children\n const length = children.length\n const clonedChildren = new Array(length)\n newNode.children = clonedChildren\n\n for (let i = 0; i < length; i++) {\n const clonedChild = cloneNode(nodeMap, children[i], newNode)\n clonedChildren[i] = clonedChild\n if (i > 0) {\n clonedChild.prev = clonedChildren[i - 1]\n clonedChildren[i - 1].next = clonedChild\n }\n }\n }\n\n // Update slot references to point to new cloned nodes\n if (node.slots) {\n const slots = node.slots\n const length = slots.length\n const clonedSlots = new Array(length)\n for (let i = 0; i < length; i++) {\n const slot = slots[i]\n const clonedSlot = { ...slot }\n if (slot.node) {\n const clonedNode = nodeMap.get(slot.node)\n if (clonedNode) {\n clonedSlot.node = clonedNode\n }\n }\n clonedSlots[i] = clonedSlot\n }\n newNode.slots = clonedSlots\n }\n\n // Preserve the enhanced flag without re-running enhanceNode\n Object.defineProperty(newNode, '__coralite_enhanced__', {\n value: true,\n enumerable: false,\n configurable: true\n })\n\n return newNode\n}\n\n/**\n * Creates a shallow copy of a CoraliteModule with a deep clone of its DOM tree (template) and re-linked internal references to enable safe independent mutation.\n *\n * Top-level non-DOM state (id, path, script, isTemplate, lineOffset) are shallow copied. Nested objects within these state (e.g., path) remain shared references. Only DOM-related structures undergo deep cloning and reference re-linking to isolate mutations from the original module.\n *\n * @param {CoraliteModule} originalModule - Module to clone.\n * @returns {CoraliteModule}\n */\nexport function cloneModuleInstance (originalModule) {\n const nodeMap = new Map()\n\n // Clone the main template tree\n const newTemplate = cloneNode(nodeMap, originalModule.template, null)\n\n // Reconstruct the 'values' object\n const newValues = {\n attributes: originalModule.values.attributes.map(item => ({\n ...item,\n element: nodeMap.get(item.element)\n })),\n textNodes: originalModule.values.textNodes.map(item => ({\n ...item,\n textNode: nodeMap.get(item.textNode)\n })),\n refs: originalModule.values.refs.map(item => ({\n ...item,\n element: nodeMap.get(item.element)\n }))\n }\n\n // Reconstruct customElements list\n const newCustomElements = originalModule.customElements.map(el => nodeMap.get(el))\n\n // Reconstruct slotElements\n const newSlotElements = {}\n if (originalModule.slotElements) {\n for (const modId in originalModule.slotElements) {\n newSlotElements[modId] = {}\n const slotGroup = originalModule.slotElements[modId]\n\n for (const slotName in slotGroup) {\n const slotItem = slotGroup[slotName]\n newSlotElements[modId][slotName] = {\n ...slotItem,\n element: nodeMap.get(slotItem.element)\n }\n }\n }\n }\n\n // Return the new module structure\n return {\n ...originalModule,\n template: newTemplate,\n values: newValues,\n customElements: newCustomElements,\n // @ts-ignore\n slotElements: newSlotElements\n }\n}\n\n/**\n * Creates a deep copy of a CoraliteComponent with re-linked internal references to enable safe independent mutation.\n *\n * @param {CoraliteComponent & CoraliteComponentResult} originalDocument - Document to clone.\n * @returns {CoraliteComponent & CoraliteComponentResult}\n */\nexport function cloneComponentInstance (originalDocument) {\n const nodeMap = new Map()\n const newRoot = cloneNode(nodeMap, originalDocument.root, null)\n\n const newCustomElements = originalDocument.customElements.map(el => nodeMap.get(el))\n const newTempElements = originalDocument.tempElements ? originalDocument.tempElements.map(el => nodeMap.get(el)) : []\n const newSkipRenderElements = originalDocument.skipRenderElements ? originalDocument.skipRenderElements.map(el => nodeMap.get(el)) : []\n\n return {\n ...originalDocument,\n state: { ...originalDocument.state },\n root: newRoot,\n customElements: newCustomElements,\n tempElements: newTempElements,\n skipRenderElements: newSkipRenderElements\n }\n}\n\n/**\n * Calculates the DOM path from a node to the root.\n * @param {Object} node - The node to calculate the path for.\n * @param {Object} root - The root node.\n * @returns {Array<number>} An array of indices representing the path.\n */\nexport function getNodePath (node, root) {\n const path = []\n let current = node\n while (current && current !== root) {\n const parent = current.parent\n if (!parent) {\n break\n }\n const index = parent.children.indexOf(current)\n if (index === -1) {\n break\n }\n path.unshift(index)\n current = parent\n }\n return path\n}\n\n/**\n * Generates a hydration map for the client.\n * @param {Array<Object>} templateNodes - The component's template nodes.\n * @param {Object} templateValues - The component's template values.\n * @returns {Object} The hydration map.\n */\nexport function generateHydrationMap (templateNodes, templateValues) {\n const map = {\n texts: [],\n attributes: [],\n refs: []\n }\n\n if (!templateNodes || !templateValues) {\n return map\n }\n\n const root = templateNodes.length > 0 ? templateNodes[0].parent : { children: templateNodes }\n\n if (templateValues.textNodes) {\n for (const item of templateValues.textNodes) {\n if (item.textNode) {\n const isHtml = item.type === 'html'\n const targetNode = isHtml ? item.textNode.parent : item.textNode\n\n map.texts.push({\n path: getNodePath(targetNode, root),\n template: item.textNode.data,\n type: isHtml ? 'html' : 'text'\n })\n }\n }\n }\n\n if (templateValues.attributes) {\n for (const item of templateValues.attributes) {\n if (item.element && item.element.attribs) {\n const originalValue = item.element.attribs[item.name]\n map.attributes.push({\n path: getNodePath(item.element, root),\n name: item.name,\n template: originalValue\n })\n }\n }\n }\n\n if (templateValues.refs) {\n for (const item of templateValues.refs) {\n if (item.element) {\n map.refs.push({\n path: getNodePath(item.element, root),\n name: item.name\n })\n }\n }\n }\n\n return map\n}\n\n/**\n * Recursively adds a component and its dependencies to a tracking object.\n *\n * @param {string} componentId - The ID of the component to add.\n * @param {Object.<string, boolean>} processed - The object tracking processed components.\n * @param {Object.<string, any>} sharedFunctions - The map of shared component functions.\n */\nexport function addComponentAndDependencies (componentId, processed, sharedFunctions) {\n if (!processed[componentId] && sharedFunctions[componentId]) {\n processed[componentId] = true\n\n // Add all dependencies of this component\n const dependencies = sharedFunctions[componentId].components || []\n for (const depId of dependencies) {\n addComponentAndDependencies(depId, processed, sharedFunctions)\n }\n }\n}\n\n/**\n * Recursively clones an AST node and its children, stripping circular references\n * and assigning unique IDs for client-side hydration.\n *\n * @param {Array<Object>} nodes - The nodes to clean.\n * @param {WeakMap} nodeMap - Map to track original nodes to their unique IDs.\n * @param {Object} state - Object containing the current node counter.\n * @returns {Array<Object>|null} The cleaned AST nodes.\n */\nexport function cleanAST (nodes, nodeMap, state) {\n if (!nodes) {\n return null\n }\n\n return nodes.map((node) => {\n const cloned = { ...node }\n // Assign unique ID for token mapping\n const id = state.counter++\n nodeMap.set(node, id)\n cloned._id = id\n\n // Remove circular references\n delete cloned.parent\n delete cloned.prev\n delete cloned.next\n delete cloned.slots\n\n if (cloned.children) {\n cloned.children = cleanAST(cloned.children, nodeMap, state)\n }\n return cloned\n })\n}\n\n/**\n * Cleans the template values object, mapping original node references to unique IDs.\n *\n * @param {Object} values - The values object to clean.\n * @param {WeakMap} nodeMap - Map of original nodes to their unique IDs.\n * @returns {Object|null} The cleaned values object.\n */\nexport function cleanValues (values, nodeMap) {\n if (!values) {\n return null\n }\n\n const result = { ...values }\n\n if (result.attributes) {\n result.attributes = result.attributes.map(item => {\n const cloned = { ...item }\n cloned.elementId = nodeMap.get(item.element)\n delete cloned.element\n return cloned\n })\n }\n\n if (result.textNodes) {\n result.textNodes = result.textNodes.map(item => {\n const cloned = { ...item }\n cloned.textNodeId = nodeMap.get(item.textNode)\n delete cloned.textNode\n return cloned\n })\n }\n\n if (result.refs) {\n result.refs = result.refs.map(item => {\n const cloned = { ...item }\n cloned.elementId = nodeMap.get(item.element)\n delete cloned.element\n return cloned\n })\n }\n return result\n}\n\n/**\n * Safely merges partial plugin updates into the main context object.\n * Deeply merges plain objects and overwrites other types (arrays, primitives, etc.).\n *\n * @param {any} current - The current state object.\n * @param {any} patch - The patch object containing updates.\n * @returns {any} The newly merged state object.\n */\nexport function mergePluginState (current, patch) {\n if (!patch || typeof patch !== 'object') {\n return current\n }\n\n const result = { ...current }\n\n for (const key of Object.keys(patch)) {\n const patchValue = patch[key]\n const currentValue = result[key]\n\n // If both are plain objects, merge them deeply\n if (\n patchValue && typeof patchValue === 'object' && !Array.isArray(patchValue) &&\n currentValue && typeof currentValue === 'object' && !Array.isArray(currentValue)\n ) {\n result[key] = mergePluginState(currentValue, patchValue)\n } else {\n // Otherwise, overwrite (Arrays, strings, numbers, etc.)\n result[key] = patchValue\n }\n }\n\n return result\n}\n\n/**\n * Creates a reactive proxy that triggers a callback on changes.\n * Supports deep reactivity via lazy proxying of nested objects.\n *\n * @param {Object} target - The object to proxy.\n * @param {Function} onChange - Callback triggered when a property is set or deleted.\n * @param {WeakMap} [proxies=new WeakMap()] - Cache for existing proxies to handle circular references and identity.\n * @returns {Proxy} The reactive proxy.\n */\nexport function createReactiveProxy (target, onChange, proxies = new WeakMap()) {\n if (proxies.has(target)) {\n return proxies.get(target)\n }\n\n const handler = {\n get (target, property, receiver) {\n const value = Reflect.get(target, property, receiver)\n if (value !== null && typeof value === 'object' && !(typeof Node !== 'undefined' && value instanceof Node)) {\n return createReactiveProxy(value, onChange, proxies)\n }\n return value\n },\n set (target, property, value, receiver) {\n const oldValue = target[property]\n if (oldValue === value && property in target) {\n return true\n }\n\n const result = Reflect.set(target, property, value, receiver)\n if (result) {\n onChange({\n property,\n value,\n oldValue,\n target\n })\n }\n return result\n },\n deleteProperty (target, property) {\n const hadProperty = Object.prototype.hasOwnProperty.call(target, property)\n const oldValue = target[property]\n const result = Reflect.deleteProperty(target, property)\n if (result && hadProperty) {\n onChange({\n property,\n value: undefined,\n oldValue,\n target,\n deleted: true\n })\n }\n return result\n }\n }\n\n const proxy = new Proxy(target, handler)\n proxies.set(target, proxy)\n return proxy\n}\n\n/**\n * Creates a read-only proxy that throws on mutation attempts.\n * @param {Object} target - The object to proxy.\n * @param {WeakMap} [proxies=new WeakMap()] - Cache for existing proxies.\n * @returns {Proxy} The read-only proxy.\n */\nexport function createReadOnlyProxy (target, proxies = new WeakMap()) {\n if (proxies.has(target)) {\n return proxies.get(target)\n }\n\n const handler = {\n get (target, property, receiver) {\n const value = Reflect.get(target, property, receiver)\n if (value !== null && typeof value === 'object' && !(typeof Node !== 'undefined' && value instanceof Node)) {\n return createReadOnlyProxy(value, proxies)\n }\n return value\n },\n set () {\n throw new CoraliteError('Cannot mutate state inside a getter. State is read-only here.')\n },\n deleteProperty () {\n throw new CoraliteError('Cannot delete state inside a getter. State is read-only here.')\n }\n }\n\n const proxy = new Proxy(target, handler)\n\n proxies.set(target, proxy)\n\n return proxy\n}\n\n/**\n * Defines a Coralite component.\n * On the client, this acts as an identity function for type safety and HRM.\n * @param {Object} options - Component options\n * @returns {Object} The component options\n */\nexport function defineComponent (options) {\n return options\n}\n\n/**\n * Recursively validates that an object contains only serializable data.\n * Throws a CoraliteError if a function is encountered.\n *\n * @param {any} value - The value to validate.\n * @param {string} [path='root'] - The current path in the object (for error reporting).\n * @param {WeakSet} [seen=new WeakSet()] - Set of seen objects to handle circular references.\n * @throws {CoraliteError} If a function is found.\n */\nexport function validateSerializable (value, path = 'root', seen = new WeakSet()) {\n if (value === null || typeof value !== 'object') {\n if (typeof value === 'function') {\n throw new CoraliteError(`Function detected at \"${path}\". The \"server()\" block must only return serializable data (JSON-compatible plus Date, RegExp, Map, Set). Functions are not allowed.`, {\n path\n })\n }\n\n return\n }\n\n if (seen.has(value)) {\n return\n }\n\n seen.add(value)\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n validateSerializable(value[i], `${path}[${i}]`, seen)\n }\n } else if (value instanceof Map) {\n for (const [key, val] of value.entries()) {\n validateSerializable(val, `${path}.get(${JSON.stringify(key)})`, seen)\n }\n } else if (value instanceof Set) {\n let i = 0\n for (const val of value) {\n validateSerializable(val, `${path}.set[${i++}]`, seen)\n }\n } else {\n for (const key of Object.keys(value)) {\n validateSerializable(value[key], `${path}.${key}`, seen)\n }\n }\n}\n", "import { defineComponent } from '../core.js'\nimport { definePlugin } from '../../plugin.js'\n\n/**\n * Creates a Coralite element or a standard HTML element.\n * Proxy to window.createCoraliteElement or document.createElement.\n *\n * @param {string} tag - The tag name.\n * @param {Object} [options] - Optional element options.\n * @returns {HTMLElement} The created element.\n */\nexport function createCoraliteElement (tag, options) {\n // @ts-ignore\n if (typeof window !== 'undefined' && window.createCoraliteElement) {\n // @ts-ignore\n return window.createCoraliteElement(tag, options)\n }\n return document.createElement(tag, options)\n}\n\n/**\n * Processes an HTML string for custom elements.\n * Proxy to window.processHTML if available.\n *\n * @param {string} html - The HTML string.\n * @returns {string} The HTML string.\n */\nexport function processHTML (html) {\n // @ts-ignore\n if (typeof window !== 'undefined' && window.processHTML) {\n // @ts-ignore\n return window.processHTML(html)\n }\n return html\n}\n\nexport { defineComponent, definePlugin }\n", "/**\n * @import {\n * CoraliteClientPluginDisconnectedCallback,\n * CoraliteClientPluginAfterComponentRenderCallback,\n * CoraliteClientPluginBeforeComponentRenderCallback\n * } from '../types/plugin.js'\n */\n\nimport { createReadOnlyProxy } from './utils/core.js'\nimport { processHTML } from './utils/client/inject.js'\n\nconst BOOLEAN_ATTRIBUTES = new Set([\n 'allowfullscreen',\n 'async',\n 'autofocus',\n 'autoplay',\n 'checked',\n 'controls',\n 'default',\n 'defer',\n 'disabled',\n 'formnovalidate',\n 'hidden',\n 'inert',\n 'ismap',\n 'itemscope',\n 'loop',\n 'multiple',\n 'muted',\n 'nomodule',\n 'novalidate',\n 'open',\n 'playsinline',\n 'readonly',\n 'required',\n 'reversed',\n 'selected',\n 'truespeed'\n])\n\n/**\n * Coerces a value to a specified type.\n * Supports Number, Boolean, and String.\n * @param {any} value - The value to coerce.\n * @param {Function|string} type - The target type (Constructor or string name).\n * @returns {any} The coerced value.\n */\nexport function coerce (value, type) {\n if (value === null || value === undefined) {\n return value\n }\n if (type === Number || type === 'Number') {\n return Number(value)\n }\n if (type === Boolean || type === 'Boolean') {\n if (value === '') {\n return true\n }\n return value !== 'false' && value !== null\n }\n if (type === String || type === 'String') {\n return String(value)\n }\n return value\n}\n\n/**\n * @typedef {Object} CoraliteComponentOptions\n * @property {string} componentId - The unique identifier for the component.\n * @property {string} [templateHTML] - The raw HTML string for imperative mounting.\n * @property {Object} [defaultValues] - The initial state values extracted from the server data block.\n * @property {Object} [attributes] - Schema for coercing HTML attributes into typed primitives.\n * @property {Object.<string, Function>} [getters] - Pure functions for derived state, supporting Promises.\n * @property {Object.<string, Function>} [slots] - Transformation functions for projected Light DOM.\n * @property {Function} [client] - The client-side controller logic.\n * @property {Object} [hydrationMap] - AST mapping for reactive text nodes, attributes, and refs.\n */\n\n/**\n * Base class for all Coralite custom elements.\n *\n * @augments HTMLElement\n */\nexport class CoraliteElement extends HTMLElement {\n /**\n * Initializes a new instance of the CoraliteElement.\n * Sets up internal state trackers, binding collections, and hook registries.\n */\n constructor () {\n super()\n /**\n * Controls native teardown of event listeners and async fetches upon disconnection.\n * @type {AbortController|null}\n * @protected\n */\n this._abortController = null\n\n /**\n * A globally unique, deterministic identifier (e.g., `my-comp-0`).\n * @type {string|null}\n * @protected\n */\n this._instanceId = null\n\n /**\n * The unified, deeply reactive proxy holding attributes, data, and getters.\n * @type {Object|null}\n * @protected\n */\n this._state = null\n\n /**\n * The collection of DOM nodes mapped to template tokens and attributes.\n * @type {Array<{type: string, node: Node, template?: string, name?: string}>}\n * @protected\n */\n this._bindings = []\n\n /**\n * Flag to prevent multiple synchronous state mutations from triggering multiple DOM paints.\n * @type {boolean}\n * @protected\n */\n this._isUpdatePending = false\n\n /**\n * A unique Symbol generated per render cycle to prevent async getter race conditions.\n * @type {symbol|null}\n * @protected\n */\n this._currentRenderVersion = null\n\n /**\n * @type {MutationObserver|null}\n * @protected\n */\n this._observer = null\n\n /**\n * Hook to fetch globally registered Phase-2 plugin contexts.\n * @type {Function|null}\n * @protected\n */\n this._clientContextGetter = null\n\n /**\n * Tracks AbortControllers specifically for cancelling stale async getters.\n * @type {Object.<string, AbortController>|null}\n * @protected\n */\n this._getterAbortControllers = null\n\n /**\n * Internal lifecycle hooks injected by registered Coralite plugins.\n * @type {{\n * onBeforeComponentRender: Array<CoraliteClientPluginBeforeComponentRenderCallback>,\n * onAfterComponentRender: Array<CoraliteClientPluginAfterComponentRenderCallback>,\n * onDisconnected: Array<CoraliteClientPluginDisconnectedCallback>\n * }}\n * @protected\n */\n this._hooks = {\n onBeforeComponentRender: [],\n onAfterComponentRender: [],\n onDisconnected: []\n }\n\n /**\n * The definition and schema of the component generated by the compiler.\n * @type {CoraliteComponentOptions|null}\n */\n this.componentOptions = null\n\n /**\n * Hydrated data passed from the server.\n * @type {Object|null}\n * @protected\n */\n this._hydrationData = null\n }\n\n /**\n * Invoked natively when the element is added to the document.\n * Handles the architectural split between Declarative (SSR) and Imperative (JS) components.\n * Orchestrates template injection, instance ID generation, and state/binding setup.\n */\n connectedCallback () {\n this._abortController = new AbortController()\n\n if (!this.componentOptions) {\n return\n }\n\n // Declarative components receive a data-cid from the server.\n // Imperative components (created via document.createElement) do not.\n const isImperative = !this.hasAttribute('data-cid')\n\n // Imperative Flow: Manually stamp the template and project the Light DOM.\n if (isImperative && this.componentOptions.templateHTML) {\n const originalLightDOM = Array.from(this.childNodes)\n this.innerHTML = processHTML(this.componentOptions.templateHTML)\n\n if (originalLightDOM.length > 0) {\n const slots = this.querySelectorAll('slot')\n slots.forEach(slot => {\n const slotName = slot.getAttribute('name') || 'default'\n const matchingNodes = originalLightDOM.filter(node => {\n // @ts-ignore\n const nodeSlot = (node.getAttribute && node.getAttribute('slot')) || 'default'\n return nodeSlot === slotName\n })\n matchingNodes.forEach(n => slot.appendChild(n))\n })\n }\n }\n\n // Establish the Deterministic Instance ID\n if (this.hasAttribute('data-cid')) {\n this._instanceId = this.getAttribute('data-cid')\n } else {\n // Fallback counter for imperatively created components\n // @ts-ignore\n window.__coralite_instanceCounters = window.__coralite_instanceCounters || {}\n const prefix = this.componentOptions.componentId\n // @ts-ignore\n if (window.__coralite_instanceCounters[prefix] === undefined) {\n // @ts-ignore\n window.__coralite_instanceCounters[prefix] = 0\n }\n // @ts-ignore\n this._instanceId = `${prefix}-${window.__coralite_instanceCounters[prefix]++}`\n }\n\n if (isImperative) {\n this.setAttribute('data-cid', this._instanceId)\n }\n\n this._setupState()\n this._setupBindings()\n this._init(isImperative)\n }\n\n /**\n * Invoked natively when the element is removed from the document.\n * Aborts pending requests and triggers `onDisconnected` plugin hooks\n * to ensure external libraries (e.g., Observers) do not cause memory leaks.\n * @this {any}\n */\n disconnectedCallback () {\n if (this._abortController) {\n this._abortController.abort()\n }\n\n if (!this.componentOptions) {\n return\n }\n\n for (const hook of this._hooks.onDisconnected) {\n hook({\n state: this._state,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n element: this,\n options: this.componentOptions\n })\n }\n }\n\n /**\n * Invoked natively when an observed HTML attribute changes.\n * Coerces the raw string value based on the component's attribute schema\n * and synchronizes it into the reactive state proxy.\n * @param {string} name - The kebab-case name of the attribute.\n * @param {string|null} oldVal - The previous value.\n * @param {string|null} newVal - The new value.\n */\n attributeChangedCallback (name, oldVal, newVal) {\n if (!this._state || oldVal === newVal || name === 'data-cid') {\n return\n }\n const camelName = name.replace(/-([a-z])/g, (g) => g[1].toUpperCase())\n const schema = this.componentOptions.attributes?.[camelName] || this.componentOptions.attributes?.[name]\n const value = schema ? coerce(newVal, schema.type) : newVal\n\n this._state[camelName] = value\n }\n\n /**\n * Constructs the unified state object.\n * Merges `defaultValues`, JSON hydration payloads, and DOM attributes.\n * Defines getters (wrapping state in a Read-Only proxy) and applies the final Read/Write Proxy.\n * @this {any}\n * @private\n */\n _setupState () {\n const options = this.componentOptions\n const target = { ...options.defaultValues }\n\n /** @type {Array<{name: string, element: HTMLElement}>} */\n const refs = []\n if (options.hydrationMap && options.hydrationMap.refs) {\n for (const ref of options.hydrationMap.refs) {\n const uniqueRefValue = `${this._instanceId}__${ref.name}`\n\n if (!target[`ref_${ref.name}`]) {\n target[`ref_${ref.name}`] = uniqueRefValue\n }\n\n const node = this.getNodeByPath(ref.path)\n if (node) {\n if (node.setAttribute) {\n node.setAttribute('ref', uniqueRefValue)\n }\n refs.push({\n name: ref.name,\n element: node\n })\n }\n }\n }\n\n // Process initial attributes mapping\n for (const attr of this.attributes) {\n if (attr.name === 'data-cid') {\n continue\n }\n const camelName = attr.name.replace(/-([a-z])/g, (g) => g[1].toUpperCase())\n const schema = options.attributes?.[camelName] || options.attributes?.[attr.name]\n target[camelName] = schema ? coerce(attr.value, schema.type) : attr.value\n }\n\n // Hydrate data() block results from the SSR payload\n if (this._hydrationData && this._hydrationData[this._instanceId]) {\n Object.assign(target, this._hydrationData[this._instanceId])\n }\n\n // Trigger Before-Render hooks BEFORE state is proxied, allowing plugins to inject reactive data\n for (const hook of this._hooks.onBeforeComponentRender) {\n hook({\n state: target,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n refs,\n element: this,\n options: this.componentOptions\n })\n }\n\n // Define derived state getters with isolation controllers\n this._getterAbortControllers = {}\n for (const [key, getter] of Object.entries(options.getters || {})) {\n Object.defineProperty(target, key, {\n get: () => {\n if (this._getterAbortControllers[key]) {\n this._getterAbortControllers[key].abort()\n }\n this._getterAbortControllers[key] = new AbortController()\n\n // Enforce \"Dual-Proxy\" safety: Getters cannot mutate state\n const roState = createReadOnlyProxy(this._state)\n return getter(roState, { signal: this._getterAbortControllers[key].signal })\n },\n enumerable: true,\n configurable: true\n })\n }\n\n this._state = this._createReactiveProxy(target)\n }\n\n /**\n * Wraps the state target in a reactive Proxy.\n * Intercepts property setters to automatically batch and schedule DOM updates.\n * @param {Object} target - The state dictionary.\n * @returns {Proxy} The reactive state proxy.\n * @private\n */\n _createReactiveProxy (target) {\n const self = this\n return new Proxy(target, {\n set (t, p, v) {\n if (t[p] === v) {\n return true\n }\n t[p] = v\n self._scheduleUpdate()\n return true\n }\n })\n }\n\n /**\n * Traverses the DOM tree using an AST-generated path index array.\n * Allows O(1) element lookups without relying on querySelectors or classes.\n * @param {number[]} path - Array of childNode indices (e.g., `[0, 1, 2]`).\n * @returns {Node|null} The physical DOM node, or null if traversal fails.\n */\n getNodeByPath (path) {\n let node = this\n for (const index of path) {\n if (!node) {\n return null\n }\n // @ts-ignore\n node = node.childNodes[index]\n }\n return node\n }\n\n /**\n * Initializes DOM bindings based on the compiler's hydration map.\n * Caches physical DOM references to text nodes and attributes that contain template tokens.\n * @private\n */\n _setupBindings () {\n this._bindings = []\n const map = this.componentOptions.hydrationMap\n if (!map) {\n return\n }\n\n if (map.texts) {\n for (const item of map.texts) {\n const node = this.getNodeByPath(item.path)\n if (node) {\n this._bindings.push({\n type: item.type || 'text',\n node,\n template: item.template\n })\n }\n }\n }\n\n if (map.attributes) {\n for (const item of map.attributes) {\n const node = this.getNodeByPath(item.path)\n if (node) {\n this._bindings.push({\n type: 'attribute',\n node,\n name: item.name,\n template: item.template\n })\n }\n }\n }\n }\n\n /**\n * Schedules a DOM update in the next microtask queue.\n * This guarantees that multiple synchronous state mutations result in only one render pass.\n * @private\n */\n _scheduleUpdate () {\n if (this._isUpdatePending) {\n return\n }\n this._isUpdatePending = true\n queueMicrotask(() => {\n this._updateDOM()\n this._isUpdatePending = false\n })\n }\n\n /**\n * Performs the physical DOM update and resolves template tokens.\n * **Async Safety:** Implements a Symbol-based locking mechanism (`renderVersion`)\n * to guarantee that if state mutates while an async getter is pending, the stale\n * Promise will be discarded, preventing DOM race conditions.\n * @this {any}\n * @private\n */\n _updateDOM () {\n // Create a unique lock for this specific render cycle\n const renderVersion = Symbol()\n this._currentRenderVersion = renderVersion\n\n // Extract unique tokens to prevent double-reading and accidental aborts\n /** @type {Set<string>} */\n const requiredTokens = new Set()\n for (const binding of this._bindings) {\n binding.template.replace(/\\{\\{\\s*(.+?)\\s*\\}\\}/g, (_, key) => {\n requiredTokens.add(key)\n return ''\n })\n }\n\n const evaluatedTokens = {}\n let hasPromise = false\n\n // Evaluate getters exactly once per render cycle\n for (const key of requiredTokens) {\n let val = this._state[key]\n if (typeof val === 'function') {\n val = val(this._state)\n }\n evaluatedTokens[key] = val\n if (val instanceof Promise) {\n hasPromise = true\n }\n }\n\n // The DOM Mutator Function\n const applyBindings = (tokenValues) => {\n // Race Condition Lock: Abort if a newer render cycle has already begun\n if (this._currentRenderVersion !== renderVersion) {\n return\n }\n\n for (const binding of this._bindings) {\n const hydratedValue = binding.template.replace(/\\{\\{\\s*(.+?)\\s*\\}\\}/g, (_, key) => {\n return tokenValues[key] ?? ''\n })\n\n if (binding.type === 'text') {\n if (binding.node.textContent !== hydratedValue) {\n binding.node.textContent = hydratedValue\n }\n } else if (binding.type === 'html') {\n /** @type {HTMLElement} */\n // @ts-ignore\n const element = binding.node\n\n if (element.innerHTML !== hydratedValue) {\n element.innerHTML = hydratedValue\n }\n } else if (binding.type === 'attribute') {\n /** @type {HTMLElement} */\n // @ts-ignore\n const element = binding.node\n\n if (BOOLEAN_ATTRIBUTES.has(binding.name)) {\n const isFalsy = hydratedValue === '' || hydratedValue === 'false' || hydratedValue === 'null' || hydratedValue === '0' || hydratedValue === 'undefined'\n if (isFalsy) {\n element.removeAttribute(binding.name)\n } else {\n element.setAttribute(binding.name, '')\n }\n } else {\n if (element.getAttribute(binding.name) !== hydratedValue) {\n element.setAttribute(binding.name, hydratedValue)\n }\n }\n }\n }\n\n this._processSlots()\n\n // Trigger After-Render hooks ONLY after the physical DOM is stable\n for (const hook of this._hooks.onAfterComponentRender) {\n hook({\n state: this._state,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n element: this,\n options: this.componentOptions\n })\n }\n }\n\n // Await Promises or Apply Synchronously\n if (hasPromise) {\n const keys = Object.keys(evaluatedTokens)\n const promises = keys.map(k => Promise.resolve(evaluatedTokens[k]))\n\n Promise.all(promises).then(resolvedValues => {\n const resolvedMap = {}\n keys.forEach((k, i) => {\n resolvedMap[k] = resolvedValues[i]\n })\n applyBindings(resolvedMap)\n }).catch(e => {\n if (e.name !== 'AbortError') {\n console.error('Coralite Async Getter Error:', e)\n }\n })\n } else {\n applyBindings(evaluatedTokens)\n }\n }\n\n /**\n * Evaluates and projects Light DOM elements into their respective `<slot>` nodes.\n * Invokes component-specific slot transformation functions.\n * @private\n */\n _processSlots () {\n const slots = this.componentOptions.slots\n if (!slots || Object.keys(slots).length === 0) {\n return\n }\n\n const slotElements = this.querySelectorAll('slot')\n slotElements.forEach(slotEl => {\n const slotName = slotEl.getAttribute('name') || 'default'\n const slotFn = slots[slotName]\n\n if (slotFn) {\n // @ts-ignore\n if (!slotEl._originalNodes) {\n // @ts-ignore\n slotEl._originalNodes = Array.from(slotEl.childNodes).map(n => n.cloneNode(true))\n }\n\n // @ts-ignore\n const result = slotFn(slotEl._originalNodes, this._state)\n\n if (result === undefined) {\n return\n }\n\n if (result === null || result === '' || (Array.isArray(result) && result.length === 0)) {\n slotEl.innerHTML = ''\n return\n }\n\n if (typeof result === 'string') {\n slotEl.innerHTML = result\n } else if (Array.isArray(result)) {\n slotEl.replaceChildren(...result)\n }\n }\n })\n }\n\n /**\n * The final initialization pipeline.\n * Injects globally registered client plugins into the local context payload,\n * triggers the initial DOM render, and invokes the user's `script()` logic.\n * @param {boolean} [isImperative=false] - If true, initial render runs synchronously.\n * @private\n */\n async _init (isImperative = false) {\n const self = this\n /**\n * The context payload injected into the user's script block.\n * @type {Object}\n */\n let localContext = {\n instanceId: this._instanceId,\n state: this._state,\n root: this,\n signal: this._abortController.signal,\n refs (id) {\n const refId = self._state[`ref_${id}`]\n if (!refId && typeof refId !== 'string') {\n return null\n }\n return self.querySelector(`[ref=\"${refId}\"]`)\n }\n }\n\n if (typeof this._clientContextGetter === 'function') {\n localContext = await this._clientContextGetter(localContext)\n }\n\n if (isImperative) {\n this._updateDOM()\n } else {\n this._scheduleUpdate()\n }\n\n if (this.componentOptions.client) {\n try {\n this.componentOptions.client(localContext)\n } catch (error) {\n console.error(`Coralite Error: Component \"${this.componentOptions.componentId}\" script failed:`, error)\n }\n }\n }\n}\n\n/**\n * Factory function to create a Coralite element class.\n * It dynamically defines the class, including observed attributes and hook initialization.\n * @param {CoraliteComponentOptions} options - Component options and metadata.\n * @param {Function|null} [contextGetter=null] - Optional function to retrieve client-side plugin context.\n * @param {Object} [hooks={}] - Lifecycle hooks to register.\n * @param {Array<CoraliteClientPluginBeforeComponentRenderCallback>} [hooks.onBeforeComponentRender] - Hooks to run before render.\n * @param {Array<CoraliteClientPluginAfterComponentRenderCallback>} [hooks.onAfterComponentRender] - Hooks to run after render.\n * @param {Array<CoraliteClientPluginDisconnectedCallback>} [hooks.onDisconnected] - Hooks to run after render.\n * @param {Object|null} [hydrationData=null] - Hydrated data passed from the server.\n * @returns {typeof CoraliteElement} A new CoraliteElement subclass.\n */\nexport function createCoraliteClass (options, contextGetter = null, hooks = {}, hydrationData = null) {\n return class extends CoraliteElement {\n /**\n * The attributes to observe for changes.\n * @returns {string[]} Array of attribute names.\n */\n static get observedAttributes () {\n if (!options.attributes) {\n return []\n }\n return Object.keys(options.attributes).map(key => key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n )\n }\n\n /**\n * Initializes the dynamic Coralite element.\n */\n constructor () {\n super()\n this.componentOptions = options\n this._clientContextGetter = contextGetter\n this._hydrationData = hydrationData\n this._hooks = {\n onBeforeComponentRender: hooks.onBeforeComponentRender || [],\n onAfterComponentRender: hooks.onAfterComponentRender || [],\n onDisconnected: hooks.onDisconnected || []\n }\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\n/**\n * @import { CoraliteErrorData } from '../../types/index.js'\n */\n\n/**\n * Base error class for all Coralite-related errors.\n */\nexport class CoraliteError extends Error {\n /**\n * @param {string} message - The error message.\n * @param {Object} [options] - Additional options for the error.\n * @param {string} [options.componentId] - The ID of the component where the error occurred.\n * @param {string} [options.filePath] - The path to the file where the error occurred.\n * @param {string} [options.instanceId] - The unique ID of the component instance.\n * @param {string} [options.pagePath] - The path to the page being rendered.\n * @param {string} [options.path] - The path to the data property where the error occurred.\n * @param {number} [options.line] - The line number where the error occurred.\n * @param {number} [options.column] - The column number where the error occurred.\n * @param {string} [options.stackFile] - The file name from the stack trace.\n * @param {Error} [options.cause] - The original error that caused this error.\n */\n constructor (message, options = {}) {\n super(message, options)\n this.name = 'CoraliteError'\n this.isCoraliteError = true\n this.componentId = options.componentId\n this.filePath = options.filePath\n this.instanceId = options.instanceId\n this.pagePath = options.pagePath\n this.path = options.path\n this.line = options.line\n this.column = options.column\n this.stackFile = options.stackFile\n\n // Polyfill cause if necessary (node version differences)\n if (options.cause && !this.cause) {\n this.cause = options.cause\n }\n }\n}\n\n/**\n * Default error handler.\n * @param {CoraliteErrorData} data - The data object containing error details.\n */\nexport function defaultOnError ({ level, message, error }) {\n if (level === 'ERR') {\n if (error) {\n throw error\n }\n throw new CoraliteError(message)\n } else if (level === 'WARN') {\n console.warn(message)\n } else {\n console.log(message)\n }\n}\n\n/**\n * Handles errors using an optional callback or the default handler.\n * @param {Object} options - The options for handling the error.\n * @param {Function} [options.onErrorCallback] - The optional custom error callback function.\n * @param {CoraliteErrorData} options.data - The error data to be handled.\n */\nexport function handleError ({ onErrorCallback, data }) {\n const error = data.error\n if (error && 'isCoraliteError' in error && error.isCoraliteError) {\n const coraliteError = error\n // @ts-ignore\n data.componentId = data.componentId || coraliteError.componentId\n // @ts-ignore\n data.filePath = data.filePath || coraliteError.filePath\n // @ts-ignore\n data.instanceId = data.instanceId || coraliteError.instanceId\n // @ts-ignore\n data.pagePath = data.pagePath || coraliteError.pagePath\n // @ts-ignore\n data.path = data.path || coraliteError.path\n // @ts-ignore\n data.line = data.line || coraliteError.line\n // @ts-ignore\n data.column = data.column || coraliteError.column\n // @ts-ignore\n data.stackFile = data.stackFile || coraliteError.stackFile\n }\n\n if (onErrorCallback) {\n onErrorCallback(data)\n } else {\n defaultOnError(data)\n }\n}\n", "import { CoraliteError } from './errors.js'\n\n/**\n * @import {\n * CoraliteModule,\n * CoraliteComponent,\n * CoraliteComponentResult,\n * } from '../../types/index.js'\n */\n\nconst KEBAB_REGEX = /[-|:]([a-z])/g\n\n/**\n * Converts a kebab-case string to camelCase\n * @param {string} str - The kebab-case string to convert\n * @returns {string} - The camelCase version of the string\n */\nexport function kebabToCamel (str) {\n // replace each dash followed by a letter with the uppercase version of the letter\n return str.replace(KEBAB_REGEX, function (match, letter) {\n return letter.toUpperCase()\n })\n}\n\n/**\n * Converts all keys in an object from kebab-case to camelCase\n * @template T\n * @param {Record<string, T>} object - The object with kebab-case keys\n * @returns {Record<string, T>} - A new object with camelCase keys\n */\nexport function cleanKeys (object) {\n /** @type {Record<string, T>} */\n const result = {}\n\n for (const [key, value] of Object.entries(object)) {\n result[key] = value\n\n const camelKey = kebabToCamel(key)\n if (camelKey !== key) {\n result[camelKey] = value\n }\n }\n\n return result\n}\n\n/**\n * Recursively clones an object or array and normalizes any function state\n * it finds into a string representation that preserves standard function syntax,\n * bypassing ES6 shorthand method serialization issues.\n * @param {any} target - The object or array to normalize.\n * @param {Function} [transform] - Optional transform function for each node.\n * @param {WeakMap} [seen=new WeakMap()] - Map of seen objects to handle circular references.\n * @returns {any} A deeply cloned object with normalized functions.\n */\nexport function normalizeObjectFunctions (target, transform = null, seen = new WeakMap()) {\n if (typeof transform === 'function') {\n const transformed = transform(target)\n if (transformed !== target) {\n return transformed\n }\n }\n\n if (typeof target !== 'object' || target === null) {\n return target\n }\n\n if (seen.has(target)) {\n return seen.get(target)\n }\n\n if (Array.isArray(target)) {\n const arr = []\n seen.set(target, arr)\n for (let i = 0; i < target.length; i++) {\n arr.push(normalizeObjectFunctions(target[i], transform, seen))\n }\n return arr\n }\n\n const obj = {}\n seen.set(target, obj)\n for (const key in target) {\n if (Object.hasOwn(target, key)) {\n if (typeof target[key] === 'function') {\n const normalizedString = normalizeFunction(target[key])\n const originalFunction = target[key]\n\n const wrapper = function () {\n return originalFunction.apply(this, arguments)\n }\n wrapper.toString = () => normalizedString\n obj[key] = wrapper\n } else {\n obj[key] = normalizeObjectFunctions(target[key], transform, seen)\n }\n }\n }\n\n return obj\n}\n\n/**\n * Checks whether the given object is an object and has at least one own key.\n * @param {any} obj - The object to check.\n * @returns {boolean} True if the object is truthy and has keys, otherwise false.\n */\nexport function hasObjectKeys (obj) {\n return obj && typeof obj === 'object' && Object.keys(obj).length > 0\n}\n\n/**\n * Merges two arrays, returning a new array with unique items.\n * Uses JSON.stringify for deep comparison of object elements, preserving object uniqueness correctly.\n * @param {Array<any>} [arr1] - The first array.\n * @param {Array<any>} [arr2] - The second array.\n * @returns {Array<any>} A new array with unique values from both input arrays.\n */\nexport function mergeUniqueObjects (arr1, arr2) {\n const all = [...(arr1 || []), ...(arr2 || [])]\n const seen = new Set()\n return all.filter(item => {\n const key = typeof item === 'object' ? JSON.stringify(item) : item\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n}\n\n/**\n * Normalizes function declarations to ensure consistent formatting.\n * Converts shorthand method syntax to full function declarations where needed,\n * while preserving arrow functions and existing full declarations.\n *\n * @param {Function} func - The function to normalize\n * @returns {string} The normalized function string representation\n */\nexport function normalizeFunction (func) {\n const original = func.toString().trim()\n\n const firstBrace = original.indexOf('{')\n const firstArrow = original.indexOf('=>')\n\n const isArrow = firstArrow !== -1 && (firstBrace === -1 || firstArrow < firstBrace)\n\n if (isArrow) {\n return original\n }\n\n // For non-arrows, extract header to check for shorthand\n const header = firstBrace !== -1 ? original.slice(0, firstBrace).trim() : original\n\n const isStandard = header.startsWith('function') || header.startsWith('async function')\n\n if (isStandard) {\n return original\n }\n\n // Handle Method Shorthand\n if (header.startsWith('async ')) {\n if (header.startsWith('async get ') || header.startsWith('async set ')) {\n return original\n }\n\n return original.replace(/^async\\s+([$\\w]+)\\s*\\(/, 'async function(')\n } else {\n if (header.startsWith('get ') || header.startsWith('set ')) {\n return original\n }\n\n return original.replace(/^([$\\w]+)\\s*\\(/, 'function(')\n }\n}\n\n\n/**\n * Recursively clones an AST node and its children, ensuring that\n * inner references (like parents and slots) point to the newly cloned nodes.\n *\n * @param {Map<Object, Object>} nodeMap - A map tracking original nodes to their newly cloned counterparts.\n * @param {Object} node - The current AST node being cloned.\n * @param {Object} [parent] - The parent node reference to assign to the clone.\n * @returns {Object} The newly cloned node.\n */\nexport function cloneNode (nodeMap, node, parent) {\n const newNode = Object.create(Object.getPrototypeOf(node))\n\n // Copy all own enumerable properties\n Object.assign(newNode, node)\n\n if (parent) {\n newNode.parent = parent\n }\n\n if (newNode.attribs) {\n newNode.attribs = { ...newNode.attribs }\n }\n\n // Register in map\n nodeMap.set(node, newNode)\n\n // Recursively clone children\n if (node.children) {\n const children = node.children\n const length = children.length\n const clonedChildren = new Array(length)\n newNode.children = clonedChildren\n\n for (let i = 0; i < length; i++) {\n const clonedChild = cloneNode(nodeMap, children[i], newNode)\n clonedChildren[i] = clonedChild\n if (i > 0) {\n clonedChild.prev = clonedChildren[i - 1]\n clonedChildren[i - 1].next = clonedChild\n }\n }\n }\n\n // Update slot references to point to new cloned nodes\n if (node.slots) {\n const slots = node.slots\n const length = slots.length\n const clonedSlots = new Array(length)\n for (let i = 0; i < length; i++) {\n const slot = slots[i]\n const clonedSlot = { ...slot }\n if (slot.node) {\n const clonedNode = nodeMap.get(slot.node)\n if (clonedNode) {\n clonedSlot.node = clonedNode\n }\n }\n clonedSlots[i] = clonedSlot\n }\n newNode.slots = clonedSlots\n }\n\n // Preserve the enhanced flag without re-running enhanceNode\n Object.defineProperty(newNode, '__coralite_enhanced__', {\n value: true,\n enumerable: false,\n configurable: true\n })\n\n return newNode\n}\n\n/**\n * Creates a shallow copy of a CoraliteModule with a deep clone of its DOM tree (template) and re-linked internal references to enable safe independent mutation.\n *\n * Top-level non-DOM state (id, path, script, isTemplate, lineOffset) are shallow copied. Nested objects within these state (e.g., path) remain shared references. Only DOM-related structures undergo deep cloning and reference re-linking to isolate mutations from the original module.\n *\n * @param {CoraliteModule} originalModule - Module to clone.\n * @returns {CoraliteModule}\n */\nexport function cloneModuleInstance (originalModule) {\n const nodeMap = new Map()\n\n // Clone the main template tree\n const newTemplate = cloneNode(nodeMap, originalModule.template, null)\n\n // Reconstruct the 'values' object\n const newValues = {\n attributes: originalModule.values.attributes.map(item => ({\n ...item,\n element: nodeMap.get(item.element)\n })),\n textNodes: originalModule.values.textNodes.map(item => ({\n ...item,\n textNode: nodeMap.get(item.textNode)\n })),\n refs: originalModule.values.refs.map(item => ({\n ...item,\n element: nodeMap.get(item.element)\n }))\n }\n\n // Reconstruct customElements list\n const newCustomElements = originalModule.customElements.map(el => nodeMap.get(el))\n\n // Reconstruct slotElements\n const newSlotElements = {}\n if (originalModule.slotElements) {\n for (const modId in originalModule.slotElements) {\n newSlotElements[modId] = {}\n const slotGroup = originalModule.slotElements[modId]\n\n for (const slotName in slotGroup) {\n const slotItem = slotGroup[slotName]\n newSlotElements[modId][slotName] = {\n ...slotItem,\n element: nodeMap.get(slotItem.element)\n }\n }\n }\n }\n\n // Return the new module structure\n return {\n ...originalModule,\n template: newTemplate,\n values: newValues,\n customElements: newCustomElements,\n // @ts-ignore\n slotElements: newSlotElements\n }\n}\n\n/**\n * Creates a deep copy of a CoraliteComponent with re-linked internal references to enable safe independent mutation.\n *\n * @param {CoraliteComponent & CoraliteComponentResult} originalDocument - Document to clone.\n * @returns {CoraliteComponent & CoraliteComponentResult}\n */\nexport function cloneComponentInstance (originalDocument) {\n const nodeMap = new Map()\n const newRoot = cloneNode(nodeMap, originalDocument.root, null)\n\n const newCustomElements = originalDocument.customElements.map(el => nodeMap.get(el))\n const newTempElements = originalDocument.tempElements ? originalDocument.tempElements.map(el => nodeMap.get(el)) : []\n const newSkipRenderElements = originalDocument.skipRenderElements ? originalDocument.skipRenderElements.map(el => nodeMap.get(el)) : []\n\n return {\n ...originalDocument,\n state: { ...originalDocument.state },\n root: newRoot,\n customElements: newCustomElements,\n tempElements: newTempElements,\n skipRenderElements: newSkipRenderElements\n }\n}\n\n/**\n * Calculates the DOM path from a node to the root.\n * @param {Object} node - The node to calculate the path for.\n * @param {Object} root - The root node.\n * @returns {Array<number>} An array of indices representing the path.\n */\nexport function getNodePath (node, root) {\n const path = []\n let current = node\n while (current && current !== root) {\n const parent = current.parent\n if (!parent) {\n break\n }\n const index = parent.children.indexOf(current)\n if (index === -1) {\n break\n }\n path.unshift(index)\n current = parent\n }\n return path\n}\n\n/**\n * Generates a hydration map for the client.\n * @param {Array<Object>} templateNodes - The component's template nodes.\n * @param {Object} templateValues - The component's template values.\n * @returns {Object} The hydration map.\n */\nexport function generateHydrationMap (templateNodes, templateValues) {\n const map = {\n texts: [],\n attributes: [],\n refs: []\n }\n\n if (!templateNodes || !templateValues) {\n return map\n }\n\n const root = templateNodes.length > 0 ? templateNodes[0].parent : { children: templateNodes }\n\n if (templateValues.textNodes) {\n for (const item of templateValues.textNodes) {\n if (item.textNode) {\n const isHtml = item.type === 'html'\n const targetNode = isHtml ? item.textNode.parent : item.textNode\n\n map.texts.push({\n path: getNodePath(targetNode, root),\n template: item.textNode.data,\n type: isHtml ? 'html' : 'text'\n })\n }\n }\n }\n\n if (templateValues.attributes) {\n for (const item of templateValues.attributes) {\n if (item.element && item.element.attribs) {\n const originalValue = item.element.attribs[item.name]\n map.attributes.push({\n path: getNodePath(item.element, root),\n name: item.name,\n template: originalValue\n })\n }\n }\n }\n\n if (templateValues.refs) {\n for (const item of templateValues.refs) {\n if (item.element) {\n map.refs.push({\n path: getNodePath(item.element, root),\n name: item.name\n })\n }\n }\n }\n\n return map\n}\n\n/**\n * Recursively adds a component and its dependencies to a tracking object.\n *\n * @param {string} componentId - The ID of the component to add.\n * @param {Object.<string, boolean>} processed - The object tracking processed components.\n * @param {Object.<string, any>} sharedFunctions - The map of shared component functions.\n */\nexport function addComponentAndDependencies (componentId, processed, sharedFunctions) {\n if (!processed[componentId] && sharedFunctions[componentId]) {\n processed[componentId] = true\n\n // Add all dependencies of this component\n const dependencies = sharedFunctions[componentId].components || []\n for (const depId of dependencies) {\n addComponentAndDependencies(depId, processed, sharedFunctions)\n }\n }\n}\n\n/**\n * Recursively clones an AST node and its children, stripping circular references\n * and assigning unique IDs for client-side hydration.\n *\n * @param {Array<Object>} nodes - The nodes to clean.\n * @param {WeakMap} nodeMap - Map to track original nodes to their unique IDs.\n * @param {Object} state - Object containing the current node counter.\n * @returns {Array<Object>|null} The cleaned AST nodes.\n */\nexport function cleanAST (nodes, nodeMap, state) {\n if (!nodes) {\n return null\n }\n\n return nodes.map((node) => {\n const cloned = { ...node }\n // Assign unique ID for token mapping\n const id = state.counter++\n nodeMap.set(node, id)\n cloned._id = id\n\n // Remove circular references\n delete cloned.parent\n delete cloned.prev\n delete cloned.next\n delete cloned.slots\n\n if (cloned.children) {\n cloned.children = cleanAST(cloned.children, nodeMap, state)\n }\n return cloned\n })\n}\n\n/**\n * Cleans the template values object, mapping original node references to unique IDs.\n *\n * @param {Object} values - The values object to clean.\n * @param {WeakMap} nodeMap - Map of original nodes to their unique IDs.\n * @returns {Object|null} The cleaned values object.\n */\nexport function cleanValues (values, nodeMap) {\n if (!values) {\n return null\n }\n\n const result = { ...values }\n\n if (result.attributes) {\n result.attributes = result.attributes.map(item => {\n const cloned = { ...item }\n cloned.elementId = nodeMap.get(item.element)\n delete cloned.element\n return cloned\n })\n }\n\n if (result.textNodes) {\n result.textNodes = result.textNodes.map(item => {\n const cloned = { ...item }\n cloned.textNodeId = nodeMap.get(item.textNode)\n delete cloned.textNode\n return cloned\n })\n }\n\n if (result.refs) {\n result.refs = result.refs.map(item => {\n const cloned = { ...item }\n cloned.elementId = nodeMap.get(item.element)\n delete cloned.element\n return cloned\n })\n }\n return result\n}\n\n/**\n * Safely merges partial plugin updates into the main context object.\n * Deeply merges plain objects and overwrites other types (arrays, primitives, etc.).\n *\n * @param {any} current - The current state object.\n * @param {any} patch - The patch object containing updates.\n * @returns {any} The newly merged state object.\n */\nexport function mergePluginState (current, patch) {\n if (!patch || typeof patch !== 'object') {\n return current\n }\n\n const result = { ...current }\n\n for (const key of Object.keys(patch)) {\n const patchValue = patch[key]\n const currentValue = result[key]\n\n // If both are plain objects, merge them deeply\n if (\n patchValue && typeof patchValue === 'object' && !Array.isArray(patchValue) &&\n currentValue && typeof currentValue === 'object' && !Array.isArray(currentValue)\n ) {\n result[key] = mergePluginState(currentValue, patchValue)\n } else {\n // Otherwise, overwrite (Arrays, strings, numbers, etc.)\n result[key] = patchValue\n }\n }\n\n return result\n}\n\n/**\n * Creates a reactive proxy that triggers a callback on changes.\n * Supports deep reactivity via lazy proxying of nested objects.\n *\n * @param {Object} target - The object to proxy.\n * @param {Function} onChange - Callback triggered when a property is set or deleted.\n * @param {WeakMap} [proxies=new WeakMap()] - Cache for existing proxies to handle circular references and identity.\n * @returns {Proxy} The reactive proxy.\n */\nexport function createReactiveProxy (target, onChange, proxies = new WeakMap()) {\n if (proxies.has(target)) {\n return proxies.get(target)\n }\n\n const handler = {\n get (target, property, receiver) {\n const value = Reflect.get(target, property, receiver)\n if (value !== null && typeof value === 'object' && !(typeof Node !== 'undefined' && value instanceof Node)) {\n return createReactiveProxy(value, onChange, proxies)\n }\n return value\n },\n set (target, property, value, receiver) {\n const oldValue = target[property]\n if (oldValue === value && property in target) {\n return true\n }\n\n const result = Reflect.set(target, property, value, receiver)\n if (result) {\n onChange({\n property,\n value,\n oldValue,\n target\n })\n }\n return result\n },\n deleteProperty (target, property) {\n const hadProperty = Object.prototype.hasOwnProperty.call(target, property)\n const oldValue = target[property]\n const result = Reflect.deleteProperty(target, property)\n if (result && hadProperty) {\n onChange({\n property,\n value: undefined,\n oldValue,\n target,\n deleted: true\n })\n }\n return result\n }\n }\n\n const proxy = new Proxy(target, handler)\n proxies.set(target, proxy)\n return proxy\n}\n\n/**\n * Creates a read-only proxy that throws on mutation attempts.\n * @param {Object} target - The object to proxy.\n * @param {WeakMap} [proxies=new WeakMap()] - Cache for existing proxies.\n * @returns {Proxy} The read-only proxy.\n */\nexport function createReadOnlyProxy (target, proxies = new WeakMap()) {\n if (proxies.has(target)) {\n return proxies.get(target)\n }\n\n const handler = {\n get (target, property, receiver) {\n const value = Reflect.get(target, property, receiver)\n if (value !== null && typeof value === 'object' && !(typeof Node !== 'undefined' && value instanceof Node)) {\n return createReadOnlyProxy(value, proxies)\n }\n return value\n },\n set () {\n throw new CoraliteError('Cannot mutate state inside a getter. State is read-only here.')\n },\n deleteProperty () {\n throw new CoraliteError('Cannot delete state inside a getter. State is read-only here.')\n }\n }\n\n const proxy = new Proxy(target, handler)\n\n proxies.set(target, proxy)\n\n return proxy\n}\n\n/**\n * Defines a Coralite component.\n * On the client, this acts as an identity function for type safety and HRM.\n * @param {Object} options - Component options\n * @returns {Object} The component options\n */\nexport function defineComponent (options) {\n return options\n}\n\n/**\n * Recursively validates that an object contains only serializable data.\n * Throws a CoraliteError if a function is encountered.\n *\n * @param {any} value - The value to validate.\n * @param {string} [path='root'] - The current path in the object (for error reporting).\n * @param {WeakSet} [seen=new WeakSet()] - Set of seen objects to handle circular references.\n * @throws {CoraliteError} If a function is found.\n */\nexport function validateSerializable (value, path = 'root', seen = new WeakSet()) {\n if (value === null || typeof value !== 'object') {\n if (typeof value === 'function') {\n throw new CoraliteError(`Function detected at \"${path}\". The \"server()\" block must only return serializable data (JSON-compatible plus Date, RegExp, Map, Set). Functions are not allowed.`, {\n path\n })\n }\n\n return\n }\n\n if (seen.has(value)) {\n return\n }\n\n seen.add(value)\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n validateSerializable(value[i], `${path}[${i}]`, seen)\n }\n } else if (value instanceof Map) {\n for (const [key, val] of value.entries()) {\n validateSerializable(val, `${path}.get(${JSON.stringify(key)})`, seen)\n }\n } else if (value instanceof Set) {\n let i = 0\n for (const val of value) {\n validateSerializable(val, `${path}.set[${i++}]`, seen)\n }\n } else {\n for (const key of Object.keys(value)) {\n validateSerializable(value[key], `${path}.${key}`, seen)\n }\n }\n}\n", "import { defineComponent } from '../core.js'\nimport { definePlugin } from '../../plugin.js'\n\n/**\n * Creates a Coralite element or a standard HTML element.\n * Proxy to window.createCoraliteElement or document.createElement.\n *\n * @param {string} tag - The tag name.\n * @param {Object} [options] - Optional element options.\n * @returns {HTMLElement} The created element.\n */\nexport function createCoraliteElement (tag, options) {\n // @ts-ignore\n if (typeof window !== 'undefined' && window.createCoraliteElement) {\n // @ts-ignore\n return window.createCoraliteElement(tag, options)\n }\n return document.createElement(tag, options)\n}\n\n/**\n * Processes an HTML string for custom elements.\n * Proxy to window.processHTML if available.\n *\n * @param {string} html - The HTML string.\n * @returns {string} The HTML string.\n */\nexport function processHTML (html) {\n // @ts-ignore\n if (typeof window !== 'undefined' && window.processHTML) {\n // @ts-ignore\n return window.processHTML(html)\n }\n return html\n}\n\nexport { defineComponent, definePlugin }\n", "/**\n * @import {\n * CoraliteClientPluginDisconnectedCallback,\n * CoraliteClientPluginAfterComponentRenderCallback,\n * CoraliteClientPluginBeforeComponentRenderCallback\n * } from '../types/plugin.js'\n */\n\nimport { createReadOnlyProxy } from './utils/core.js'\nimport { processHTML } from './utils/client/inject.js'\n\nconst BOOLEAN_ATTRIBUTES = new Set([\n 'allowfullscreen',\n 'async',\n 'autofocus',\n 'autoplay',\n 'checked',\n 'controls',\n 'default',\n 'defer',\n 'disabled',\n 'formnovalidate',\n 'hidden',\n 'inert',\n 'ismap',\n 'itemscope',\n 'loop',\n 'multiple',\n 'muted',\n 'nomodule',\n 'novalidate',\n 'open',\n 'playsinline',\n 'readonly',\n 'required',\n 'reversed',\n 'selected',\n 'truespeed'\n])\n\n/**\n * Coerces a value to a specified type.\n * Supports Number, Boolean, and String.\n * @param {any} value - The value to coerce.\n * @param {Function|string} type - The target type (Constructor or string name).\n * @returns {any} The coerced value.\n */\nexport function coerce (value, type) {\n if (value === null || value === undefined) {\n return value\n }\n if (type === Number || type === 'Number') {\n return Number(value)\n }\n if (type === Boolean || type === 'Boolean') {\n if (value === '') {\n return true\n }\n return value !== 'false' && value !== null\n }\n if (type === String || type === 'String') {\n return String(value)\n }\n return value\n}\n\n/**\n * @typedef {Object} CoraliteComponentOptions\n * @property {string} componentId - The unique identifier for the component.\n * @property {string} [templateHTML] - The raw HTML string for imperative mounting.\n * @property {Object} [defaultValues] - The initial state values extracted from the server data block.\n * @property {Object} [attributes] - Schema for coercing HTML attributes into typed primitives.\n * @property {Object.<string, Function>} [getters] - Pure functions for derived state, supporting Promises.\n * @property {Object.<string, Function>} [slots] - Transformation functions for projected Light DOM.\n * @property {Function} [client] - The client-side controller logic.\n * @property {Object} [hydrationMap] - AST mapping for reactive text nodes, attributes, and refs.\n */\n\n/**\n * Base class for all Coralite custom elements.\n *\n * @augments HTMLElement\n */\nexport class CoraliteElement extends HTMLElement {\n /**\n * Initializes a new instance of the CoraliteElement.\n * Sets up internal state trackers, binding collections, and hook registries.\n */\n constructor () {\n super()\n /**\n * Controls native teardown of event listeners and async fetches upon disconnection.\n * @type {AbortController|null}\n * @protected\n */\n this._abortController = null\n\n /**\n * A globally unique, deterministic identifier (e.g., `my-comp-0`).\n * @type {string|null}\n * @protected\n */\n this._instanceId = null\n\n /**\n * The unified, deeply reactive proxy holding attributes, data, and getters.\n * @type {Object|null}\n * @protected\n */\n this._state = null\n\n /**\n * The collection of DOM nodes mapped to template tokens and attributes.\n * @type {Array<{type: string, node: Node, template?: string, name?: string}>}\n * @protected\n */\n this._bindings = []\n\n /**\n * Flag to prevent multiple synchronous state mutations from triggering multiple DOM paints.\n * @type {boolean}\n * @protected\n */\n this._isUpdatePending = false\n\n /**\n * A unique Symbol generated per render cycle to prevent async getter race conditions.\n * @type {symbol|null}\n * @protected\n */\n this._currentRenderVersion = null\n\n /**\n * @type {MutationObserver|null}\n * @protected\n */\n this._observer = null\n\n /**\n * Hook to fetch globally registered Phase-2 plugin contexts.\n * @type {Function|null}\n * @protected\n */\n this._clientContextGetter = null\n\n /**\n * Tracks AbortControllers specifically for cancelling stale async getters.\n * @type {Object.<string, AbortController>|null}\n * @protected\n */\n this._getterAbortControllers = null\n\n /**\n * Internal lifecycle hooks injected by registered Coralite plugins.\n * @type {{\n * onBeforeComponentRender: Array<CoraliteClientPluginBeforeComponentRenderCallback>,\n * onAfterComponentRender: Array<CoraliteClientPluginAfterComponentRenderCallback>,\n * onDisconnected: Array<CoraliteClientPluginDisconnectedCallback>\n * }}\n * @protected\n */\n this._hooks = {\n onBeforeComponentRender: [],\n onAfterComponentRender: [],\n onDisconnected: []\n }\n\n /**\n * The definition and schema of the component generated by the compiler.\n * @type {CoraliteComponentOptions|null}\n */\n this.componentOptions = null\n\n /**\n * Hydrated data passed from the server.\n * @type {Object|null}\n * @protected\n */\n this._hydrationData = null\n }\n\n /**\n * Invoked natively when the element is added to the document.\n * Handles the architectural split between Declarative (SSR) and Imperative (JS) components.\n * Orchestrates template injection, instance ID generation, and state/binding setup.\n */\n connectedCallback () {\n this._abortController = new AbortController()\n\n if (!this.componentOptions) {\n return\n }\n\n // Declarative components receive a data-cid from the server.\n // Imperative components (created via document.createElement) do not.\n const isImperative = !this.hasAttribute('data-cid')\n\n // Imperative Flow: Manually stamp the template and project the Light DOM.\n if (isImperative && this.componentOptions.templateHTML) {\n const originalLightDOM = Array.from(this.childNodes)\n this.innerHTML = processHTML(this.componentOptions.templateHTML)\n\n if (originalLightDOM.length > 0) {\n const slots = this.querySelectorAll('slot')\n slots.forEach(slot => {\n const slotName = slot.getAttribute('name') || 'default'\n const matchingNodes = originalLightDOM.filter(node => {\n // @ts-ignore\n const nodeSlot = (node.getAttribute && node.getAttribute('slot')) || 'default'\n return nodeSlot === slotName\n })\n matchingNodes.forEach(n => slot.appendChild(n))\n })\n }\n }\n\n // Establish the Deterministic Instance ID\n if (this.hasAttribute('data-cid')) {\n this._instanceId = this.getAttribute('data-cid')\n } else {\n // Fallback counter for imperatively created components\n // @ts-ignore\n window.__coralite_instanceCounters = window.__coralite_instanceCounters || {}\n const prefix = this.componentOptions.componentId\n // @ts-ignore\n if (window.__coralite_instanceCounters[prefix] === undefined) {\n // @ts-ignore\n window.__coralite_instanceCounters[prefix] = 0\n }\n // @ts-ignore\n this._instanceId = `${prefix}-${window.__coralite_instanceCounters[prefix]++}`\n }\n\n if (isImperative) {\n this.setAttribute('data-cid', this._instanceId)\n }\n\n this._setupState()\n this._setupBindings()\n this._init(isImperative)\n }\n\n /**\n * Invoked natively when the element is removed from the document.\n * Aborts pending requests and triggers `onDisconnected` plugin hooks\n * to ensure external libraries (e.g., Observers) do not cause memory leaks.\n * @this {any}\n */\n disconnectedCallback () {\n if (this._abortController) {\n this._abortController.abort()\n }\n\n if (!this.componentOptions) {\n return\n }\n\n for (const hook of this._hooks.onDisconnected) {\n hook({\n state: this._state,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n element: this,\n options: this.componentOptions\n })\n }\n }\n\n /**\n * Invoked natively when an observed HTML attribute changes.\n * Coerces the raw string value based on the component's attribute schema\n * and synchronizes it into the reactive state proxy.\n * @param {string} name - The kebab-case name of the attribute.\n * @param {string|null} oldVal - The previous value.\n * @param {string|null} newVal - The new value.\n */\n attributeChangedCallback (name, oldVal, newVal) {\n if (!this._state || oldVal === newVal || name === 'data-cid') {\n return\n }\n const camelName = name.replace(/-([a-z])/g, (g) => g[1].toUpperCase())\n const schema = this.componentOptions.attributes?.[camelName] || this.componentOptions.attributes?.[name]\n const value = schema ? coerce(newVal, schema.type) : newVal\n\n this._state[camelName] = value\n }\n\n /**\n * Constructs the unified state object.\n * Merges `defaultValues`, JSON hydration payloads, and DOM attributes.\n * Defines getters (wrapping state in a Read-Only proxy) and applies the final Read/Write Proxy.\n * @this {any}\n * @private\n */\n _setupState () {\n const options = this.componentOptions\n const target = { ...options.defaultValues }\n\n /** @type {Array<{name: string, element: HTMLElement}>} */\n const refs = []\n if (options.hydrationMap && options.hydrationMap.refs) {\n for (const ref of options.hydrationMap.refs) {\n const uniqueRefValue = `${this._instanceId}__${ref.name}`\n\n if (!target[`ref_${ref.name}`]) {\n target[`ref_${ref.name}`] = uniqueRefValue\n }\n\n const node = this.getNodeByPath(ref.path)\n if (node) {\n if (node.setAttribute) {\n node.setAttribute('ref', uniqueRefValue)\n }\n refs.push({\n name: ref.name,\n element: node\n })\n }\n }\n }\n\n // Process initial attributes mapping\n for (const attr of this.attributes) {\n if (attr.name === 'data-cid') {\n continue\n }\n const camelName = attr.name.replace(/-([a-z])/g, (g) => g[1].toUpperCase())\n const schema = options.attributes?.[camelName] || options.attributes?.[attr.name]\n target[camelName] = schema ? coerce(attr.value, schema.type) : attr.value\n }\n\n // Hydrate data() block results from the SSR payload\n if (this._hydrationData && this._hydrationData[this._instanceId]) {\n Object.assign(target, this._hydrationData[this._instanceId])\n }\n\n // Trigger Before-Render hooks BEFORE state is proxied, allowing plugins to inject reactive data\n for (const hook of this._hooks.onBeforeComponentRender) {\n hook({\n state: target,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n refs,\n element: this,\n options: this.componentOptions\n })\n }\n\n // Define derived state getters with isolation controllers\n this._getterAbortControllers = {}\n for (const [key, getter] of Object.entries(options.getters || {})) {\n Object.defineProperty(target, key, {\n get: () => {\n if (this._getterAbortControllers[key]) {\n this._getterAbortControllers[key].abort()\n }\n this._getterAbortControllers[key] = new AbortController()\n\n // Enforce \"Dual-Proxy\" safety: Getters cannot mutate state\n const roState = createReadOnlyProxy(this._state)\n return getter(roState, { signal: this._getterAbortControllers[key].signal })\n },\n enumerable: true,\n configurable: true\n })\n }\n\n this._state = this._createReactiveProxy(target)\n }\n\n /**\n * Wraps the state target in a reactive Proxy.\n * Intercepts property setters to automatically batch and schedule DOM updates.\n * @param {Object} target - The state dictionary.\n * @returns {Proxy} The reactive state proxy.\n * @private\n */\n _createReactiveProxy (target) {\n const self = this\n return new Proxy(target, {\n set (t, p, v) {\n if (t[p] === v) {\n return true\n }\n t[p] = v\n self._scheduleUpdate()\n return true\n }\n })\n }\n\n /**\n * Traverses the DOM tree using an AST-generated path index array.\n * Allows O(1) element lookups without relying on querySelectors or classes.\n * @param {number[]} path - Array of childNode indices (e.g., `[0, 1, 2]`).\n * @returns {Node|null} The physical DOM node, or null if traversal fails.\n */\n getNodeByPath (path) {\n let node = this\n for (const index of path) {\n if (!node) {\n return null\n }\n // @ts-ignore\n node = node.childNodes[index]\n }\n return node\n }\n\n /**\n * Initializes DOM bindings based on the compiler's hydration map.\n * Caches physical DOM references to text nodes and attributes that contain template tokens.\n * @private\n */\n _setupBindings () {\n this._bindings = []\n const map = this.componentOptions.hydrationMap\n if (!map) {\n return\n }\n\n if (map.texts) {\n for (const item of map.texts) {\n const node = this.getNodeByPath(item.path)\n if (node) {\n this._bindings.push({\n type: item.type || 'text',\n node,\n template: item.template\n })\n }\n }\n }\n\n if (map.attributes) {\n for (const item of map.attributes) {\n const node = this.getNodeByPath(item.path)\n if (node) {\n this._bindings.push({\n type: 'attribute',\n node,\n name: item.name,\n template: item.template\n })\n }\n }\n }\n }\n\n /**\n * Schedules a DOM update in the next microtask queue.\n * This guarantees that multiple synchronous state mutations result in only one render pass.\n * @private\n */\n _scheduleUpdate () {\n if (this._isUpdatePending) {\n return\n }\n this._isUpdatePending = true\n queueMicrotask(() => {\n this._updateDOM()\n this._isUpdatePending = false\n })\n }\n\n /**\n * Performs the physical DOM update and resolves template tokens.\n * **Async Safety:** Implements a Symbol-based locking mechanism (`renderVersion`)\n * to guarantee that if state mutates while an async getter is pending, the stale\n * Promise will be discarded, preventing DOM race conditions.\n * @this {any}\n * @private\n */\n _updateDOM () {\n // Create a unique lock for this specific render cycle\n const renderVersion = Symbol()\n this._currentRenderVersion = renderVersion\n\n // Extract unique tokens to prevent double-reading and accidental aborts\n /** @type {Set<string>} */\n const requiredTokens = new Set()\n for (const binding of this._bindings) {\n binding.template.replace(/\\{\\{\\s*(.+?)\\s*\\}\\}/g, (_, key) => {\n requiredTokens.add(key)\n return ''\n })\n }\n\n const evaluatedTokens = {}\n let hasPromise = false\n\n // Evaluate getters exactly once per render cycle\n for (const key of requiredTokens) {\n let val = this._state[key]\n if (typeof val === 'function') {\n val = val(this._state)\n }\n evaluatedTokens[key] = val\n if (val instanceof Promise) {\n hasPromise = true\n }\n }\n\n // The DOM Mutator Function\n const applyBindings = (tokenValues) => {\n // Race Condition Lock: Abort if a newer render cycle has already begun\n if (this._currentRenderVersion !== renderVersion) {\n return\n }\n\n for (const binding of this._bindings) {\n const hydratedValue = binding.template.replace(/\\{\\{\\s*(.+?)\\s*\\}\\}/g, (_, key) => {\n return tokenValues[key] ?? ''\n })\n\n if (binding.type === 'text') {\n if (binding.node.textContent !== hydratedValue) {\n binding.node.textContent = hydratedValue\n }\n } else if (binding.type === 'html') {\n /** @type {HTMLElement} */\n // @ts-ignore\n const element = binding.node\n\n if (element.innerHTML !== hydratedValue) {\n element.innerHTML = hydratedValue\n }\n } else if (binding.type === 'attribute') {\n /** @type {HTMLElement} */\n // @ts-ignore\n const element = binding.node\n\n if (BOOLEAN_ATTRIBUTES.has(binding.name)) {\n const isFalsy = hydratedValue === '' || hydratedValue === 'false' || hydratedValue === 'null' || hydratedValue === '0' || hydratedValue === 'undefined'\n if (isFalsy) {\n element.removeAttribute(binding.name)\n } else {\n element.setAttribute(binding.name, '')\n }\n } else {\n if (element.getAttribute(binding.name) !== hydratedValue) {\n element.setAttribute(binding.name, hydratedValue)\n }\n }\n }\n }\n\n this._processSlots()\n\n // Trigger After-Render hooks ONLY after the physical DOM is stable\n for (const hook of this._hooks.onAfterComponentRender) {\n hook({\n state: this._state,\n instanceId: this._instanceId,\n componentId: this.componentOptions.componentId,\n element: this,\n options: this.componentOptions\n })\n }\n\n // @ts-ignore\n if (window.__coralite__ && window.__coralite__.lifecycle) {\n // @ts-ignore\n window.__coralite__.lifecycle._markInstanceRendered(this)\n }\n }\n\n // Await Promises or Apply Synchronously\n if (hasPromise) {\n const keys = Object.keys(evaluatedTokens)\n const promises = keys.map(k => Promise.resolve(evaluatedTokens[k]))\n\n Promise.all(promises).then(resolvedValues => {\n const resolvedMap = {}\n keys.forEach((k, i) => {\n resolvedMap[k] = resolvedValues[i]\n })\n applyBindings(resolvedMap)\n }).catch(e => {\n if (e.name !== 'AbortError') {\n console.error('Coralite Async Getter Error:', e)\n }\n })\n } else {\n applyBindings(evaluatedTokens)\n }\n }\n\n /**\n * Evaluates and projects Light DOM elements into their respective `<slot>` nodes.\n * Invokes component-specific slot transformation functions.\n * @private\n */\n _processSlots () {\n const slots = this.componentOptions.slots\n if (!slots || Object.keys(slots).length === 0) {\n return\n }\n\n const slotElements = this.querySelectorAll('slot')\n slotElements.forEach(slotEl => {\n const slotName = slotEl.getAttribute('name') || 'default'\n const slotFn = slots[slotName]\n\n if (slotFn) {\n // @ts-ignore\n if (!slotEl._originalNodes) {\n // @ts-ignore\n slotEl._originalNodes = Array.from(slotEl.childNodes).map(n => n.cloneNode(true))\n }\n\n // @ts-ignore\n const result = slotFn(slotEl._originalNodes, this._state)\n\n if (result === undefined) {\n return\n }\n\n if (result === null || result === '' || (Array.isArray(result) && result.length === 0)) {\n slotEl.innerHTML = ''\n return\n }\n\n if (typeof result === 'string') {\n slotEl.innerHTML = result\n } else if (Array.isArray(result)) {\n slotEl.replaceChildren(...result)\n }\n }\n })\n }\n\n /**\n * The final initialization pipeline.\n * Injects globally registered client plugins into the local context payload,\n * triggers the initial DOM render, and invokes the user's `script()` logic.\n * @param {boolean} [isImperative=false] - If true, initial render runs synchronously.\n * @private\n */\n async _init (isImperative = false) {\n const self = this\n /**\n * The context payload injected into the user's script block.\n * @type {Object}\n */\n let localContext = {\n instanceId: this._instanceId,\n state: this._state,\n root: this,\n signal: this._abortController.signal,\n refs (id) {\n const refId = self._state[`ref_${id}`]\n if (!refId && typeof refId !== 'string') {\n return null\n }\n return self.querySelector(`[ref=\"${refId}\"]`)\n }\n }\n\n if (typeof this._clientContextGetter === 'function') {\n localContext = await this._clientContextGetter(localContext)\n }\n\n if (isImperative) {\n this._updateDOM()\n } else {\n this._scheduleUpdate()\n }\n\n if (this.componentOptions.client) {\n try {\n await this.componentOptions.client(localContext)\n } catch (error) {\n console.error(`Coralite Error: Component \"${this.componentOptions.componentId}\" script failed:`, error)\n }\n }\n\n // @ts-ignore\n if (window.__coralite__ && window.__coralite__.lifecycle) {\n // @ts-ignore\n window.__coralite__.lifecycle._markInstanceReady(this)\n }\n }\n}\n\n/**\n * Factory function to create a Coralite element class.\n * It dynamically defines the class, including observed attributes and hook initialization.\n * @param {CoraliteComponentOptions} options - Component options and metadata.\n * @param {Function|null} [contextGetter=null] - Optional function to retrieve client-side plugin context.\n * @param {Object} [hooks={}] - Lifecycle hooks to register.\n * @param {Array<CoraliteClientPluginBeforeComponentRenderCallback>} [hooks.onBeforeComponentRender] - Hooks to run before render.\n * @param {Array<CoraliteClientPluginAfterComponentRenderCallback>} [hooks.onAfterComponentRender] - Hooks to run after render.\n * @param {Array<CoraliteClientPluginDisconnectedCallback>} [hooks.onDisconnected] - Hooks to run after render.\n * @param {Object|null} [hydrationData=null] - Hydrated data passed from the server.\n * @returns {typeof CoraliteElement} A new CoraliteElement subclass.\n */\nexport function createCoraliteClass (options, contextGetter = null, hooks = {}, hydrationData = null) {\n return class extends CoraliteElement {\n /**\n * The attributes to observe for changes.\n * @returns {string[]} Array of attribute names.\n */\n static get observedAttributes () {\n if (!options.attributes) {\n return []\n }\n return Object.keys(options.attributes).map(key => key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()\n )\n }\n\n /**\n * Initializes the dynamic Coralite element.\n */\n constructor () {\n super()\n this.componentOptions = options\n this._clientContextGetter = contextGetter\n this._hydrationData = hydrationData\n this._hooks = {\n onBeforeComponentRender: hooks.onBeforeComponentRender || [],\n onAfterComponentRender: hooks.onAfterComponentRender || [],\n onDisconnected: hooks.onDisconnected || []\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["target"]
7
7
  }
package/dist/lib/index.js CHANGED
@@ -2538,6 +2538,7 @@ function ScriptManager(options = {}) {
2538
2538
  this.scriptModules = [];
2539
2539
  this.options = options;
2540
2540
  this.context = null;
2541
+ this.virtualModules = /* @__PURE__ */ new Map();
2541
2542
  }
2542
2543
  ScriptManager.prototype.use = async function(plugin) {
2543
2544
  if (plugin && typeof plugin !== "function") {
@@ -2740,14 +2741,38 @@ ScriptManager.prototype.compileAllInstances = async function(instances, mode) {
2740
2741
  entryCodeParts.push(`import { createCoraliteClass } from ${JSON.stringify(coraliteElementPath)};
2741
2742
  `);
2742
2743
  entryCodeParts.push("\nexport { getClientContext, createCoraliteClass, globalClientHooks };\n");
2743
- const entryPoints = {
2744
- "coralite-runtime": entryCodeParts.join("").trimEnd()
2745
- };
2744
+ this.virtualModules.clear();
2745
+ this.virtualModules.set("coralite-runtime", entryCodeParts.join("").trimEnd());
2746
2746
  const processedComponent = {};
2747
2747
  for (const id of Object.keys(this.sharedFunctions)) {
2748
2748
  processedComponent[id] = true;
2749
2749
  }
2750
2750
  const processedComponentKeys = Object.keys(processedComponent).sort();
2751
+ if (mode === "development") {
2752
+ const currentEntryPoints = new Set(processedComponentKeys);
2753
+ currentEntryPoints.add("coralite-runtime");
2754
+ if (this.context) {
2755
+ let entryPointsChanged = false;
2756
+ if (this._lastEntryPoints) {
2757
+ if (this._lastEntryPoints.size !== currentEntryPoints.size) {
2758
+ entryPointsChanged = true;
2759
+ } else {
2760
+ for (const ep of currentEntryPoints) {
2761
+ if (!this._lastEntryPoints.has(ep)) {
2762
+ entryPointsChanged = true;
2763
+ break;
2764
+ }
2765
+ }
2766
+ }
2767
+ } else {
2768
+ entryPointsChanged = true;
2769
+ }
2770
+ if (entryPointsChanged) {
2771
+ await this.disposeContext();
2772
+ }
2773
+ }
2774
+ this._lastEntryPoints = currentEntryPoints;
2775
+ }
2751
2776
  const regex = /[-.:]/g;
2752
2777
  for (const componentId of processedComponentKeys) {
2753
2778
  const sharedFn = this.sharedFunctions[componentId];
@@ -2820,13 +2845,13 @@ export default {
2820
2845
  server: ${hasState ? `componentModule_${safeId}.state` : "null"}
2821
2846
  };
2822
2847
  `;
2823
- entryPoints[componentId] = componentEntryCode;
2848
+ this.virtualModules.set(componentId, componentEntryCode);
2824
2849
  }
2825
2850
  }
2826
2851
  const resolvedImportMap = {};
2827
2852
  const userImportMap = this.options?.importMap || {};
2828
2853
  const virtualEntryPoints = {};
2829
- for (const key of Object.keys(entryPoints)) {
2854
+ for (const key of this.virtualModules.keys()) {
2830
2855
  virtualEntryPoints[key] = `${virtualPrefix}${key}`;
2831
2856
  }
2832
2857
  const injectPath = fileURLToPath(import.meta.resolve("./utils/client/inject.js"));
@@ -2871,7 +2896,7 @@ export default {
2871
2896
  if (args.namespace === "coralite-virtual") {
2872
2897
  return null;
2873
2898
  }
2874
- if (args.path.startsWith(virtualPrefix) || args.path === "coralite-runtime" || Object.hasOwn(entryPoints, args.path)) {
2899
+ if (args.path.startsWith(virtualPrefix) || args.path === "coralite-runtime" || this.virtualModules.has(args.path)) {
2875
2900
  return null;
2876
2901
  }
2877
2902
  if (args.path === "coralite") {
@@ -2914,9 +2939,10 @@ export default {
2914
2939
  namespace: "coralite-virtual"
2915
2940
  }, (args) => {
2916
2941
  const path2 = args.path.replace(virtualPrefix, "");
2917
- if (entryPoints[path2]) {
2942
+ const virtualContent = this.virtualModules.get(path2);
2943
+ if (virtualContent) {
2918
2944
  return {
2919
- contents: entryPoints[path2],
2945
+ contents: virtualContent,
2920
2946
  loader: "js",
2921
2947
  resolveDir: process.cwd()
2922
2948
  };
@@ -3339,7 +3365,7 @@ var metadataPlugin = definePlugin({
3339
3365
 
3340
3366
  // plugins/static-assets.js
3341
3367
  import { createRequire } from "node:module";
3342
- import { dirname as dirname4, join as join2, parse as parse2 } from "node:path";
3368
+ import { dirname as dirname4, join as join2, parse as parse2, isAbsolute } from "node:path";
3343
3369
  import { existsSync as existsSync2 } from "node:fs";
3344
3370
  import { cp, mkdir, stat } from "node:fs/promises";
3345
3371
  function findPackageRoot(startDir) {
@@ -3359,19 +3385,23 @@ var staticAssetPlugin = (assets = []) => {
3359
3385
  name: "static-asset-plugin",
3360
3386
  server: {
3361
3387
  onBeforeBuild: async function(context2) {
3362
- const outputDir = context2.app.options.output || join2(process.cwd(), "dist");
3388
+ const projectRoot = context2.app.options.projectRoot || process.cwd();
3389
+ const outputDir = context2.app.options.output || join2(projectRoot, "dist");
3363
3390
  const copyTasks = [];
3364
3391
  for (const asset of assets) {
3365
3392
  if (!asset.dest) {
3366
3393
  throw new Error("staticAssetPlugin requires assets to have a dest property.");
3367
3394
  }
3368
- const dest = join2(outputDir, asset.dest);
3395
+ const dest = isAbsolute(asset.dest) ? asset.dest : join2(outputDir, asset.dest);
3369
3396
  let src = asset.src;
3397
+ if (src && !isAbsolute(src)) {
3398
+ src = join2(projectRoot, src);
3399
+ }
3370
3400
  if (!src) {
3371
3401
  if (!asset.pkg || !asset.path) {
3372
3402
  throw new Error("staticAssetPlugin requires assets to have pkg and path state when src is not provided.");
3373
3403
  }
3374
- const require2 = createRequire(join2(process.cwd(), "package.json"));
3404
+ const require2 = createRequire(join2(projectRoot, "package.json"));
3375
3405
  let pkgPath;
3376
3406
  try {
3377
3407
  pkgPath = dirname4(require2.resolve(`${asset.pkg}/package.json`));
@@ -4893,7 +4923,10 @@ function injectReadinessScript(root, head, hasScripts) {
4893
4923
  attribs: {},
4894
4924
  children: []
4895
4925
  });
4896
- const data = hasScripts ? "window.__coralite_ready__ = new Promise(resolve => { window.__coralite_resolve_ready__ = resolve; });" : "window.__coralite_ready__ = Promise.resolve(); window.__coralite_resolve_ready__ = () => {};";
4926
+ let data = "class CoraliteLifecycleManager { constructor() { this.defined = new Promise(r => this._dr = r); this.rendered = new Promise(r => this._rr = r); this.hydrated = new Promise(r => this._hr = r); this._t = 0; this._rc = 0; this._hc = 0; this._ts = 0; this._dt = new Set(); this._ip = new WeakMap(); this._ir = new WeakMap(); this._rs = new WeakSet(); this._hs = new WeakSet(); this._s = false; } _start(t, ts) { this._t = t; this._ts = ts; this._s = true; this._check(); } _check() { if (!this._s) return; if (this._rc >= this._t) this._rr(); if (this._hc >= this._t) this._hr(); if (this._dt.size >= this._ts) this._dr(); } _markDefined(tag) { this._dt.add(tag); this._check(); } _markInstanceRendered(el) { if (el.hasAttribute('data-coralite-initial') && !this._rs.has(el)) { this._rs.add(el); this._rc++; this._check(); } } _markInstanceReady(el) { const r = this._ir.get(el); r && r(); this._ip.set(el, Promise.resolve()); if (el.hasAttribute('data-coralite-initial') && !this._hs.has(el)) { this._hs.add(el); this._hc++; this._check(); } } waitFor(el) { let p = this._ip.get(el); if (!p) { p = new Promise(r => this._ir.set(el, r)); this._ip.set(el, p); } return p; } } window.__coralite__ = { lifecycle: new CoraliteLifecycleManager() };";
4927
+ if (!hasScripts) {
4928
+ data += " window.__coralite__.lifecycle._start(0, 0);";
4929
+ }
4897
4930
  readinessScriptElement.children.push(createCoraliteTextNode({
4898
4931
  type: "text",
4899
4932
  data,
@@ -4996,8 +5029,11 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
4996
5029
 
4997
5030
  (async () => {
4998
5031
  const hydrationData = ${hydrationData};
4999
- if (!window.__coralite_ready__) {
5000
- window.__coralite_ready__ = new Promise(resolve => { window.__coralite_resolve_ready__ = resolve; });
5032
+ const declarativeTags = ${JSON.stringify(declarativeTags)};
5033
+ const initialElements = Array.from(document.querySelectorAll('[data-coralite-initial]'))
5034
+ .filter(el => declarativeTags.includes(el.tagName.toLowerCase()));
5035
+ if (window.__coralite__ && window.__coralite__.lifecycle) {
5036
+ window.__coralite__.lifecycle._start(initialElements.length, declarativeTags.length);
5001
5037
  }
5002
5038
  globalThis.executableScripts = [];
5003
5039
  globalThis.globalAbortController = new AbortController();
@@ -5042,6 +5078,7 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
5042
5078
  }
5043
5079
  }
5044
5080
  customElements.define(id, createCoraliteClass(module.default, getClientContext, globalClientHooks, hydrationData));
5081
+ if (window.__coralite__ && window.__coralite__.lifecycle) window.__coralite__.lifecycle._markDefined(id);
5045
5082
  }
5046
5083
 
5047
5084
  // Upgrade any existing elements that might have been created before the definition was loaded
@@ -5058,15 +5095,9 @@ import { getClientContext, createCoraliteClass, globalClientHooks } from '${base
5058
5095
  return loadCache[componentId];
5059
5096
  };
5060
5097
 
5061
- const declarativeTags = ${JSON.stringify(declarativeTags)};
5062
-
5063
5098
  const loadPromises = declarativeTags.map(tagName => loadComponent(tagName));
5064
5099
  await Promise.all(loadPromises);
5065
5100
 
5066
- if (typeof window.__coralite_resolve_ready__ === 'function') {
5067
- window.__coralite_resolve_ready__();
5068
- }
5069
-
5070
5101
  window.createCoraliteElement = (tag, options) => {
5071
5102
  const el = document.createElement(tag, options);
5072
5103
  if (componentManifest[tag]) {
@@ -5316,6 +5347,7 @@ function createRenderer({
5316
5347
  node.attribs = {};
5317
5348
  }
5318
5349
  node.attribs["data-cid"] = slotContextId;
5350
+ node.attribs["data-coralite-initial"] = "";
5319
5351
  session.componentTags.add(node.name);
5320
5352
  }
5321
5353
  }
@@ -5724,6 +5756,7 @@ function createRenderer({
5724
5756
  customElement.attribs = {};
5725
5757
  }
5726
5758
  customElement.attribs["data-cid"] = childContextId;
5759
+ customElement.attribs["data-coralite-initial"] = "";
5727
5760
  session.componentTags.add(customElement.name);
5728
5761
  }
5729
5762
  }
@@ -5838,6 +5871,7 @@ function createRenderer({
5838
5871
  customElement.attribs = {};
5839
5872
  }
5840
5873
  customElement.attribs["data-cid"] = contextId;
5874
+ customElement.attribs["data-coralite-initial"] = "";
5841
5875
  mappedSessionObject.componentTags.add(customElement.name);
5842
5876
  }
5843
5877
  }