@relax.js/core 1.0.2 → 1.0.3
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/dist/collections/Index.d.ts +2 -0
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +4 -4
- package/dist/collections/index.mjs +1 -1
- package/dist/collections/index.mjs.map +4 -4
- package/dist/index.d.ts +0 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/i18n/locales/en/r-common.json", "../src/i18n/locales/en/r-pipes.json", "../src/i18n/locales/en/r-validation.json", "../src/i18n/locales/sv/r-common.json", "../src/i18n/locales/sv/r-pipes.json", "../src/i18n/locales/sv/r-validation.json", "../src/errors.ts", "../src/collections/LinkedList.ts", "../src/forms/FormValidator.ts", "../src/i18n/icu.ts", "../src/i18n/i18n.ts", "../src/forms/FormReader.ts", "../src/forms/ValidationRules.ts", "../src/forms/setFormData.ts", "../src/pipes.ts", "../src/html/html.ts", "../src/html/template.ts", "../src/templates/accessorParser.ts", "../src/templates/tokenizer.ts", "../src/templates/parseTemplate.ts", "../src/templates/NodeTemplate.ts", "../src/html/TableRenderer.ts", "../src/routing/types.ts", "../src/routing/NavigateRouteEvent.ts", "../src/routing/routeTargetRegistry.ts", "../src/routing/routeMatching.ts", "../src/routing/RouteLink.ts", "../src/routing/RoutingTarget.ts", "../src/routing/navigation.ts", "../src/DependencyInjection.ts", "../src/getParentComponent.ts", "../src/SequentialId.ts", "../src/http/http.ts", "../src/http/ServerSentEvents.ts", "../src/tools.ts"
|
|
4
|
-
"sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "/**\r\n * @module FormValidator\r\n * Form validation with support for native HTML5 validation and error summaries.\r\n * Provides automatic validation on submit with customizable behavior.\r\n *\r\n * @example\r\n * // Basic usage with submit callback\r\n * const form = document.querySelector('form');\r\n * const validator = new FormValidator(form, {\r\n * submitCallback: () => saveData()\r\n * });\r\n *\r\n * @example\r\n * // With auto-validation on input\r\n * const validator = new FormValidator(form, {\r\n * autoValidate: true,\r\n * useSummary: true\r\n * });\r\n */\r\n\r\n/**\r\n * Gets the human-readable field name from its associated label.\r\n */\r\nfunction getFieldName(element: HTMLElement): string | null {\r\n const id = element.getAttribute('id');\r\n if (id) {\r\n const form = element.closest('form');\r\n if (form) {\r\n const label = form.querySelector(`label[for=\"${id}\"]`) as HTMLLabelElement | null;\r\n if (label) {\r\n return label.textContent?.trim() || null;\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Configuration options for FormValidator.\r\n */\r\nexport interface ValidatorOptions {\r\n /** Validate on every input event, not just submit */\r\n autoValidate?: boolean;\r\n /** Show errors in a summary element instead of browser tooltips */\r\n useSummary?: boolean;\r\n /** Custom validation function called before native validation */\r\n customChecks?: (form: HTMLFormElement) => void;\r\n /** Always prevent default form submission */\r\n preventDefault?: boolean;\r\n /** Prevent default on validation failure (default: true) */\r\n preventDefaultOnFailed?: boolean;\r\n /** Callback invoked when form passes validation */\r\n submitCallback?: () => void;\r\n}\r\n\r\n/**\r\n * Form validation helper that integrates with HTML5 validation.\r\n * Supports error summaries, auto-validation, and custom submit handling.\r\n *\r\n * @example\r\n * // Prevent submission and handle manually\r\n * class MyComponent extends HTMLElement {\r\n * private validator: FormValidator;\r\n *\r\n * connectedCallback() {\r\n * const form = this.querySelector('form');\r\n * this.validator = new FormValidator(form, {\r\n * submitCallback: () => this.handleSubmit()\r\n * });\r\n * }\r\n *\r\n * private async handleSubmit() {\r\n * const data = readData(this.form);\r\n * await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // With error summary display\r\n * const validator = new FormValidator(form, {\r\n * useSummary: true,\r\n * autoValidate: true\r\n * });\r\n */\r\nexport class FormValidator {\r\n private errorSummary: HTMLDivElement;\r\n\r\n constructor(\r\n private form: HTMLFormElement,\r\n private options?: ValidatorOptions\r\n ) {\r\n if (!this.form) {\r\n throw new Error('Form must be specified.');\r\n }\r\n\r\n this.form.addEventListener('submit', (event) => {\r\n if (\r\n options?.preventDefault ||\r\n this.options?.submitCallback != null\r\n ) {\r\n event.preventDefault();\r\n }\r\n if (this.options?.customChecks) {\r\n this.options.customChecks(form);\r\n }\r\n\r\n if (this.validateForm()) {\r\n this.options?.submitCallback?.apply(this);\r\n } else {\r\n if (options?.preventDefaultOnFailed !== false) {\r\n event.preventDefault();\r\n }\r\n }\r\n });\r\n\r\n if (options?.autoValidate) {\r\n form.addEventListener('input', (/*e: InputEvent*/) => {\r\n this.validateForm();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Validates all form fields.\r\n * Uses native HTML5 validation and optionally displays an error summary.\r\n *\r\n * @returns true if form is valid, false otherwise\r\n */\r\n public validateForm(): boolean {\r\n const formElements = Array.from(\r\n this.form.querySelectorAll('input,textarea,select')\r\n ) as (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)[];\r\n let isFormValid = true;\r\n\r\n if (this.options?.useSummary !== true) {\r\n if (this.form.checkValidity()) {\r\n return true;\r\n }\r\n\r\n this.form.reportValidity();\r\n this.focusFirstErrorElement();\r\n return false;\r\n }\r\n\r\n const errorMessages: string[] = [];\r\n\r\n formElements.forEach((element) => {\r\n if (!element.checkValidity()) {\r\n isFormValid = false;\r\n const fieldName =\r\n getFieldName.call(this, element) ||\r\n element.name ||\r\n 'Unnamed Field';\r\n errorMessages.push(\r\n `${fieldName}: ${element.validationMessage}`\r\n );\r\n }\r\n });\r\n\r\n if (!isFormValid) {\r\n this.displayErrorSummary(errorMessages);\r\n this.focusFirstErrorElement();\r\n } else {\r\n this.clearErrorSummary();\r\n }\r\n\r\n return isFormValid;\r\n }\r\n\r\n /**\r\n * Displays a list of error messages in the summary element.\r\n *\r\n * @param messages - Array of error messages to display\r\n */\r\n public displayErrorSummary(messages: string[]) {\r\n this.clearErrorSummary();\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n\r\n const errorList = this.errorSummary.querySelector('ul');\r\n messages.forEach((message) => {\r\n const listItem = document.createElement('li');\r\n listItem.textContent = message;\r\n errorList.appendChild(listItem);\r\n });\r\n }\r\n\r\n private createErrorSummary() {\r\n const errorSummary = document.createElement('div');\r\n errorSummary.className = 'error-summary';\r\n errorSummary.style.color = 'red';\r\n errorSummary.setAttribute('role', 'alert');\r\n errorSummary.setAttribute('aria-live', 'assertive');\r\n errorSummary.setAttribute('aria-atomic', 'true');\r\n this.errorSummary = errorSummary;\r\n\r\n const errorList = document.createElement('ul');\r\n this.errorSummary.appendChild(errorList);\r\n\r\n this.form.prepend(errorSummary);\r\n }\r\n /**\r\n * Adds a single error to the summary display.\r\n *\r\n * @param fieldName - The name of the field with the error\r\n * @param message - The error message\r\n */\r\n public addErrorToSummary(fieldName: string, message: string) {\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n const errorList = this.errorSummary.querySelector('ul');\r\n const listItem = document.createElement('li');\r\n listItem.textContent = `${fieldName}: ${message}`;\r\n errorList.appendChild(listItem);\r\n }\r\n\r\n /**\r\n * Clears all errors from the summary display.\r\n */\r\n public clearErrorSummary() {\r\n if (this.errorSummary){\r\n this.errorSummary.querySelector('ul').innerHTML='';\r\n }\r\n }\r\n\r\n private focusFirstErrorElement() {\r\n const firstInvalidElement = this.form.querySelector(':invalid');\r\n if (\r\n firstInvalidElement instanceof HTMLElement &&\r\n document.activeElement !== firstInvalidElement\r\n ) {\r\n firstInvalidElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Finds a form element relative to the given element.\r\n * Searches parent first, then direct children.\r\n *\r\n * @param element - The element to search from\r\n * @returns The found form element\r\n * @throws Error if no form is found\r\n *\r\n * @example\r\n * class MyComponent extends HTMLElement {\r\n * connectedCallback() {\r\n * const form = FormValidator.FindForm(this);\r\n * new FormValidator(form);\r\n * }\r\n * }\r\n */\r\n public static FindForm(element: HTMLElement): HTMLFormElement {\r\n if (element.parentElement?.tagName == 'FORM') {\r\n return <HTMLFormElement>element.parentElement;\r\n } else {\r\n for (let i = 0; i < element.children.length; i++) {\r\n const child = element.children[i];\r\n if (child.tagName == 'FORM') {\r\n return <HTMLFormElement>child;\r\n }\r\n }\r\n }\r\n\r\n throw new Error(\r\n 'Parent or a direct child must be a FORM for class ' +\r\n element.constructor.name\r\n );\r\n }\r\n}\r\n", "/**\r\n * @module icu\r\n * ICU message format support for internationalization.\r\n * Provides pluralization, select, and value interpolation.\r\n *\r\n * @example\r\n * // Simple interpolation\r\n * formatICU('Hello, {name}!', { name: 'World' });\r\n * // Returns: 'Hello, World!'\r\n *\r\n * @example\r\n * // Pluralization\r\n * formatICU('{count, plural, one {# item} other {# items}}', { count: 5 });\r\n * // Returns: '5 items'\r\n *\r\n * @example\r\n * // Select\r\n * formatICU('{gender, select, male {He} female {She} other {They}}', { gender: 'female' });\r\n * // Returns: 'She'\r\n */\r\n\r\nconst pluralRulesCache = new Map<string, Intl.PluralRules>();\r\n\r\n/**\r\n * Function type for message formatters.\r\n * Implement this to provide custom message formatting.\r\n */\r\nexport type MessageFormatter = (\r\n message: string,\r\n values?: Record<string, any>,\r\n locale?: string\r\n) => string;\r\n\r\n\r\nfunction getPluralRule(locale: string): Intl.PluralRules {\r\n if (!pluralRulesCache.has(locale)) {\r\n pluralRulesCache.set(locale, new Intl.PluralRules(locale));\r\n }\r\n return pluralRulesCache.get(locale)!;\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Default ICU message formatter implementation.\r\n * Supports simple interpolation, pluralization with exact matches, and select.\r\n *\r\n * @param message - ICU format message string\r\n * @param values - Values to interpolate\r\n * @param locale - Locale for plural rules (default: 'en')\r\n * @returns Formatted message string\r\n *\r\n * @example\r\n * defaultFormatICU('{n, plural, =0 {none} one {# item} other {# items}}', { n: 0 }, 'en');\r\n * // Returns: 'none'\r\n *\r\n * @example\r\n * defaultFormatICU('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' });\r\n * // Returns: 'Full access'\r\n */\r\nexport function defaultFormatICU(\r\n message: string,\r\n values: Record<string, any>,\r\n locale: string = 'en'\r\n): string {\r\n return message.replace(\r\n /\\{(\\w+)(?:, (plural|select),((?:[^{}]*\\{[^{}]*\\})+))?\\}/g,\r\n (_, key, type, categoriesPart) => {\r\n const value = values[key];\r\n\r\n if (type === 'plural') {\r\n const exact = new RegExp(\r\n `=${escapeRegex(String(value))}\\\\s*\\\\{([^{}]*)\\\\}`\r\n ).exec(categoriesPart);\r\n if (exact) {\r\n return exact[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n\r\n const rules = getPluralRule(locale);\r\n const category = rules.select(value);\r\n const match =\r\n new RegExp(`${category}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`other\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n if (match) {\r\n return match[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n return String(value);\r\n }\r\n\r\n if (type === 'select') {\r\n const escaped = escapeRegex(String(value));\r\n const match =\r\n new RegExp(`\\\\b${escaped}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`\\\\bother\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n return match ? match[1] : String(value);\r\n }\r\n\r\n return value !== undefined ? String(value) : `{${key}}`;\r\n },\r\n );\r\n}\r\n\r\n/**\r\n * The active message formatter. Defaults to `defaultFormatICU`.\r\n * Can be replaced with `setMessageFormatter` for custom formatting.\r\n */\r\nexport let formatICU: MessageFormatter = defaultFormatICU;\r\n\r\n/**\r\n * Replaces the default message formatter with a custom implementation.\r\n * Use this to integrate with external i18n libraries like FormatJS.\r\n *\r\n * @param formatter - The custom formatter function\r\n *\r\n * @example\r\n * // Use FormatJS IntlMessageFormat\r\n * import { IntlMessageFormat } from 'intl-messageformat';\r\n *\r\n * setMessageFormatter((message, values, locale) => {\r\n * const fmt = new IntlMessageFormat(message, locale);\r\n * return fmt.format(values);\r\n * });\r\n */\r\nexport function setMessageFormatter(formatter: MessageFormatter) {\r\n formatICU = formatter;\r\n}", "/**\r\n * @module i18n\r\n * Internationalization support with namespace-based translations.\r\n * Uses ICU message format for pluralization, select, and formatting.\r\n *\r\n * @example\r\n * // Initialize locale\r\n * await setLocale('sv');\r\n *\r\n * // Use translations\r\n * const greeting = t('r-common:greeting', { name: 'John' });\r\n * const items = t('shop:items', { count: 5 });\r\n */\r\n\r\nimport { formatICU } from './icu';\r\n\r\ntype Locale = string;\r\ntype Namespace = string;\r\ntype TranslationMap = Record<string, string>;\r\ntype Translations = Record<Namespace, TranslationMap>;\r\n\r\nexport type MissingTranslationHandler = (\r\n key: string,\r\n namespace: string,\r\n locale: string,\r\n) => void;\r\n\r\n/**\r\n * Dispatched on `document` after `setLocale()` completes.\r\n * The `locale` property contains the new normalized locale code.\r\n *\r\n * @example\r\n * document.addEventListener('localechange', (e) => {\r\n * console.log(`Locale changed to ${e.locale}`);\r\n * this.render();\r\n * });\r\n */\r\nexport class LocaleChangeEvent extends Event {\r\n readonly locale: string;\r\n constructor(locale: string) {\r\n super('localechange', { bubbles: false });\r\n this.locale = locale;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface DocumentEventMap {\r\n localechange: LocaleChangeEvent;\r\n }\r\n}\r\n\r\nconst fallbackLocale: Locale = 'en';\r\nlet currentLocale: Locale = fallbackLocale;\r\nconst loadedNamespaces = new Set<Namespace>();\r\nconst translations: Translations = {};\r\nlet missingHandler: MissingTranslationHandler | null = null;\r\n\r\nfunction normalizeLocale(locale: string): string {\r\n return locale.toLowerCase().split('-')[0];\r\n}\r\n\r\n/**\r\n * Sets the current locale and loads the common namespace.\r\n * Clears previously loaded translations and dispatches a `localechange` event.\r\n *\r\n * @param locale - The locale code (e.g., 'en', 'sv', 'en-US')\r\n *\r\n * @example\r\n * await setLocale('sv');\r\n */\r\nexport async function setLocale(locale: string): Promise<void> {\r\n const normalized = normalizeLocale(locale);\r\n currentLocale = normalized;\r\n loadedNamespaces.clear();\r\n Object.keys(translations).forEach(ns => delete translations[ns]);\r\n await loadNamespace('r-common');\r\n if (typeof document !== 'undefined') {\r\n document.dispatchEvent(new LocaleChangeEvent(normalized));\r\n }\r\n}\r\n\r\n/**\r\n * Loads a translation namespace on demand.\r\n * Falls back to the default locale if translations are not found.\r\n *\r\n * @param namespace - The namespace to load (e.g., 'shop', 'errors')\r\n *\r\n * @example\r\n * await loadNamespace('shop');\r\n * const price = t('shop:priceLabel');\r\n */\r\nexport async function loadNamespace(namespace: Namespace): Promise<void> {\r\n if (loadedNamespaces.has(namespace)) return;\r\n\r\n try {\r\n const module = await import(`./locales/${currentLocale}/${namespace}.json`);\r\n translations[namespace] = module.default;\r\n loadedNamespaces.add(namespace);\r\n } catch (err) {\r\n if (currentLocale !== fallbackLocale) {\r\n const fallback = await import(`./locales/${fallbackLocale}/${namespace}.json`);\r\n translations[namespace] = fallback.default;\r\n loadedNamespaces.add(namespace);\r\n } else {\r\n console.warn(`i18n: Failed to load namespace '${namespace}' for locale '${currentLocale}'`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Loads multiple translation namespaces in parallel.\r\n *\r\n * @param namespaces - Array of namespace names to load\r\n *\r\n * @example\r\n * await loadNamespaces(['r-pipes', 'r-validation']);\r\n */\r\nexport async function loadNamespaces(namespaces: Namespace[]): Promise<void> {\r\n await Promise.all(namespaces.map(ns => loadNamespace(ns)));\r\n}\r\n\r\n/**\r\n * Translates a key with optional value interpolation.\r\n * Supports ICU message format for pluralization and select.\r\n *\r\n * @param fullKey - Translation key in format 'namespace:key' or just 'key' (uses 'r-common')\r\n * @param values - Values to interpolate into the message\r\n * @returns The translated string, or the key if not found\r\n *\r\n * @example\r\n * // Simple translation\r\n * t('greeting'); // Uses r-common:greeting\r\n *\r\n * // With namespace\r\n * t('errors:notFound');\r\n *\r\n * // With interpolation\r\n * t('welcome', { name: 'John' }); // \"Welcome, John!\"\r\n *\r\n * // With pluralization (ICU format)\r\n * t('items', { count: 5 }); // \"5 items\" or \"5 f\u00F6rem\u00E5l\"\r\n */\r\nexport function t(fullKey: string, values?: Record<string, any>): string {\r\n const [namespace, key] = fullKey.includes(':')\r\n ? fullKey.split(':')\r\n : ['r-common', fullKey];\r\n const message = translations[namespace]?.[key];\r\n if (!message) {\r\n if (missingHandler) missingHandler(key, namespace, currentLocale);\r\n return fullKey;\r\n }\r\n try {\r\n return formatICU(message, values, currentLocale) as string;\r\n } catch {\r\n return fullKey;\r\n }\r\n}\r\n\r\n/**\r\n * Returns the current locale code.\r\n *\r\n * @returns The normalized locale code (e.g., 'en', 'sv')\r\n */\r\nexport function getCurrentLocale(): string {\r\n return currentLocale;\r\n}\r\n\r\n/**\r\n * Registers a handler called when `t()` encounters a missing translation key.\r\n * Pass `null` to remove the handler.\r\n *\r\n * @param handler - Callback receiving the key, namespace, and locale\r\n *\r\n * @example\r\n * onMissingTranslation((key, ns, locale) => {\r\n * console.warn(`Missing: ${ns}:${key} [${locale}]`);\r\n * });\r\n */\r\nexport function onMissingTranslation(handler: MissingTranslationHandler | null): void {\r\n missingHandler = handler;\r\n}\r\n", "/**\r\n * @module FormReader\r\n * Utilities for reading form data into typed objects.\r\n * Handles type conversion based on input types and data-type attributes.\r\n *\r\n * @example\r\n * // Basic form reading\r\n * const form = document.querySelector('form');\r\n * const data = readData(form);\r\n *\r\n * // Type-safe mapping to a class instance\r\n * const user = mapFormToClass(form, new UserDTO());\r\n */\r\n\r\nimport { getCurrentLocale } from '../i18n/i18n';\r\n\r\n/**\r\n * Maps form field values to a class instance's properties.\r\n * Automatically converts values based on input types (checkbox, number, date).\r\n *\r\n * Form field names must match property names on the target instance.\r\n *\r\n * @template T - The type of the class instance\r\n * @param form - The HTML form element to read from\r\n * @param instance - The class instance to populate\r\n * @param options - Configuration options\r\n * @param options.throwOnMissingProperty - Throw if form field has no matching property\r\n * @param options.throwOnMissingField - Throw if class property has no matching form field\r\n * @returns The populated instance\r\n *\r\n * @example\r\n * class UserDTO {\r\n * name: string = '';\r\n * email: string = '';\r\n * age: number = 0;\r\n * newsletter: boolean = false;\r\n * }\r\n *\r\n * const form = document.querySelector('form');\r\n * const user = mapFormToClass(form, new UserDTO());\r\n * console.log(user.name, user.age, user.newsletter);\r\n *\r\n * @example\r\n * // With validation\r\n * const user = mapFormToClass(form, new UserDTO(), {\r\n * throwOnMissingProperty: true, // Catch typos in form field names\r\n * throwOnMissingField: true // Ensure all DTO fields are in form\r\n * });\r\n */\r\nexport function mapFormToClass<T extends object>(\r\n form: HTMLFormElement,\r\n instance: T,\r\n options: {\r\n throwOnMissingProperty?: boolean;\r\n throwOnMissingField?: boolean;\r\n } = {}\r\n): T {\r\n const formElements = form.querySelectorAll('input, select, textarea');\r\n\r\n formElements.forEach((element) => {\r\n if (!element.hasAttribute('name')) return;\r\n if (booleanAttr(element, 'disabled')) return;\r\n\r\n const propertyName = element.getAttribute('name')!;\r\n\r\n if (!(propertyName in instance)) {\r\n if (options.throwOnMissingProperty) {\r\n throw new Error(\r\n `Form field \"${propertyName}\" has no matching property in class instance`\r\n );\r\n }\r\n return;\r\n }\r\n\r\n const value = readElementValue(element);\r\n if (value === SKIP) return;\r\n\r\n (instance as Record<string, unknown>)[propertyName] = value;\r\n });\r\n\r\n if (options.throwOnMissingField) {\r\n const formFieldNames = new Set<string>();\r\n formElements.forEach((element) => {\r\n if (element.hasAttribute('name')) {\r\n formFieldNames.add(element.getAttribute('name')!);\r\n }\r\n });\r\n\r\n for (const prop in instance) {\r\n if (\r\n typeof instance[prop] !== 'function' &&\r\n Object.prototype.hasOwnProperty.call(instance, prop) &&\r\n !formFieldNames.has(prop)\r\n ) {\r\n throw new Error(\r\n `Class property \"${prop}\" has no matching form field`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return instance;\r\n}\r\n\r\n/**\r\n * Configuration options for form reading operations.\r\n */\r\nexport interface FormReaderOptions {\r\n /** Prefix to strip from field names when mapping to properties */\r\n prefix?: string;\r\n /** If true, checkboxes return their value instead of true/false */\r\n disableBinaryCheckbox?: boolean;\r\n /** If true, radio buttons return their value instead of true/false */\r\n disableBinaryRadioButton?: boolean;\r\n}\r\n\r\n/**\r\n * Gets the appropriate type converter function for a form element.\r\n * Uses the `data-type` attribute if present, otherwise infers from input type.\r\n *\r\n * @param element - The form element to get a converter for\r\n * @returns A function that converts string values to the appropriate type\r\n *\r\n * @example\r\n * // With data-type attribute\r\n * <input name=\"age\" data-type=\"number\" />\r\n * const converter = getDataConverter(input);\r\n * converter('42'); // Returns: 42 (number)\r\n *\r\n * @example\r\n * // Inferred from input type\r\n * <input type=\"checkbox\" name=\"active\" />\r\n * const converter = getDataConverter(checkbox);\r\n * converter('true'); // Returns: true (boolean)\r\n */\r\nexport function getDataConverter(element: HTMLElement): ConverterFunc {\r\n const dataType = element.getAttribute('data-type') as DataType | null;\r\n if (dataType) {\r\n return createConverterFromDataType(dataType);\r\n }\r\n\r\n if (element instanceof HTMLInputElement) {\r\n return createConverterFromInputType(element.type as InputType);\r\n }\r\n\r\n // Handle custom form-associated elements with checked property (boolean values)\r\n if ('checked' in element && typeof (element as any).checked === 'boolean') {\r\n return BooleanConverter as ConverterFunc;\r\n }\r\n\r\n return (str) => str;\r\n}\r\n\r\n\r\n/**\r\n * Reads all form data into a plain object with automatic type conversion.\r\n * Handles multiple values (e.g., multi-select) and custom form-associated elements.\r\n *\r\n * Type conversion is based on:\r\n * 1. `data-type` attribute if present (number, boolean, string, Date)\r\n * 2. Input type (checkbox, number, date, etc.)\r\n * 3. Falls back to string\r\n *\r\n * @param form - The HTML form element to read\r\n * @returns Object with property names matching field names\r\n *\r\n * @example\r\n * // HTML form\r\n * <form>\r\n * <input name=\"username\" value=\"john\" />\r\n * <input name=\"age\" type=\"number\" value=\"25\" />\r\n * <input name=\"active\" type=\"checkbox\" checked />\r\n * <select name=\"colors\" multiple>\r\n * <option value=\"red\" selected>Red</option>\r\n * <option value=\"blue\" selected>Blue</option>\r\n * </select>\r\n * </form>\r\n *\r\n * // Reading the form\r\n * const data = readData(form);\r\n * // Returns: { username: 'john', age: 25, active: true, colors: ['red', 'blue'] }\r\n *\r\n * @example\r\n * // With custom form elements\r\n * <form>\r\n * <r-input name=\"email\" value=\"test@example.com\" />\r\n * <r-checkbox name=\"terms\" checked />\r\n * </form>\r\n * const data = readData(form);\r\n 1*/\r\nexport function readData<T = Record<string, unknown>>(form: HTMLFormElement): T{\r\n const data: Record<string, unknown> = {};\r\n const formData = new FormData(form);\r\n const seen = new Set<string>();\r\n\r\n formData.forEach((_, name) => {\r\n if (seen.has(name)) return;\r\n seen.add(name);\r\n\r\n const values = formData.getAll(name);\r\n const element = form.elements.namedItem(name);\r\n const converter = element ? getDataConverter(element as HTMLElement) : (v: string) => v;\r\n\r\n if (values.length === 1) {\r\n const v = values[0];\r\n data[name] = typeof v === 'string' ? converter(v) : v;\r\n } else {\r\n data[name] = values.map(v => typeof v === 'string' ? converter(v) : v);\r\n }\r\n });\r\n\r\n for (let i = 0; i < form.elements.length; i++) {\r\n const el = form.elements[i] as HTMLInputElement;\r\n if (el.type === 'checkbox' && el.name && !seen.has(el.name)) {\r\n seen.add(el.name);\r\n data[el.name] = false;\r\n }\r\n }\r\n\r\n return data as T;\r\n}\r\n\r\n/**\r\n * Function type for converting string form values to typed values.\r\n */\r\nexport type ConverterFunc = (value: string) => unknown;\r\n\r\n/**\r\n * Supported data-type attribute values for explicit type conversion.\r\n */\r\nexport type DataType = 'number' | 'boolean' | 'string' | 'Date';\r\n\r\n/**\r\n * Supported HTML input types for automatic type inference.\r\n */\r\nexport type InputType =\r\n | 'tel'\r\n | 'text'\r\n | 'checkbox'\r\n | 'radio'\r\n | 'number'\r\n | 'color'\r\n | 'date'\r\n | 'datetime-local'\r\n | 'month'\r\n | 'week'\r\n | 'time';\r\n\r\n/**\r\n * Converts string values to booleans.\r\n * Handles 'true'/'false' strings and numeric values (>0 is true).\r\n *\r\n * @param value - String value to convert\r\n * @returns Boolean value or undefined if empty\r\n * @throws Error if value cannot be interpreted as boolean\r\n */\r\nexport function BooleanConverter(value?: string): boolean | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n\r\n const lower = value.toLowerCase();\r\n\r\n if (lower === 'true' || lower === 'on' || Number(value) > 0) {\r\n return true;\r\n }\r\n\r\n if (lower === 'false' || lower === 'off' || Number(value) <= 0) {\r\n return false;\r\n }\r\n\r\n throw new Error(\"Could not convert value '\" + value + \"' to boolean.\");\r\n}\r\n\r\n/**\r\n * Converts string values to numbers.\r\n *\r\n * @param value - String value to convert\r\n * @returns Number value or undefined if empty\r\n * @throws Error if value is not a valid number\r\n */\r\nexport function NumberConverter(value?: string): number | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n const nr = Number(value);\r\n if (!isNaN(nr)) {\r\n return nr;\r\n }\r\n throw new Error(\"Could not convert value '\" + value + \"' to number.\");\r\n}\r\n\r\n/**\r\n * Detects the order of day/month/year parts for a given locale\r\n * using `Intl.DateTimeFormat.formatToParts`.\r\n *\r\n * @example\r\n * getLocaleDateOrder('en-US') // ['month', 'day', 'year']\r\n * getLocaleDateOrder('sv') // ['year', 'month', 'day']\r\n * getLocaleDateOrder('de') // ['day', 'month', 'year']\r\n */\r\nfunction getLocaleDateOrder(locale: string): ('day' | 'month' | 'year')[] {\r\n const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(2024, 0, 15));\r\n return parts\r\n .filter((p): p is Intl.DateTimeFormatPart & { type: 'day' | 'month' | 'year' } =>\r\n p.type === 'day' || p.type === 'month' || p.type === 'year')\r\n .map(p => p.type);\r\n}\r\n\r\n/**\r\n * Converts string values to Date objects.\r\n * Supports both ISO format (`2024-01-15`) and locale-specific formats\r\n * (`01/15/2024` for en-US, `15.01.2024` for de, etc.) based on the\r\n * current i18n locale.\r\n *\r\n * @param value - Date string in ISO or locale format\r\n * @returns Date object\r\n * @throws Error if value is not a valid date\r\n *\r\n * @example\r\n * // ISO format (from <input type=\"date\">)\r\n * DateConverter('2024-01-15') // Date(2024, 0, 15)\r\n *\r\n * // Locale format (from <input type=\"text\" data-type=\"Date\">)\r\n * // with locale set to 'sv': 2024-01-15\r\n * // with locale set to 'en-US': 01/15/2024\r\n * // with locale set to 'de': 15.01.2024\r\n */\r\nexport function DateConverter(value: string): Date | undefined {\r\n if (!value || value === '') return undefined;\r\n\r\n if (/^\\d{4}-\\d{2}-\\d{2}(T|$)/.test(value)) {\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n\r\n const numericParts = value.split(/[\\/.\\-\\s]/);\r\n if (numericParts.length >= 3 && numericParts.every(p => /^\\d+$/.test(p))) {\r\n const locale = getCurrentLocale();\r\n const order = getLocaleDateOrder(locale);\r\n const mapped: Record<string, number> = {};\r\n order.forEach((type, i) => {\r\n mapped[type] = parseInt(numericParts[i], 10);\r\n });\r\n\r\n if (mapped.year !== undefined && mapped.month !== undefined && mapped.day !== undefined) {\r\n if (mapped.year < 100) mapped.year += 2000;\r\n const date = new Date(mapped.year, mapped.month - 1, mapped.day);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) {\r\n throw new Error('Invalid date format');\r\n }\r\n return date;\r\n}\r\n\r\n/**\r\n * Creates a converter function based on the data-type attribute value.\r\n *\r\n * @param dataType - The data-type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromDataType(dataType: DataType): ConverterFunc {\r\n switch (dataType) {\r\n case 'boolean':\r\n return BooleanConverter as ConverterFunc;\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n case 'Date':\r\n return DateConverter;\r\n case 'string':\r\n return (value) => (!value || value == '' ? undefined : value);\r\n default:\r\n throw new Error(`Unknown data-type \"${dataType}\".`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a converter function based on HTML input type.\r\n * Handles special types like checkbox, date, time, week, and month.\r\n *\r\n * @param inputType - The HTML input type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromInputType(inputType: InputType): ConverterFunc {\r\n switch (inputType) {\r\n case 'checkbox':\r\n return BooleanConverter as ConverterFunc;\r\n\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n\r\n case 'date':\r\n case 'datetime-local':\r\n return DateConverter;\r\n\r\n case 'month':\r\n return (value) => {\r\n const [year, month] = value.split('-').map(Number);\r\n return new Date(year, month - 1);\r\n };\r\n\r\n case 'week':\r\n return (value) => {\r\n const [year, week] = value.split('-W').map(Number);\r\n return { year, week };\r\n };\r\n\r\n case 'time':\r\n return (value) => {\r\n const [hours, minutes, seconds = 0] = value.split(':').map(Number);\r\n return { hours, minutes, seconds };\r\n };\r\n\r\n default:\r\n return (value) => (!value || value == '' ? undefined : value);\r\n }\r\n}\r\n\r\nfunction booleanAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n}\r\n\r\nconst SKIP = Symbol('skip');\r\n\r\nfunction readElementValue(element: Element): unknown {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n return booleanAttr(element, 'checked');\r\n }\r\n\r\n if (type === 'radio') {\r\n if (!booleanAttr(element, 'checked')) return SKIP;\r\n return el.value;\r\n }\r\n\r\n if (type === 'number') {\r\n return el.value ? Number(el.value) : null;\r\n }\r\n\r\n if (type === 'date') {\r\n return el.value ? new Date(el.value) : null;\r\n }\r\n\r\n if ('selectedOptions' in el && booleanAttr(element, 'multiple')) {\r\n return Array.from(el.selectedOptions as NodeListOf<HTMLOptionElement>)\r\n .map((o: HTMLOptionElement) => o.value);\r\n }\r\n\r\n if ('value' in el) {\r\n return el.value;\r\n }\r\n\r\n return undefined;\r\n}", "/**\r\n * @module ValidationRules\r\n * Form validation rules for use with FormValidator.\r\n * Provides declarative validation through decorators.\r\n *\r\n * Validation messages use the i18n system. Load the 'r-validation' namespace\r\n * for localized error messages:\r\n *\r\n * @example\r\n * await loadNamespace('r-validation');\r\n *\r\n * @example\r\n * // In HTML, use validation attributes\r\n * <input name=\"age\" data-validate=\"required range(0-120)\" />\r\n */\r\n\r\nimport { t } from '../i18n/i18n';\r\n\r\n/**\r\n * Context provided to validators during validation.\r\n */\r\nexport interface ValidationContext {\r\n /** The HTML input type (text, number, email, etc.) */\r\n inputType: string;\r\n /** The data-type attribute value if present */\r\n dataType?: string;\r\n /** Adds an error message to the validation result */\r\n addError(message: string): void;\r\n}\r\n\r\n/**\r\n * Interface for custom validators.\r\n */\r\ninterface Validator {\r\n /**\r\n * Validates the given value.\r\n * @param value - The string value to validate\r\n * @param context - Validation context with type info and error reporting\r\n */\r\n validate(value: string, context: ValidationContext): void;\r\n}\r\n\r\ninterface ValidatorRegistryEntry {\r\n validator: { new (): Validator };\r\n validInputTypes: string[];\r\n}\r\n\r\nconst validators: Map<string, ValidatorRegistryEntry> = new Map();\r\n\r\n/**\r\n * Decorator to register a validator class for a specific validation name.\r\n *\r\n * @param validationName - The name used in data-validate attribute\r\n * @param validInputTypes - Optional list of input types this validator applies to\r\n *\r\n * @example\r\n * @RegisterValidator('email')\r\n * class EmailValidation implements Validator {\r\n * validate(value: string, context: ValidationContext) {\r\n * if (!value.includes('@')) {\r\n * context.addError('Invalid email address');\r\n * }\r\n * }\r\n * }\r\n */\r\nexport function RegisterValidator(validationName: string, validInputTypes: string[] = []) {\r\n return function (target: { new (...args: unknown[]): Validator }) {\r\n validators.set(validationName, { validator: target, validInputTypes });\r\n };\r\n}\r\n\r\n/**\r\n * Looks up a registered validator by name.\r\n *\r\n * @param name - The validator name used in `data-validate`\r\n * @returns The registry entry, or `undefined` if not found\r\n */\r\nexport function getValidator(name: string): ValidatorRegistryEntry | undefined {\r\n return validators.get(name);\r\n}\r\n\r\n/**\r\n * Validates that a field has a non-empty value.\r\n * Use with `data-validate=\"required\"`.\r\n */\r\n@RegisterValidator('required')\r\nexport class RequiredValidation implements Validator {\r\n static create(rule: string): RequiredValidation | null {\r\n return rule === 'required' ? new RequiredValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() !== ''){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:required');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a numeric value falls within a specified range.\r\n * Use with `data-validate=\"range(min-max)\"`.\r\n *\r\n * @example\r\n * <input name=\"age\" type=\"number\" data-validate=\"range(0-120)\" />\r\n */\r\n@RegisterValidator('range', ['number'])\r\nexport class RangeValidation implements Validator {\r\n min: number;\r\n max: number;\r\n\r\n constructor(min: number, max: number) {\r\n this.min = min;\r\n this.max = max;\r\n }\r\n\r\n static create(rule: string): RangeValidation | null {\r\n const rangeMatch = rule.match(/^range\\((-?\\d+(?:\\.\\d+)?)-(-?\\d+(?:\\.\\d+)?)\\)$/);\r\n if (rangeMatch) {\r\n const [, min, max] = rangeMatch;\r\n return new RangeValidation(parseFloat(min), parseFloat(max));\r\n }\r\n return null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() === '') return;\r\n\r\n const num = parseFloat(value);\r\n if (!isNaN(num) && num >= this.min && num <= this.max){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage(value));\r\n }\r\n\r\n getMessage(actual: string): string {\r\n return t('r-validation:range', { min: this.min, max: this.max, actual });\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a value contains only numeric digits (0-9).\r\n * Use with `data-validate=\"digits\"`.\r\n */\r\n@RegisterValidator('digits', ['number'])\r\nexport class DigitsValidation implements Validator {\r\n static create(rule: string): DigitsValidation | null {\r\n return rule === 'digits' ? new DigitsValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (/^\\d+$/.test(value)){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:digits');\r\n }\r\n}\r\n", "/**\r\n * Sets form field values from a data object using the name attribute.\r\n * Supports dot notation for accessing nested properties and array handling.\r\n * \r\n * @param form - The HTML form element to populate\r\n * @param data - The data object containing values to set in the form\r\n * \r\n * @example\r\n * // Basic usage with flat object\r\n * const form = document.querySelector('form');\r\n * const data = { name: 'John', email: 'john@example.com' };\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with nested objects via dot notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * user: { \r\n * name: 'John', \r\n * contact: { \r\n * email: 'john@example.com' \r\n * } \r\n * } \r\n * };\r\n * // Form has fields with names like \"user.name\" and \"user.contact.email\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with simple arrays using [] notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * hobbies: ['Reading', 'Cycling', 'Cooking']\r\n * };\r\n * // Form has multiple fields with names like \"hobbies[]\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with array of objects using numeric indexers\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * users: [\r\n * { name: 'John', email: 'john@example.com' },\r\n * { name: 'Jane', email: 'jane@example.com' }\r\n * ]\r\n * };\r\n * // Form has fields with names like \"users[0].name\", \"users[1].email\", etc.\r\n * setFormData(form, data);\r\n */\r\nexport function setFormData(form: HTMLFormElement, data: object): void {\r\n const formElements = form.querySelectorAll('[name]');\r\n\r\n formElements.forEach(element => {\r\n\r\n const name = element.getAttribute('name');\r\n if (!name) return;\r\n\r\n // Handle simple array notation (e.g., hobbies[])\r\n if (name.endsWith('[]')) {\r\n const arrayName = name.slice(0, -2);\r\n const arrayValue = getValueByComplexPath(data, arrayName);\r\n\r\n if (Array.isArray(arrayValue)) {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox' || type === 'radio') {\r\n el.checked = arrayValue.includes(el.value);\r\n } else if ('options' in el && boolAttr(element, 'multiple')) {\r\n arrayValue.forEach(val => {\r\n const option = Array.from(el.options as HTMLOptionElement[])\r\n .find((opt: HTMLOptionElement) => opt.value === String(val));\r\n if (option) (option as HTMLOptionElement).selected = true;\r\n });\r\n } else if ('value' in el) {\r\n const allWithName = form.querySelectorAll(`[name=\"${name}\"]`);\r\n const idx = Array.from(allWithName).indexOf(element);\r\n if (idx >= 0 && idx < arrayValue.length) {\r\n el.value = String(arrayValue[idx]);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Handle complex paths with array indexers and dot notation\r\n const value = getValueByComplexPath(data, name);\r\n if (value === undefined || value === null) return;\r\n\r\n setElementValue(element, value);\r\n });\r\n }\r\n \r\n function getValueByComplexPath(obj: object, path: string): any {\r\n // Handle array indexers like users[0].name\r\n const segments = [];\r\n let currentSegment = '';\r\n let inBrackets = false;\r\n \r\n for (let i = 0; i < path.length; i++) {\r\n const char = path[i];\r\n \r\n if (char === '[' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n inBrackets = true;\r\n currentSegment += char;\r\n } else if (char === ']' && inBrackets) {\r\n currentSegment += char;\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n inBrackets = false;\r\n } else if (char === '.' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n } else {\r\n currentSegment += char;\r\n }\r\n }\r\n \r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n }\r\n \r\n return segments.reduce((result, segment) => {\r\n if (!result || typeof result !== 'object') return undefined;\r\n \r\n // Handle array indexer segments like [0]\r\n if (segment.startsWith('[') && segment.endsWith(']')) {\r\n const index = segment.slice(1, -1);\r\n return result[index];\r\n }\r\n \r\n return result[segment];\r\n }, obj);\r\n }\r\n \r\n function getValueByPath(obj: object, path: string): any {\r\n return path.split('.').reduce((o, key) => {\r\n return o && typeof o === 'object' ? o[key] : undefined;\r\n }, obj);\r\n }\r\n \r\n function setElementValue(element: Element, value: any): void {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n el.checked = Boolean(value);\r\n } else if (type === 'radio') {\r\n el.checked = el.value === String(value);\r\n } else if (type === 'date' && value instanceof Date) {\r\n el.value = value.toISOString().split('T')[0];\r\n } else if (type === 'datetime-local' && value instanceof Date) {\r\n const pad = (n: number) => String(n).padStart(2, '0');\r\n el.value = `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;\r\n } else if ('options' in el && boolAttr(element, 'multiple') && Array.isArray(value)) {\r\n const options = Array.from(el.options as HTMLOptionElement[]);\r\n const vals = value.map(String);\r\n options.forEach((opt: HTMLOptionElement) => {\r\n opt.selected = vals.includes(opt.value);\r\n });\r\n } else if ('value' in el) {\r\n el.value = String(value);\r\n }\r\n }\r\n\r\n function boolAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n }", "/**\r\n * @module pipes\r\n * Data transformation functions (pipes) for use in template expressions.\r\n * Pipes transform values for display, like formatting dates, currencies, or text.\r\n *\r\n * Locale-aware pipes (currency, date, daysAgo, pieces) use the i18n system\r\n * for formatting and translations. Call `setLocale()` before using these pipes.\r\n *\r\n * Pipes can be chained in templates: `{{value | uppercase | shorten:20}}`\r\n *\r\n * @example\r\n * // In templates\r\n * <span>{{user.name | uppercase}}</span>\r\n * <span>{{price | currency}}</span>\r\n * <span>{{createdAt | daysAgo}}</span>\r\n *\r\n * @example\r\n * // Programmatic usage\r\n * import { applyPipes, defaultPipes } from 'relaxjs';\r\n * const result = applyPipes('hello world', ['uppercase', 'shorten:8']);\r\n * // Returns: 'HELLO...'\r\n */\r\n\r\nimport { getCurrentLocale, t } from './i18n/i18n';\r\n\r\n/**\r\n * Type definition for pipe transformation functions.\r\n * Pipes take a value and optional arguments, returning a transformed value.\r\n *\r\n * @example\r\n * // Define a custom pipe\r\n * const reversePipe: PipeFunction = (value: string) => {\r\n * return value.split('').reverse().join('');\r\n * };\r\n */\r\nexport type PipeFunction = (value: any, ...args: any[]) => any;\r\n\r\n\r\n// =============================== Text manipulation pipes ===========================\r\n\r\n\r\n\r\n/**\r\n * Converts a string to uppercase\r\n * @param value The string to convert\r\n * @returns The uppercase string\r\n */\r\nexport function uppercasePipe(value: string): string {\r\n return String(value).toUpperCase();\r\n}\r\n\r\n/**\r\n * Converts a string to uppercase\r\n * @param value The string to convert\r\n * @returns The uppercase string\r\n */\r\nexport function trimPipe(value: string): string {\r\n return String(value).trimEnd().trimStart();\r\n}\r\n\r\n\r\n/**\r\n * Converts a string to lowercase\r\n * @param value The string to convert\r\n * @returns The lowercase string\r\n */\r\nexport function lowercasePipe(value: string): string {\r\n return String(value).toLowerCase();\r\n}\r\n\r\n/**\r\n * Capitalizes the first character of a string\r\n * @param value The string to capitalize\r\n * @returns The capitalized string\r\n */\r\nexport function capitalizePipe(value: string): string {\r\n const str = String(value);\r\n return str.charAt(0).toUpperCase() + str.slice(1);\r\n}\r\n\r\n/**\r\n * Shortens a string to a specified length and adds ellipsis.\r\n * @param value The string to shorten\r\n * @param length Maximum length including ellipsis\r\n * @returns The shortened string with ellipsis if needed\r\n */\r\nexport function shortenPipe(value: string, length: string): string {\r\n const str = String(value);\r\n const maxLength = parseInt(length, 10);\r\n return str.length > maxLength\r\n ? str.substring(0, maxLength - 3) + '...'\r\n : str;\r\n}\r\n\r\n// Formatting pipes\r\n/**\r\n * Formats a number as currency using the current locale.\r\n * Uses the i18n system's current locale for formatting.\r\n *\r\n * @param value The number to format\r\n * @param currency Currency code (defaults to USD)\r\n * @returns Formatted currency string\r\n *\r\n * @example\r\n * // In template: {{price | currency}} or {{price | currency:EUR}}\r\n * currencyPipe(1234.56); // \"$1,234.56\" (en) or \"1 234,56 $\" (sv)\r\n * currencyPipe(1234.56, 'SEK'); // \"SEK 1,234.56\" (en) or \"1 234,56 kr\" (sv)\r\n */\r\nexport function currencyPipe(value: number, currency: string = 'USD'): string {\r\n const locale = getCurrentLocale();\r\n return new Intl.NumberFormat(locale, {\r\n style: 'currency',\r\n currency\r\n }).format(value);\r\n}\r\n\r\n/**\r\n * Formats a date value according to the specified format.\r\n * Uses the i18n system's current locale for formatting.\r\n *\r\n * @param value Date value (string, number, or Date object)\r\n * @param format Format type: 'short', 'long', or default (ISO)\r\n * @returns Formatted date string\r\n *\r\n * @example\r\n * // In template: {{date | date:short}} or {{date | date:long}}\r\n * datePipe(new Date(), 'short'); // \"1/15/2024\" (en) or \"2024-01-15\" (sv)\r\n * datePipe(new Date(), 'long'); // \"Monday, January 15, 2024\" (en) or \"m\u00E5ndag 15 januari 2024\" (sv)\r\n */\r\nexport function datePipe(value: string | number | Date, format?: string): string {\r\n const date = new Date(value);\r\n const locale = getCurrentLocale();\r\n if (format === 'short') {\r\n return date.toLocaleDateString(locale);\r\n } else if (format === 'long') {\r\n return date.toLocaleDateString(locale, {\r\n weekday: 'long',\r\n year: 'numeric',\r\n month: 'long',\r\n day: 'numeric'\r\n });\r\n }\r\n return date.toISOString();\r\n}\r\n\r\n/**\r\n * Prints today, yesterday or X days ago.\r\n * Uses the i18n system for translations (requires pipes namespace loaded).\r\n *\r\n * @param value Date value (string, number, or Date object)\r\n * @returns Formatted relative date string\r\n *\r\n * @example\r\n * // In template: {{createdAt | daysAgo}}\r\n * // English: \"today\", \"yesterday\", \"3 days ago\"\r\n * // Swedish: \"idag\", \"ig\u00E5r\", \"3 dagar sedan\"\r\n */\r\nexport function daysAgoPipe(value: string | number | Date): string {\r\n if (!value) {\r\n return 'n/a';\r\n }\r\n\r\n const inputDate = new Date(value);\r\n const today = new Date();\r\n\r\n // Normalize times to midnight to compare only dates\r\n inputDate.setHours(0, 0, 0, 0);\r\n today.setHours(0, 0, 0, 0);\r\n\r\n const diffTime = today.getTime() - inputDate.getTime();\r\n const diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24));\r\n\r\n if (diffDays === 0) return t('r-pipes:today');\r\n if (diffDays === 1) return t('r-pipes:yesterday');\r\n return t('r-pipes:daysAgo', { count: diffDays });\r\n}\r\n\r\n/**\r\n * Formats a count as pieces/items.\r\n * Uses the i18n system for translations (requires pipes namespace loaded).\r\n *\r\n * @param value Count value\r\n * @returns Formatted piece count string\r\n *\r\n * @example\r\n * // In template: {{quantity | pieces}}\r\n * // English: \"none\", \"one\", \"3 pcs\"\r\n * // Swedish: \"inga\", \"en\", \"3 st\"\r\n */\r\nexport function piecesPipe(value: string | number): string {\r\n if (value === null || value === undefined) {\r\n return 'n/a';\r\n }\r\n\r\n const count = Number(value);\r\n return t('r-pipes:pieces', { count });\r\n}\r\n\r\n\r\n\r\n// =============================== Array operation pipes ===========================\r\n\r\n\r\n\r\n/**\r\n * Joins array elements with the specified separator\r\n * @param value Array to join\r\n * @param separator Character(s) to use between elements (defaults to comma)\r\n * @returns Joined string or original value if not an array\r\n */\r\nexport function joinPipe(value: any[], separator: string = ','): string | any {\r\n if (!Array.isArray(value)) return value;\r\n return value.join(separator);\r\n}\r\n\r\n/**\r\n * Returns the first element of an array\r\n * @param value Array to extract from\r\n * @returns First element or empty string if array is empty/invalid\r\n */\r\nexport function firstPipe(value: any[]): any {\r\n if (!Array.isArray(value) || value.length === 0) return '';\r\n return value[0];\r\n}\r\n\r\n/**\r\n * Returns the last element of an array\r\n * @param value Array to extract from\r\n * @returns Last element or empty string if array is empty/invalid\r\n */\r\nexport function lastPipe(value: any[]): any {\r\n if (!Array.isArray(value) || value.length === 0) return '';\r\n return value[value.length - 1];\r\n}\r\n\r\n// Object operation pipes\r\n/**\r\n * Returns the keys of an object\r\n * @param value Object to extract keys from\r\n * @returns Array of object keys or empty array if not an object\r\n */\r\nexport function keysPipe(value: object): string[] {\r\n if (typeof value !== 'object' || value === null) return [];\r\n return Object.keys(value);\r\n}\r\n\r\n// Conditional pipes\r\n/**\r\n * Returns a default value if the input is falsy\r\n * @param value Input value to check\r\n * @param defaultValue Value to return if input is falsy\r\n * @returns Original value or default value\r\n */\r\nexport function defaultPipe(value: any, defaultValue: string): any {\r\n return value || defaultValue;\r\n}\r\n\r\n/**\r\n * Implements ternary operator as a pipe\r\n * @param value Condition to evaluate\r\n * @param trueValue Value to return if condition is truthy\r\n * @param falseValue Value to return if condition is falsy\r\n * @returns Selected value based on condition\r\n */\r\nexport function ternaryPipe(value: any, trueValue: string, falseValue: string): string {\r\n return value ? trueValue : falseValue;\r\n}\r\n\r\n\r\n\r\n// =============================== Pipe registry and application ===========================\r\n\r\n\r\n/**\r\n * Interface for a collection of pipe functions.\r\n * Use this to look up pipes by name for template processing.\r\n *\r\n * @example\r\n * // Check if a pipe exists before using\r\n * if (registry.has('currency')) {\r\n * const formatted = registry.get('currency')(price);\r\n * }\r\n */\r\nexport interface PipeRegistry {\r\n /**\r\n * Looks up a pipe by name, returning null if not found.\r\n */\r\n lookup(name: string): PipeFunction | null;\r\n\r\n /**\r\n * Gets a pipe by name, throwing if not found.\r\n */\r\n get(name: string): PipeFunction;\r\n\r\n /**\r\n * Checks if a pipe with the given name exists.\r\n */\r\n has(name: string): boolean;\r\n}\r\n\r\n\r\n/**\r\n * Creates a new pipe registry with all built-in pipes registered.\r\n * Built-in pipes include:\r\n *\r\n * **Text:** uppercase, lowercase, capitalize, trim, shorten\r\n * **Formatting:** currency, date, daysAgo, pieces\r\n * **Arrays:** join, first, last\r\n * **Objects:** keys\r\n * **Conditionals:** default, ternary\r\n *\r\n * @returns A new pipe registry instance\r\n *\r\n * @example\r\n * const registry = createPipeRegistry();\r\n * const upperPipe = registry.get('uppercase');\r\n * console.log(upperPipe('hello')); // 'HELLO'\r\n */\r\nexport function createPipeRegistry(): PipeRegistry {\r\n const pipes = new Map<string, PipeFunction>();\r\n\r\n // Text manipulation\r\n pipes.set('uppercase', uppercasePipe);\r\n pipes.set('lowercase', lowercasePipe);\r\n pipes.set('capitalize', capitalizePipe);\r\n pipes.set('trim', trimPipe);\r\n pipes.set('shorten', shortenPipe);\r\n\r\n // Formatting\r\n pipes.set('currency', currencyPipe);\r\n pipes.set('date', datePipe);\r\n pipes.set('daysAgo', daysAgoPipe);\r\n pipes.set('pieces', piecesPipe);\r\n\r\n // Array operations\r\n pipes.set('join', joinPipe);\r\n pipes.set('first', firstPipe);\r\n pipes.set('last', lastPipe);\r\n\r\n // Object operations\r\n pipes.set('keys', keysPipe);\r\n\r\n // Conditional formatting\r\n pipes.set('default', defaultPipe);\r\n pipes.set('ternary', ternaryPipe);\r\n\r\n return {\r\n lookup(name) {\r\n return pipes.get(name);\r\n },\r\n get(name) {\r\n var pipe = pipes.get(name);\r\n if (!pipe) {\r\n throw Error(\"Pipe '\" + name + \"' not found.\");\r\n }\r\n return pipe;\r\n },\r\n has(name) {\r\n return pipes.has(name);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Default pipe registry instance with all built-in pipes.\r\n * Used by template engines unless a custom registry is provided.\r\n *\r\n * @example\r\n * import { defaultPipes } from 'relaxjs';\r\n *\r\n * if (defaultPipes.has('uppercase')) {\r\n * const result = defaultPipes.get('uppercase')('hello');\r\n * }\r\n */\r\nexport const defaultPipes = createPipeRegistry();\r\n\r\n/**\r\n * Applies a series of pipes to a value sequentially.\r\n * Each pipe transforms the output of the previous pipe.\r\n *\r\n * Pipe arguments are specified after a colon: `shorten:20`\r\n *\r\n * @param value - Initial value to transform\r\n * @param pipes - Array of pipe strings (name and optional arguments separated by ':')\r\n * @param registry - Optional custom pipe registry (uses defaultPipes if not provided)\r\n * @returns The transformed value after applying all pipes\r\n *\r\n * @example\r\n * // Apply single pipe\r\n * applyPipes('hello', ['uppercase']); // 'HELLO'\r\n *\r\n * @example\r\n * // Chain multiple pipes\r\n * applyPipes('hello world', ['uppercase', 'shorten:8']); // 'HELLO...'\r\n *\r\n * @example\r\n * // With pipe arguments\r\n * applyPipes(1234.56, ['currency']); // '$1,234.56'\r\n */\r\nexport function applyPipes(\r\n value: any,\r\n pipes: string[],\r\n registry: PipeRegistry = defaultPipes\r\n): any {\r\n\r\n return pipes.reduce((currentValue, pipe) => {\r\n const [pipeName, ...args] = pipe.split(':').map((p) => p.trim());\r\n\r\n if (!registry.has(pipeName)) {\r\n return `[Pipe ${pipeName} not found]`;\r\n }\r\n\r\n try {\r\n return registry.get(pipeName)(currentValue, ...args);\r\n } catch (error) {\r\n return `[Pipe ${pipeName}, value: ${value}, error: ${error}]`;\r\n }\r\n }, value);\r\n}", "/**\r\n * @module html\r\n * HTML template engine with update capabilities.\r\n * Creates templates that can be re-rendered with new data without recreating DOM nodes.\r\n */\r\n\r\nimport { defaultPipes } from \"../pipes\";\r\n\r\nconst pipes = defaultPipes;\r\n\r\ninterface Binding {\r\n originalValue?: unknown;\r\n setter: (instance: unknown) => void;\r\n}\r\n\r\n/**\r\n * Result of rendering a template.\r\n * Provides the DOM fragment and an update function for re-rendering.\r\n */\r\nexport interface RenderTemplate {\r\n /** The rendered DOM fragment */\r\n fragment: DocumentFragment;\r\n /** Updates the DOM with new data without recreating elements */\r\n update(context: any): void;\r\n}\r\n\r\n/**\r\n * Creates an updateable HTML template using tagged template literals.\r\n * Returns an object with the fragment and an update method for efficient re-rendering.\r\n *\r\n * Supports:\r\n * - Template literal substitutions (`${}`)\r\n * - Mustache-style bindings (`{{property}}`)\r\n * - Pipe transformations (`{{value|uppercase}}`)\r\n * - Event handler binding\r\n *\r\n * @param templateStrings - The static parts of the template literal\r\n * @param substitutions - The dynamic values interpolated into the template\r\n * @returns A function that takes context and returns a RenderTemplate\r\n *\r\n * @example\r\n * // Create and render a template\r\n * const template = html`\r\n * <div class=\"user\">\r\n * <h2>{{name}}</h2>\r\n * <p>{{email}}</p>\r\n * <span>{{createdAt|daysAgo}}</span>\r\n * </div>\r\n * `;\r\n *\r\n * const result = template({ name: 'John', email: 'john@example.com', createdAt: new Date() });\r\n * container.appendChild(result.fragment);\r\n *\r\n * // Later, update with new data\r\n * result.update({ name: 'Jane', email: 'jane@example.com', createdAt: new Date() });\r\n *\r\n * @example\r\n * // With event handlers\r\n * const row = html`\r\n * <tr>\r\n * <td>{{name}}</td>\r\n * <td><button onclick=${function() { this.edit(this.id) }}>Edit</button></td>\r\n * </tr>\r\n * `;\r\n */\r\nexport function html(\r\n templateStrings: TemplateStringsArray,\r\n ...substitutions: any[]\r\n): (context: any) => RenderTemplate {\r\n // Preprocess template strings\r\n const template = document.createElement(\"template\");\r\n const resolvedTemplate = resolveTemplate(templateStrings);\r\n template.innerHTML = resolvedTemplate;\r\n const bindings: Binding[] = [];\r\n\r\n const walker = document.createTreeWalker(\r\n template.content,\r\n NodeFilter.SHOW_ALL\r\n );\r\n let node: Node | null;\r\n\r\n while ((node = walker.nextNode())) {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n processElement(element, substitutions, bindings);\r\n if (customElements.get(element.tagName.toLowerCase())) {\r\n customElements.upgrade(element);\r\n }\r\n } else if (node.nodeType === Node.TEXT_NODE) {\r\n const myNode = node;\r\n const text = myNode.textContent!;\r\n const result = parseTemplate(text, substitutions);\r\n if (result) {\r\n const hasSubstitutions = /\u20AC\u20AC\\d+\u20AC\u20AC/.test(text);\r\n if (hasSubstitutions) {\r\n let startMarker: Comment | null = null;\r\n let endMarker: Comment | null = null;\r\n let insertedNodes: Node[] = [];\r\n bindings.push({\r\n originalValue: text,\r\n setter(instance) {\r\n var value = result(instance);\r\n if (!startMarker) {\r\n startMarker = document.createComment('');\r\n endMarker = document.createComment('');\r\n myNode.parentNode?.replaceChild(endMarker, myNode);\r\n endMarker.parentNode?.insertBefore(startMarker, endMarker);\r\n }\r\n insertedNodes.forEach(n => n.parentNode?.removeChild(n));\r\n insertedNodes = [];\r\n const temp = document.createElement('template');\r\n temp.innerHTML = value;\r\n const nodes = Array.from(temp.content.childNodes);\r\n const parent = endMarker!.parentNode!;\r\n nodes.forEach(n => {\r\n parent.insertBefore(n, endMarker);\r\n insertedNodes.push(n);\r\n });\r\n },\r\n });\r\n } else {\r\n bindings.push({\r\n originalValue: text,\r\n setter(instance) {\r\n var value = result(instance);\r\n myNode.textContent = value;\r\n },\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Return a function for binding\r\n return function bind(context: any): RenderTemplate {\r\n bindings.forEach((x) => {\r\n x.setter(context);\r\n });\r\n\r\n return {\r\n fragment: template.content,\r\n update(context: any) {\r\n bindings.forEach((x) => {\r\n x.setter(context);\r\n });\r\n },\r\n };\r\n };\r\n}\r\n\r\nfunction resolveTemplate(templateStrings: TemplateStringsArray): string {\r\n return templateStrings.raw\r\n .map((str, i) =>\r\n i < templateStrings.raw.length - 1 ? `${str}\u20AC\u20AC${i}\u20AC\u20AC` : str\r\n )\r\n .join(\"\");\r\n}\r\n\r\nfunction processElement(\r\n element: HTMLElement,\r\n substitutions: any[],\r\n bindings: Binding[]\r\n) {\r\n const attrBindings: Binding[] = [];\r\n\r\n for (const attr of Array.from(element.attributes)) {\r\n var attrValue = attr.value;\r\n if (attrValue == \"\") {\r\n continue;\r\n }\r\n\r\n const regex = /\u20AC\u20AC(\\d+)\u20AC\u20AC/;\r\n const match = attrValue.match(regex);\r\n if (match) {\r\n const index = parseInt(match[1], 10);\r\n const func = substitutions[index];\r\n if (typeof func === \"function\") {\r\n attrBindings.push({\r\n setter(instance) {\r\n const boundFunction = func.bind(instance);\r\n element.removeAttribute(attr.name);\r\n element[attr.name] = boundFunction;\r\n },\r\n });\r\n\r\n continue;\r\n }\r\n }\r\n\r\n var attributeCallback = parseTemplate(attrValue, substitutions);\r\n if (attributeCallback == null) {\r\n continue;\r\n }\r\n\r\n attrBindings.push({\r\n originalValue: attrValue,\r\n setter(instance) {\r\n const value = attributeCallback!(instance) ?? attrValue;\r\n if (attr.name in element) {\r\n element[attr.name] = value;\r\n } else {\r\n attr.value = value;\r\n }\r\n },\r\n });\r\n }\r\n\r\n if (attrBindings.length > 0) {\r\n bindings.push({\r\n originalValue: element.tagName,\r\n setter(instance) {\r\n attrBindings.forEach((attrBinding) => attrBinding.setter(instance));\r\n },\r\n });\r\n }\r\n}\r\n\r\ntype TemplateCallback = (instance: any) => string;\r\n\r\n\r\n/**\r\n * Parse arguments for function calls in mustache expressions\r\n * Handles dot notation like row.id and nested properties\r\n */\r\nfunction parseArguments(argsStr: string, instance: any): any[] {\r\n return argsStr.split(',').map(arg => {\r\n arg = arg.trim();\r\n\r\n if ((arg.startsWith('\"') && arg.endsWith('\"')) ||\r\n (arg.startsWith(\"'\") && arg.endsWith(\"'\"))) {\r\n return arg.slice(1, -1);\r\n }\r\n\r\n if (!isNaN(Number(arg))) {\r\n return Number(arg);\r\n }\r\n\r\n if (arg.includes('.')) {\r\n const parts = arg.split('.');\r\n let value = instance;\r\n for (const part of parts) {\r\n if (value === undefined || value === null) return undefined;\r\n value = value[part];\r\n }\r\n return value;\r\n }\r\n\r\n // Handle simple variable references\r\n return instance[arg];\r\n });\r\n}\r\n\r\n\r\nfunction parseTemplate(\r\n template: string,\r\n substitutions: any[]\r\n): TemplateCallback | null {\r\n const regex = /\u20AC\u20AC(\\d+)\u20AC\u20AC|{{\\s*([^|]+?)(?:\\|([\\w|]+))?\\s*}}/g;\r\n let lastIndex = 0;\r\n let match;\r\n\r\n const textBindings: TemplateCallback[] = [];\r\n while ((match = regex.exec(template)) !== null) {\r\n var value = template.slice(lastIndex, match.index);\r\n if (value.length > 0) {\r\n textBindings.push((_instance) => {\r\n return value;\r\n });\r\n }\r\n\r\n // ${}\r\n if (match[1]) {\r\n const index = parseInt(match[1], 10);\r\n const sub = substitutions[index];\r\n if (!sub) {\r\n continue;\r\n }\r\n\r\n if (typeof sub === \"function\") {\r\n const func = sub as Function;\r\n textBindings.push((instance) => {\r\n var result = func.apply(instance);\r\n return result;\r\n });\r\n } else {\r\n if (sub && sub.length > 0) {\r\n textBindings.push((instance) => {\r\n return sub;\r\n });\r\n }\r\n }\r\n } else if (match[2]) {\r\n // {{mustache|pipes}} case\r\n const mustacheName = match[2].trim();\r\n const argsStr = match[3] ? match[3].trim() : null;\r\n const matchingPipes = match[4]\r\n ? match[4].split(\"|\").map((pipe) => pipe.trim())\r\n : [];\r\n\r\n textBindings.push((instance) => {\r\n var value = instance[mustacheName];\r\n\r\n if (typeof value === \"function\") {\r\n if (argsStr) {\r\n const args = parseArguments(argsStr, instance);\r\n value = value.apply(instance, args);\r\n } else {\r\n value = value.call(instance);\r\n }\r\n }\r\n\r\n matchingPipes.forEach((pipe) => {\r\n value = pipes[pipe](value);\r\n });\r\n return value;\r\n });\r\n }\r\n\r\n lastIndex = regex.lastIndex;\r\n }\r\n\r\n if (textBindings.length == 0) {\r\n return null;\r\n }\r\n\r\n var val = template.slice(lastIndex);\r\n if (val.length > 0) {\r\n textBindings.push((_) => {\r\n return val;\r\n });\r\n }\r\n return (instance) => {\r\n var result = \"\";\r\n textBindings.forEach((binding) => {\r\n var value = binding(instance);\r\n result += value;\r\n });\r\n\r\n return result;\r\n };\r\n}\r\n", "/**\r\n * @module template\r\n * DOM-based template engine with reactive rendering capabilities.\r\n *\r\n * Compiles HTML templates with mustache-style expressions into efficient\r\n * render functions that update the DOM when data changes.\r\n *\r\n * **Features:**\r\n * - Text interpolation: `{{name}}`, `{{user.profile.email}}`\r\n * - Attribute binding: `<div class=\"{{className}}\">`\r\n * - Pipes: `{{price | currency}}`, `{{name | uppercase | shorten:20}}`\r\n * - Function calls: `{{formatDate(createdAt)}}`, `{{add(5, 3)}}`\r\n * - Array indexing: `{{items[0]}}`, `{{users[1].name}}`\r\n * - Conditionals: `<div if=\"isVisible\">`, `<div unless=\"isHidden\">`\r\n * - Loops: `<li loop=\"item in items\">{{item.name}}</li>`\r\n *\r\n * @example\r\n * // Basic usage\r\n * import { compileTemplate } from './m';\r\n *\r\n * const { content, render } = compileTemplate(`\r\n * <div class=\"card\">\r\n * <h2>{{title}}</h2>\r\n * <p>{{description}}</p>\r\n * </div>\r\n * `);\r\n *\r\n * render({ title: 'Hello', description: 'World' });\r\n * document.body.appendChild(content);\r\n *\r\n * @example\r\n * // With pipes and functions\r\n * import { createPipeRegistry } from '../pipes';\r\n *\r\n * const pipeRegistry = createPipeRegistry();\r\n * const { content, render } = compileTemplate(`\r\n * <span>{{user.name | uppercase}}</span>\r\n * <span>{{formatDate(user.createdAt)}}</span>\r\n * `, { strict: false, pipeRegistry });\r\n *\r\n * render(\r\n * { user: { name: 'john', createdAt: new Date() } },\r\n * { formatDate: (d) => d.toLocaleDateString() }\r\n * );\r\n *\r\n * @example\r\n * // With loops and conditionals\r\n * const { content, render } = compileTemplate(`\r\n * <ul>\r\n * <li loop=\"item in items\" if=\"item.visible\">\r\n * {{item.name}}: {{item.price | currency}}\r\n * </li>\r\n * </ul>\r\n * `);\r\n *\r\n * render({ items: [\r\n * { name: 'Apple', price: 1.5, visible: true },\r\n * { name: 'Hidden', price: 0, visible: false }\r\n * ]});\r\n */\r\n\r\nimport { PipeRegistry, defaultPipes, applyPipes } from '../pipes';\r\n\r\n/**\r\n * Configuration options for the template engine.\r\n *\r\n * @example\r\n * const config: EngineConfig = {\r\n * strict: true,\r\n * onError: (msg) => console.error(msg),\r\n * pipeRegistry: createPipeRegistry()\r\n * };\r\n */\r\nexport interface EngineConfig {\r\n /** When true, throws errors for missing paths/functions. When false, returns empty string. */\r\n strict: boolean;\r\n /** Optional callback invoked when errors occur, receives formatted error message. */\r\n onError?: (msg: string) => void;\r\n /** Custom pipe registry for transformations. Defaults to built-in pipes. */\r\n pipeRegistry?: PipeRegistry;\r\n}\r\n\r\nexport type Path = string;\r\nexport type TemplateValue = string | number | boolean | null | undefined;\r\n\r\n/**\r\n * Data context object passed to render function.\r\n * Contains the data values that expressions resolve against.\r\n *\r\n * @example\r\n * const ctx: Context = {\r\n * user: { name: 'John', age: 30 },\r\n * items: ['a', 'b', 'c'],\r\n * isActive: true\r\n * };\r\n */\r\nexport interface Context {\r\n [key: string]: ContextValue;\r\n}\r\n\r\n/**\r\n * Functions context object passed as second argument to render.\r\n * Contains callable functions that can be invoked from templates.\r\n *\r\n * @example\r\n * const fns: FunctionsContext = {\r\n * formatDate: (d) => d.toLocaleDateString(),\r\n * add: (a, b) => a + b,\r\n * greet: (name) => `Hello, ${name}!`\r\n * };\r\n */\r\nexport interface FunctionsContext {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n [key: string]: (...args: any[]) => any;\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ContextValue = TemplateValue | any[] | Context | ((...args: any[]) => any);\r\n\r\nexport type Getter = (ctx: Context, path: Path, debugInfo?: string) => TemplateValue;\r\nexport type Setter = (ctx: Context, fns?: FunctionsContext) => void;\r\nexport type Patcher = (node: Node, get: Getter, config: EngineConfig) => Setter | void;\r\nexport type ExpressionFn = (ctx: Context, fns?: FunctionsContext) => TemplateValue;\r\n\r\ninterface ParsedExpression {\r\n type: 'path' | 'function';\r\n path?: string;\r\n fnName?: string;\r\n fnArgs?: string[];\r\n pipes: string[];\r\n}\r\n\r\nfunction parseExpression(expr: string): ParsedExpression {\r\n const pipesSplit = expr.split('|').map(s => s.trim());\r\n const mainExpr = pipesSplit[0];\r\n const pipes = pipesSplit.slice(1);\r\n\r\n // Check if it's a function call: functionName(args)\r\n const fnMatch = mainExpr.match(/^(\\w+)\\s*\\((.*)\\)$/);\r\n if (fnMatch) {\r\n const [, fnName, argsStr] = fnMatch;\r\n const fnArgs = argsStr\r\n ? argsStr.split(',').map(a => a.trim())\r\n : [];\r\n return { type: 'function', fnName, fnArgs, pipes };\r\n }\r\n\r\n return { type: 'path', path: mainExpr, pipes };\r\n}\r\n\r\n// Resolve a path with support for array indexing: items[0].name\r\nfunction resolvePath(ctx: ContextValue, path: string): ContextValue {\r\n // Handle array indexing by converting items[0] to items.0\r\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\r\n const segments = normalizedPath.split('.');\r\n let current = ctx;\r\n\r\n for (const key of segments) {\r\n if (current && typeof current === 'object' && key in current) {\r\n current = (current as Record<string, ContextValue>)[key];\r\n } else {\r\n return undefined;\r\n }\r\n }\r\n\r\n return current;\r\n}\r\n \r\n function handleError(config: EngineConfig, message: string, context: string, shouldThrow = false): void {\r\n const formattedMessage = `[template error] ${message} (at ${context})`;\r\n \r\n if (config.onError) config.onError(formattedMessage);\r\n if (config.strict || shouldThrow) throw new Error(formattedMessage);\r\n }\r\n \r\nfunction createGetter(config: EngineConfig): Getter {\r\n return function get(ctx: ContextValue, path: Path, debugInfo = ''): TemplateValue {\r\n try {\r\n const current = resolvePath(ctx, path);\r\n\r\n if (current === undefined) {\r\n handleError(config, `Cannot resolve \"${path}\"`, debugInfo);\r\n return '';\r\n }\r\n\r\n // Return primitive values as-is for conditional checks\r\n if (current === null) {\r\n return '';\r\n } else if (Array.isArray(current)) {\r\n return current.length > 0 ? JSON.stringify(current) : '';\r\n } else if (typeof current === 'object') {\r\n return JSON.stringify(current);\r\n } else {\r\n return current as TemplateValue;\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : String(err);\r\n handleError(config, `Exception resolving \"${path}\": ${errorMessage}`, debugInfo, true);\r\n return '';\r\n }\r\n };\r\n}\r\n\r\nfunction evaluateExpression(\r\n parsed: ParsedExpression,\r\n ctx: Context,\r\n fns: FunctionsContext | undefined,\r\n config: EngineConfig,\r\n debugInfo: string\r\n): TemplateValue {\r\n let value: TemplateValue;\r\n const registry = config.pipeRegistry ?? defaultPipes;\r\n\r\n if (parsed.type === 'function') {\r\n const fn = fns?.[parsed.fnName!];\r\n if (typeof fn !== 'function') {\r\n handleError(config, `Function \"${parsed.fnName}\" not found`, debugInfo);\r\n return '';\r\n }\r\n\r\n // Resolve function arguments - could be literals or paths\r\n const resolvedArgs = (parsed.fnArgs ?? []).map(arg => {\r\n // String literal\r\n if ((arg.startsWith('\"') && arg.endsWith('\"')) ||\r\n (arg.startsWith(\"'\") && arg.endsWith(\"'\"))) {\r\n return arg.slice(1, -1);\r\n }\r\n // Number literal\r\n if (!isNaN(Number(arg))) {\r\n return Number(arg);\r\n }\r\n // Path reference - resolve from context\r\n const resolved = resolvePath(ctx, arg);\r\n return resolved;\r\n });\r\n\r\n try {\r\n value = fn(...resolvedArgs) as TemplateValue;\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : String(err);\r\n handleError(config, `Error calling \"${parsed.fnName}\": ${errorMessage}`, debugInfo);\r\n return '';\r\n }\r\n } else {\r\n // Path resolution\r\n const resolved = resolvePath(ctx, parsed.path!);\r\n if (resolved === undefined) {\r\n handleError(config, `Cannot resolve \"${parsed.path}\"`, debugInfo);\r\n return '';\r\n }\r\n if (resolved === null) {\r\n value = '';\r\n } else if (typeof resolved === 'object') {\r\n value = JSON.stringify(resolved);\r\n } else {\r\n value = resolved as TemplateValue;\r\n }\r\n }\r\n\r\n // Apply pipes if any\r\n if (parsed.pipes.length > 0) {\r\n value = applyPipes(value, parsed.pipes, registry);\r\n }\r\n\r\n return value;\r\n}\r\n \r\n// Improved text node patcher with expression memoization\r\nconst expressionCache = new Map<string, { parsed: ParsedExpression; literal: string }[]>();\r\n\r\nfunction textNodePatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.TEXT_NODE || !node.textContent?.includes('{{')) return;\r\n\r\n const raw = node.textContent;\r\n\r\n // Use cached parsed expressions if available\r\n if (!expressionCache.has(raw)) {\r\n const parts = raw.split(/(\\{\\{.*?\\}\\})/);\r\n const parsed = parts.map(part => {\r\n if (part.startsWith('{{')) {\r\n const expr = part.slice(2, -2).trim();\r\n return { parsed: parseExpression(expr), literal: '' };\r\n } else {\r\n return { parsed: null as unknown as ParsedExpression, literal: part };\r\n }\r\n });\r\n expressionCache.set(raw, parsed);\r\n }\r\n\r\n const exprs = expressionCache.get(raw)!;\r\n const debugInfo = `TextNode: \"${raw}\"`;\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const result = exprs.map(({ parsed, literal }) => {\r\n if (parsed) {\r\n return String(evaluateExpression(parsed, ctx, fns, config, debugInfo));\r\n }\r\n return literal;\r\n }).join('');\r\n (node as Text).textContent = result;\r\n };\r\n}\r\n \r\nfunction attributeInterpolationPatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as Element;\r\n const setters: Setter[] = [];\r\n\r\n // Use Array.from to safely iterate over NamedNodeMap\r\n const attributes = Array.from(element.attributes);\r\n for (const attr of attributes) {\r\n const match = attr.value.match(/\\{\\{(.+?)\\}\\}/);\r\n if (match) {\r\n const expr = match[1].trim();\r\n const parsed = parseExpression(expr);\r\n const name = attr.name;\r\n const debugInfo = `Attribute: ${name} on <${element.tagName.toLowerCase()}>`;\r\n setters.push((ctx: Context, fns?: FunctionsContext) => {\r\n const value = evaluateExpression(parsed, ctx, fns, config, debugInfo);\r\n element.setAttribute(name, String(value));\r\n });\r\n }\r\n }\r\n\r\n if (setters.length > 0) {\r\n return (ctx: Context, fns?: FunctionsContext) => setters.forEach(fn => fn(ctx, fns));\r\n }\r\n}\r\n \r\n/**\r\n * Caches the detached element+renderer when hiding so that re-showing\r\n * skips the clone + compile overhead. Render-before-insert order is\r\n * preserved for both fresh and cached paths.\r\n */\r\nfunction createConditionalPatcher(\r\n node: Node,\r\n get: Getter,\r\n config: EngineConfig,\r\n attrName: string,\r\n shouldRender: (value: TemplateValue) => boolean\r\n): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE || !(node as Element).hasAttribute(attrName)) return;\r\n\r\n const element = node as Element;\r\n const expr = element.getAttribute(attrName)!;\r\n const templateNode = element.cloneNode(true) as Element;\r\n const placeholder = document.createComment(`${attrName}: ${expr}`);\r\n const parent = element.parentNode!;\r\n\r\n parent.insertBefore(placeholder, element);\r\n element.remove();\r\n\r\n let currentElement: Element | null = null;\r\n let currentRenderer: ((ctx: Context, fns?: FunctionsContext) => void) | null = null;\r\n let cachedElement: Element | null = null;\r\n let cachedRenderer: ((ctx: Context, fns?: FunctionsContext) => void) | null = null;\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const value = get(ctx, expr, `${attrName}=\"${expr}\"`);\r\n const shouldBeVisible = shouldRender(value);\r\n\r\n if (shouldBeVisible && !currentElement) {\r\n if (cachedElement && cachedRenderer) {\r\n currentElement = cachedElement;\r\n currentRenderer = cachedRenderer;\r\n cachedElement = null;\r\n cachedRenderer = null;\r\n } else {\r\n const clone = templateNode.cloneNode(true) as Element;\r\n clone.removeAttribute(attrName);\r\n currentElement = clone;\r\n currentRenderer = compileDOM(clone, config);\r\n }\r\n currentRenderer(ctx, fns);\r\n parent.insertBefore(currentElement, placeholder.nextSibling);\r\n } else if (shouldBeVisible && currentRenderer) {\r\n currentRenderer(ctx, fns);\r\n }\r\n\r\n if (!shouldBeVisible && currentElement) {\r\n currentElement.remove();\r\n cachedElement = currentElement;\r\n cachedRenderer = currentRenderer;\r\n currentElement = null;\r\n currentRenderer = null;\r\n }\r\n };\r\n}\r\n\r\nfunction ifPatcher(node: Node, get: Getter, config: EngineConfig): Setter | void {\r\n return createConditionalPatcher(node, get, config, 'if', value => !!value);\r\n}\r\n\r\nfunction unlessPatcher(node: Node, get: Getter, config: EngineConfig): Setter | void {\r\n return createConditionalPatcher(node, get, config, 'unless', value => !value);\r\n}\r\n \r\ninterface LoopSlot {\r\n element: Element;\r\n renderer: (ctx: Context, fns?: FunctionsContext) => void;\r\n}\r\n\r\n/**\r\n * Rendering order for loop items:\r\n *\r\n * 1. Clone from template (detached, attributes still contain mustache)\r\n * 2. Compile the clone \u2014 creates setters for mustache in attributes/text\r\n * 3. Render \u2014 resolves mustache against the iteration context\r\n * 4. Insert into DOM \u2014 custom elements upgrade with final attribute values\r\n *\r\n * Steps 2-3 MUST happen before step 4. If we insert first, the browser\r\n * upgrades custom elements immediately (connectedCallback fires) while\r\n * attributes still contain raw \"{{expr}}\" strings.\r\n *\r\n * Slot reuse: existing elements are re-rendered in place (already in DOM,\r\n * already compiled). Only new items go through the full clone-compile-render-\r\n * insert sequence. Excess items are removed.\r\n */\r\nfunction loopPatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE || !(node as Element).hasAttribute('loop')) return;\r\n\r\n const element = node as Element;\r\n const loopDef = element.getAttribute('loop')!;\r\n const match = loopDef.match(/(\\w+)\\s+in\\s+(.+)/);\r\n if (!match) {\r\n handleError(config, `Invalid loop syntax: \"${loopDef}\"`, `Element: <${element.tagName.toLowerCase()}>`);\r\n return;\r\n }\r\n\r\n const [, alias, source] = match;\r\n const tpl = element.cloneNode(true) as Element;\r\n tpl.removeAttribute('loop');\r\n\r\n const parent = element.parentNode!;\r\n const placeholder = document.createComment(`loop: ${loopDef}`);\r\n parent.insertBefore(placeholder, element);\r\n element.remove();\r\n\r\n let slots: LoopSlot[] = [];\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const items = resolvePath(ctx, source);\r\n\r\n if (items === undefined) {\r\n handleError(config, `Cannot resolve \"${source}\"`, `Loop source: \"${loopDef}\"`);\r\n return;\r\n }\r\n\r\n if (!Array.isArray(items)) {\r\n handleError(config, `\"${source}\" is not an array in loop: \"${loopDef}\"`,\r\n `Element: <${tpl.tagName.toLowerCase()}>`);\r\n return;\r\n }\r\n\r\n const reuseCount = Math.min(slots.length, items.length);\r\n\r\n // Re-render existing slots in place\r\n for (let i = 0; i < reuseCount; i++) {\r\n slots[i].renderer({ ...ctx, [alias]: items[i] }, fns);\r\n }\r\n\r\n // Remove excess slots\r\n for (let i = slots.length - 1; i >= items.length; i--) {\r\n slots[i].element.remove();\r\n }\r\n\r\n // Create new slots via DocumentFragment for batch insertion\r\n if (items.length > reuseCount) {\r\n const frag = document.createDocumentFragment();\r\n const newSlots: LoopSlot[] = [];\r\n\r\n for (let i = reuseCount; i < items.length; i++) {\r\n // 1. Clone (detached \u2014 no connectedCallback yet)\r\n const instance = tpl.cloneNode(true) as Element;\r\n\r\n // 2-3. Compile + render while detached \u2014 resolves mustache\r\n const childRenderer = compileDOM(instance, config);\r\n childRenderer({ ...ctx, [alias]: items[i] }, fns);\r\n\r\n frag.appendChild(instance);\r\n newSlots.push({ element: instance, renderer: childRenderer });\r\n }\r\n\r\n // 4. Batch-insert into live DOM \u2014 custom elements upgrade with final values\r\n const insertAfter = reuseCount > 0\r\n ? slots[reuseCount - 1].element\r\n : placeholder;\r\n parent.insertBefore(frag, insertAfter.nextSibling);\r\n\r\n slots = slots.slice(0, reuseCount).concat(newSlots);\r\n } else {\r\n slots.length = items.length;\r\n }\r\n };\r\n}\r\n \r\n/**\r\n * Structural patchers (loop, if, unless) take full ownership of a node.\r\n * They replace the original with a placeholder, then on each render they\r\n * clone, compile, and resolve the node independently. When one matches,\r\n * content patchers and child traversal are skipped for that node.\r\n */\r\nconst structuralPatchers: Patcher[] = [\r\n loopPatcher,\r\n ifPatcher,\r\n unlessPatcher\r\n];\r\n\r\n/** Content patchers resolve mustache expressions in text nodes and attributes. */\r\nconst contentPatchers: Patcher[] = [\r\n textNodePatcher,\r\n attributeInterpolationPatcher,\r\n];\r\n\r\n/**\r\n * Walks the DOM tree and collects setters from patchers.\r\n *\r\n * Processing order per node:\r\n * 1. Try structural patchers \u2014 if one matches, it owns the node (skip steps 2-3)\r\n * 2. Run content patchers (text interpolation, attribute interpolation)\r\n * 3. Recurse into child nodes\r\n */\r\nfunction compileDOM(root: Node, config: EngineConfig): (ctx: Context, fns?: FunctionsContext) => void {\r\n const setters: Setter[] = [];\r\n const get = createGetter(config);\r\n\r\n function processNode(node: Node) {\r\n // Structural directives own the node \u2014 they clone + compileDOM internally\r\n for (const patch of structuralPatchers) {\r\n const setter = patch(node, get, config);\r\n if (setter) {\r\n setters.push(setter);\r\n return;\r\n }\r\n }\r\n\r\n // Content patchers \u2014 resolve {{expr}} in text and attributes\r\n for (const patch of contentPatchers) {\r\n const setter = patch(node, get, config);\r\n if (setter) setters.push(setter);\r\n }\r\n\r\n for (const child of Array.from(node.childNodes)) {\r\n processNode(child);\r\n }\r\n }\r\n\r\n processNode(root);\r\n\r\n // Return memoized render function\r\n let lastCtx: Context | null = null;\r\n let lastFns: FunctionsContext | undefined = undefined;\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n // Only re-render if context has changed\r\n if (lastCtx !== ctx || lastFns !== fns) {\r\n setters.forEach(fn => fn(ctx, fns));\r\n lastCtx = ctx;\r\n lastFns = fns;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Result of compiling a template.\r\n * Contains the DOM content and a render function for updating it with data.\r\n */\r\nexport interface CompiledTemplate {\r\n /** The compiled DOM element containing the template structure. */\r\n content: DocumentFragment | HTMLElement;\r\n /**\r\n * Updates the DOM with the provided data context.\r\n * Memoized: only re-renders when context object reference changes.\r\n * @param ctx - Data context with values for template expressions\r\n * @param fns - Optional functions context for callable expressions\r\n */\r\n render: (ctx: Context, fns?: FunctionsContext) => void;\r\n}\r\n\r\n/**\r\n * Compiles an HTML template string into a reusable render function.\r\n *\r\n * The template supports mustache-style expressions `{{expression}}` for:\r\n * - Path resolution: `{{user.name}}`, `{{items[0].title}}`\r\n * - Pipes: `{{value | uppercase}}`, `{{price | currency}}`\r\n * - Function calls: `{{formatDate(createdAt)}}`, `{{add(a, b)}}`\r\n *\r\n * Directive attributes for control flow:\r\n * - `if=\"condition\"` - Renders element only when condition is truthy\r\n * - `unless=\"condition\"` - Renders element only when condition is falsy\r\n * - `loop=\"item in items\"` - Repeats element for each array item\r\n *\r\n * @param templateStr - HTML template string with mustache expressions\r\n * @param config - Optional engine configuration\r\n * @returns Compiled template with content and render function\r\n *\r\n * @example\r\n * // Simple data binding\r\n * const { content, render } = compileTemplate('<h1>{{title}}</h1>');\r\n * render({ title: 'Hello World' });\r\n * document.body.appendChild(content);\r\n *\r\n * @example\r\n * // Re-rendering with new data\r\n * const { content, render } = compileTemplate('<span>Count: {{count}}</span>');\r\n * render({ count: 0 });\r\n * render({ count: 1 }); // DOM updates automatically\r\n *\r\n * @example\r\n * // With strict mode and error handling\r\n * const { render } = compileTemplate('{{missing}}', {\r\n * strict: true,\r\n * onError: (msg) => console.error(msg)\r\n * });\r\n * render({}); // Throws error for missing path\r\n */\r\nexport function compileTemplate(templateStr: string, config: EngineConfig = { strict: false }): CompiledTemplate {\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(`<template><div>${templateStr}</div></template>`, 'text/html');\r\n const content = doc.querySelector('template')!.content.firstElementChild as HTMLElement;\r\n const render = compileDOM(content, config);\r\n\r\n return { content, render };\r\n}", "/**\r\n * Represents a single step in a property access path\r\n * Can be either a property name or an array index access\r\n * @example { type: \"property\", key: \"user\" }\r\n * @example { type: \"index\", key: \"0\" }\r\n */\r\ntype PathSegment = {\r\n type: \"property\" | \"index\";\r\n key: string;\r\n};\r\n\r\n/**\r\n * Represents the result of parsing a dot-notation string into path segments\r\n * Used internally by the parser to break down property access chains including arrays\r\n * @example [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }] for \"users[0].name\"\r\n */\r\ntype PropertyPath = PathSegment[];\r\n\r\n/**\r\n * Function type that accesses nested properties safely from a record\r\n * Returns undefined if any property in the chain is missing or null/undefined\r\n * @example\r\n * const accessor = createAccessor(\"user.name\");\r\n * const result = accessor(data); // string | undefined\r\n */\r\ntype PropertyAccessor<T = unknown> = (\r\n record: Record<string, any>\r\n) => T | undefined;\r\n\r\n/**\r\n * Parser configuration options for customizing dot-notation parsing behavior\r\n * Used to modify how the parser handles property paths and edge cases\r\n * @example { delimiter: \".\", escapeChar: \"\\\\\" }\r\n */\r\ninterface ParserOptions {\r\n delimiter?: string;\r\n escapeChar?: string;\r\n}\r\n\r\n/**\r\n * Parses a dot-notation string with array support into path segments\r\n * Handles escaped delimiters, array indices, and validates input format\r\n * @param notation - Notation string with dots and brackets (e.g., \"users[0].profile.name\")\r\n * @param options - Parser configuration options\r\n * @returns Array of path segments for property and array access\r\n * @example\r\n * parsePath(\"user.profile.name\") // [{ type: \"property\", key: \"user\" }, { type: \"property\", key: \"profile\" }, { type: \"property\", key: \"name\" }]\r\n * parsePath(\"users[0].name\") // [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }]\r\n * parsePath(\"data\\\\.file[1]\", { escapeChar: \"\\\\\" }) // [{ type: \"property\", key: \"data.file\" }, { type: \"index\", key: \"1\" }]\r\n */\r\nfunction parsePath(\r\n notation: string,\r\n options: ParserOptions = {}\r\n): PropertyPath {\r\n const { delimiter = \".\", escapeChar = \"\\\\\" } = options;\r\n\r\n if (!notation || typeof notation !== \"string\") {\r\n throw new Error(\"Notation must be a non-empty string\");\r\n }\r\n\r\n const segments: PathSegment[] = [];\r\n let current = \"\";\r\n let i = 0;\r\n let inBrackets = false;\r\n let bracketContent = \"\";\r\n\r\n while (i < notation.length) {\r\n const char = notation[i];\r\n const currentInDelimLength = notation.substring(i, delimiter.length + i);\r\n const nextChar = notation[i + 1];\r\n const nextInDelimLength = notation.substring(i + 1, delimiter.length + i + 1);\r\n\r\n if (\r\n char === escapeChar &&\r\n (nextInDelimLength === delimiter || nextChar === \"[\" || nextChar === \"]\")\r\n ) {\r\n if (inBrackets) {\r\n bracketContent += nextChar;\r\n } else {\r\n current += nextChar;\r\n }\r\n i += 2;\r\n } else if (char === \"[\" && !inBrackets) {\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n current = \"\";\r\n }\r\n inBrackets = true;\r\n bracketContent = \"\";\r\n i++;\r\n } else if (char === \"]\" && inBrackets) {\r\n if (!/^\\d+$/.test(bracketContent.trim())) {\r\n throw new Error(\r\n `Invalid array index: [${bracketContent}]. Only numeric indices are supported.`\r\n );\r\n }\r\n segments.push({ type: \"index\", key: bracketContent.trim() });\r\n inBrackets = false;\r\n bracketContent = \"\";\r\n i++;\r\n } else if (currentInDelimLength === delimiter && !inBrackets) {\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n current = \"\";\r\n }\r\n i += delimiter.length;\r\n } else if (inBrackets) {\r\n bracketContent += char;\r\n i++;\r\n } else {\r\n current += char;\r\n i++;\r\n }\r\n }\r\n\r\n if (inBrackets) {\r\n throw new Error(\"Unclosed bracket in notation\");\r\n }\r\n\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n }\r\n\r\n if (segments.length === 0) {\r\n throw new Error(\r\n \"Invalid notation: must contain at least one property or index\"\r\n );\r\n }\r\n\r\n return segments;\r\n}\r\n\r\n/**\r\n * Creates an accessor function from a parsed property path with array support\r\n * The returned function safely navigates nested objects and arrays using the parsed path\r\n * @param path - Array of path segments to access in sequence\r\n * @returns Function that takes a record and returns the nested value or undefined\r\n * @example\r\n * const path = [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }];\r\n * const accessor = createAccessorFromPath(path);\r\n * accessor({ users: [{ name: \"John\" }] }) // \"John\"\r\n */\r\nfunction createAccessorFromPath<T = unknown>(\r\n path: PropertyPath\r\n): PropertyAccessor<T> {\r\n return (record: Record<string, any>): T | undefined => {\r\n let current: any = record;\r\n\r\n for (const segment of path) {\r\n if (current == null) {\r\n return undefined;\r\n }\r\n\r\n if (segment.type === \"property\") {\r\n if (typeof current !== \"object\") {\r\n return undefined;\r\n }\r\n current = current[segment.key];\r\n } else if (segment.type === \"index\") {\r\n if (!Array.isArray(current)) {\r\n return undefined;\r\n }\r\n const index = parseInt(segment.key, 10);\r\n if (index < 0 || index >= current.length) {\r\n return undefined;\r\n }\r\n current = current[index];\r\n }\r\n }\r\n\r\n return current as T;\r\n };\r\n}\r\n\r\n/**\r\n * Main parser function that creates an accessor from notation string with array support\r\n * Combines path parsing and accessor creation into a single operation\r\n * @param notation - Notation string with dots and brackets (e.g., \"users[0].profile.name\")\r\n * @param options - Parser configuration options\r\n * @returns Accessor function for the specified property path\r\n * @example\r\n * const accessor = createAccessor(\"user.profile.name\");\r\n * const name = accessor(userData); // safely gets nested property\r\n *\r\n * const arrayAccessor = createAccessor(\"users[0].name\");\r\n * const userName = arrayAccessor(data); // safely accesses array elements\r\n *\r\n * const complexAccessor = createAccessor(\"items[2].meta\\\\.data.values[1]\", { escapeChar: \"\\\\\" });\r\n * const value = complexAccessor(response); // handles escaped dots and nested arrays\r\n */\r\nfunction createAccessor<T = unknown>(\r\n notation: string,\r\n options: ParserOptions = {}\r\n): PropertyAccessor<T> {\r\n const path = parsePath(notation, options);\r\n return createAccessorFromPath<T>(path);\r\n}\r\n\r\n/**\r\n * Utility function to test if a property path exists in a record (with array support)\r\n * Useful for validation before attempting to access nested properties or array elements\r\n * @param notation - Notation string with dots and brackets to test\r\n * @param record - Record to test against\r\n * @param options - Parser configuration options\r\n * @returns Boolean indicating if the complete path exists\r\n * @example\r\n * hasProperty(\"user.name\", data) // true if data.user.name exists\r\n * hasProperty(\"users[0].name\", data) // true if data.users[0].name exists\r\n * hasProperty(\"missing.path\", data) // false if any part is undefined\r\n */\r\nfunction hasProperty(\r\n notation: string,\r\n record: Record<string, any>,\r\n options: ParserOptions = {}\r\n): boolean {\r\n const accessor = createAccessor(notation, options);\r\n return accessor(record) !== undefined;\r\n}\r\n\r\nexport {\r\n createAccessor,\r\n createAccessorFromPath,\r\n parsePath,\r\n hasProperty,\r\n type PropertyAccessor,\r\n type PropertyPath,\r\n type PathSegment,\r\n type ParserOptions,\r\n};\r\n", "/**\r\n * Represents different token types that can be identified by the tokenizer\r\n * @example\r\n * // Use to classify what kind of syntax element was found\r\n * const tokenType = TokenType.Constant;\r\n */\r\nexport enum TokenType {\r\n Constant = 0,\r\n FunctionCall = 1,\r\n Variable = 2,\r\n Pipe = 3,\r\n}\r\n\r\n/**\r\n * Represents a token with its type and value\r\n * @example\r\n * // Creating a token for a number constant\r\n * const token: Token = { type: TokenType.Constant, value: '42' };\r\n */\r\nexport interface Token {\r\n type: TokenType;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Tokenizes an input string into constants, function calls, and variables\r\n * @example\r\n * // Basic usage\r\n * const tokens = tokenize('myVar.property + func(42)');\r\n * \r\n * @example\r\n * // Handling complex expressions\r\n * const tokens = tokenize('math.sin(angle) + \"hello\".length');\r\n * \r\n * @example\r\n * // Handling pipes\r\n * const tokens = tokenize('input | transform | display');\r\n */\r\nexport function tokenize(input: string): Token[] {\r\n const tokens: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < input.length) {\r\n let char = input[i];\r\n\r\n // Skip whitespace\r\n if (/\\s/.test(char)) {\r\n i++;\r\n continue;\r\n }\r\n\r\n // Handle pipe operator (\"|\")\r\n if (char === '|') {\r\n i++;\r\n\r\n // Skip whitespace after pipe\r\n while (i < input.length && /\\s/.test(input[i])) {\r\n i++;\r\n }\r\n\r\n // Capture the pipe target (everything up to the next whitespace or special character)\r\n let pipeTarget = '';\r\n while (i < input.length && !/[\\s\\(\\)\\[\\]\\{\\}\\|\\+\\-\\*\\/\\=\\;\\,\\.]/.test(input[i])) {\r\n pipeTarget += input[i];\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Pipe, value: pipeTarget });\r\n continue;\r\n }\r\n\r\n // Handle string constants\r\n if (char === '\"' || char === \"'\") {\r\n const quote = char;\r\n let value = quote;\r\n i++;\r\n\r\n while (i < input.length && input[i] !== quote) {\r\n // Handle escaped quotes\r\n if (input[i] === '\\\\' && i + 1 < input.length && input[i + 1] === quote) {\r\n value += '\\\\' + quote;\r\n i += 2;\r\n } else {\r\n value += input[i];\r\n i++;\r\n }\r\n }\r\n\r\n if (i < input.length) {\r\n value += quote;\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Constant, value });\r\n continue;\r\n }\r\n\r\n // Handle numeric constants\r\n if (/[0-9]/.test(char)) {\r\n let value = '';\r\n let hasDecimal = false;\r\n\r\n while (i < input.length && (/[0-9]/.test(input[i]) || (input[i] === '.' && !hasDecimal))) {\r\n if (input[i] === '.') {\r\n hasDecimal = true;\r\n }\r\n value += input[i];\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Constant, value });\r\n continue;\r\n }\r\n\r\n // Handle identifiers (variables and function calls with property/array access)\r\n if (/[a-zA-Z_$]/.test(char)) {\r\n let value = '';\r\n let isFunctionCall = false;\r\n\r\n // Capture identifier, including dots and bracket access\r\n while (i < input.length) {\r\n if (/[a-zA-Z0-9_$.]/.test(input[i])) {\r\n value += input[i];\r\n i++;\r\n } else if (input[i] === '[') {\r\n // Include array index expression like [0] or ['key']\r\n let bracketCount = 1;\r\n value += input[i++];\r\n while (i < input.length && bracketCount > 0) {\r\n if (input[i] === '[') bracketCount++;\r\n if (input[i] === ']') bracketCount--;\r\n value += input[i++];\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n // Skip whitespace to check for function call\r\n let wsCount = 0;\r\n while (i < input.length && /\\s/.test(input[i])) {\r\n wsCount++;\r\n i++;\r\n }\r\n\r\n // Check if this is a function call\r\n if (i < input.length && input[i] === '(') {\r\n isFunctionCall = true;\r\n\r\n value += '(';\r\n i++;\r\n\r\n let parenCount = 1;\r\n while (i < input.length && parenCount > 0) {\r\n if (input[i] === '(') parenCount++;\r\n if (input[i] === ')') parenCount--;\r\n value += input[i++];\r\n }\r\n } else {\r\n // Restore skipped whitespace\r\n i -= wsCount;\r\n }\r\n\r\n const lastToken = tokens[tokens.length - 1];\r\n const isDotAfterConstant = input[i - value.length - 1] === '.' && lastToken?.type === TokenType.Constant;\r\n\r\n tokens.push({\r\n type: isFunctionCall || isDotAfterConstant ? TokenType.FunctionCall : TokenType.Variable,\r\n value\r\n });\r\n continue;\r\n }\r\n\r\n // Handle operators and other characters\r\n i++;\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n/** Functions */\r\n\r\nexport type ArgToken =\r\n | { type: 'number'; value: number }\r\n | { type: 'string'; value: string }\r\n | { type: 'identifier'; value: string };\r\n\r\nexport function tokenizeArgs(input: string): ArgToken[] {\r\n const tokens: ArgToken[] = [];\r\n\r\n const start = input.indexOf('(');\r\n const end = input.lastIndexOf(')');\r\n if (start === -1 || end === -1 || end <= start) {\r\n throw new Error('Invalid function call syntax');\r\n }\r\n\r\n const argsStr = input.slice(start + 1, end);\r\n let i = 0;\r\n\r\n while (i < argsStr.length) {\r\n const char = argsStr[i];\r\n\r\n if (/\\s/.test(char)) {\r\n i++;\r\n continue;\r\n }\r\n\r\n if (char === '\"' || char === \"'\") {\r\n const quoteType = char;\r\n let value = '';\r\n i++;\r\n while (i < argsStr.length && argsStr[i] !== quoteType) {\r\n if (argsStr[i] === '\\\\') {\r\n i++;\r\n if (i < argsStr.length) {\r\n value += argsStr[i];\r\n }\r\n } else {\r\n value += argsStr[i];\r\n }\r\n i++;\r\n }\r\n if (i >= argsStr.length) {\r\n throw new Error('Unterminated string in arguments');\r\n }\r\n\r\n i++; // skip closing quote\r\n tokens.push({ type: 'string', value });\r\n continue;\r\n }\r\n\r\n\r\n if (/[0-9]/.test(char)) {\r\n let numStr = '';\r\n while (i < argsStr.length && /[0-9.]/.test(argsStr[i])) {\r\n numStr += argsStr[i];\r\n i++;\r\n }\r\n tokens.push({ type: 'number', value: parseFloat(numStr) });\r\n continue;\r\n }\r\n\r\n if (/[a-zA-Z_]/.test(char)) {\r\n let ident = '';\r\n while (i < argsStr.length && /[a-zA-Z0-9_\\.]/.test(argsStr[i])) {\r\n ident += argsStr[i];\r\n i++;\r\n }\r\n tokens.push({ type: 'identifier', value: ident });\r\n continue;\r\n }\r\n\r\n if (char === ',') {\r\n i++;\r\n continue;\r\n }\r\n\r\n throw new Error(`Unexpected character in arguments: ${char}`);\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n/** For STRING/MUSTACHE */\r\n\r\nexport type MustacheTokenType = 'string' | 'mustache';\r\n\r\n/**\r\n * Represents a token extracted from a template string\r\n * @typedef {Object} MustahceToken\r\n * @property {MustacheTokenType} type - Either 'string' for plain text or 'mustache' for mustache expressions\r\n * @property {string} value - The actual content of the token\r\n */\r\nexport interface MustacheToken {\r\n type: MustacheTokenType;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Tokenizes a template string into an array of string and mustache tokens\r\n * @param {string} template - The template string containing text and mustache expressions\r\n * @returns {MustacheToken[]} An array of tokens representing the parsed template\r\n *\r\n * @example\r\n * // Returns tokens for a simple greeting template\r\n * tokenizeTemplate(\"Hello, {{name}}!\");\r\n * // [\r\n * // { type: 'string', value: 'Hello, ' },\r\n * // { type: 'mustache', value: '{{name}}' },\r\n * // { type: 'string', value: '!' }\r\n * // ]\r\n */\r\nexport function tokenizeMustache(template: string): MustacheToken[] {\r\n const tokens: MustacheToken[] = [];\r\n let currentIndex = 0;\r\n\r\n while (currentIndex < template.length) {\r\n const openTagIndex = template.indexOf('{{', currentIndex);\r\n\r\n if (openTagIndex === -1) {\r\n tokens.push(createStringToken(template.slice(currentIndex)));\r\n break;\r\n }\r\n\r\n if (openTagIndex > currentIndex) {\r\n tokens.push(createStringToken(template.slice(currentIndex, openTagIndex)));\r\n }\r\n\r\n const { value: mustache, endIndex, balanced } = extractMustache(template, openTagIndex);\r\n if (!balanced) {\r\n throw new Error(`Unclosed mustache tag starting at index ${openTagIndex}, template: ${template}`);\r\n }\r\n tokens.push(createMustacheToken(mustache));\r\n currentIndex = endIndex;\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\nfunction createStringToken(value: string): MustacheToken {\r\n return { type: 'string', value };\r\n}\r\n\r\nfunction createMustacheToken(value: string): MustacheToken {\r\n return { type: 'mustache', value };\r\n}\r\n\r\nfunction extractMustache(template: string, startIndex: number): {\r\n value: string;\r\n endIndex: number;\r\n balanced: boolean;\r\n} {\r\n const open = '{{';\r\n const close = '}}';\r\n let i = startIndex + open.length;\r\n let depth = 1;\r\n\r\n while (i < template.length && depth > 0) {\r\n if (template.slice(i, i + open.length) === open) {\r\n depth++;\r\n i += open.length;\r\n } else if (template.slice(i, i + close.length) === close) {\r\n depth--;\r\n i += close.length;\r\n } else {\r\n i++;\r\n }\r\n }\r\n\r\n const balanced = depth === 0;\r\n const endIndex = balanced ? i : template.length;\r\n const value = template.slice(startIndex, endIndex);\r\n\r\n return { value, endIndex, balanced };\r\n}\r\n", "import { defaultPipes, PipeFunction, PipeRegistry } from \"../pipes\";\r\nimport { createAccessor } from \"./accessorParser\";\r\nimport {\r\n MustacheToken,\r\n Token,\r\n tokenize,\r\n tokenizeArgs,\r\n tokenizeMustache,\r\n TokenType,\r\n} from \"./tokenizer\";\r\n\r\nexport type RenderTemplate = (data: Record<string, any>, component?: any) => string;\r\ntype ResolveValue = (data: Record<string, any>, component?: any) => any;\r\ntype ResolveFunctionValue = (data: Record<string, any>, component: any) => any;\r\ntype RenderPart = (data: Record<string, any>, component: any) => string;\r\n\r\nexport interface TemplateParserOptions {\r\n pipeRegistry?: PipeRegistry;\r\n}\r\n\r\ninterface ExpressionChain {\r\n source: ResolveValue;\r\n pipes: PipeFunction[];\r\n}\r\n\r\nexport function compileMustard(template: string, options?: TemplateParserOptions): RenderTemplate {\r\n const segments: RenderPart[] = tokenizeMustache(template).map(token =>\r\n token.type === \"string\"\r\n ? (_data, _component) => token.value\r\n : compileExpression(token, options)\r\n );\r\n\r\n return (data, component) => segments.map(fn => fn(data, component)).join(\"\");\r\n}\r\n\r\nfunction compileExpression(token: MustacheToken, options?: TemplateParserOptions): RenderPart {\r\n const tokens = tokenize(token.value);\r\n const chain = buildExpressionChain(tokens, token.value, options?.pipeRegistry);\r\n return renderFromChain(chain);\r\n}\r\n\r\nfunction buildExpressionChain(\r\n tokens: Token[],\r\n sourceText: string,\r\n pipeRegistry?: PipeRegistry\r\n): ExpressionChain {\r\n let chain: ExpressionChain | null = null;\r\n if (!pipeRegistry){\r\n pipeRegistry = defaultPipes;\r\n }\r\n\r\n for (const token of tokens) {\r\n switch (token.type) {\r\n case TokenType.Constant:\r\n throw Error(`Constants not supported: ${token.value}`);\r\n\r\n case TokenType.Variable: {\r\n const accessor = createAccessor(token.value);\r\n chain = { source: accessor, pipes: [] };\r\n break;\r\n }\r\n\r\n case TokenType.FunctionCall: {\r\n const func = resolveFunction(token.value);\r\n chain = {\r\n source: func,\r\n pipes: []\r\n };\r\n break;\r\n }\r\n\r\n case TokenType.Pipe: {\r\n if (!chain) throw Error(`Pipe '${token.value}' has no input expression in: ${sourceText}`);\r\n if (!token.value || token.value === ''){\r\n throw Error('Pipe symbol was provided, but no pipes. Template: ' + sourceText);\r\n }\r\n\r\n const [pipeName, ...args] = token.value.split(':').map((p) => p.trim());\r\n const pipe = pipeRegistry.lookup(pipeName);\r\n if (!pipe) throw Error(`Pipe not found: ${pipeName}`);\r\n chain.pipes.push(value => pipe(value, args));\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!chain) throw Error(`Invalid expression: ${sourceText}`);\r\n return chain;\r\n}\r\n\r\nfunction renderFromChain(chain: ExpressionChain): RenderPart {\r\n return (data, component) => {\r\n const initial = chain.source(data, component);\r\n const result = chain.pipes.reduce((acc, fn) => fn(acc), initial);\r\n return result != null ? result.toString() : \"\";\r\n };\r\n}\r\n\r\nfunction resolveFunction(expression: string): ResolveFunctionValue {\r\n const pos = expression.indexOf(\"(\");\r\n if (pos === -1) throw Error(`Invalid function: ${expression}`);\r\n\r\n const args = tokenizeArgs(expression);\r\n const resolvedArgs: ((data: Record<string, any>) => any)[] = args.map(arg => {\r\n if (arg.type === \"number\" || arg.type === \"string\") return () => arg.value;\r\n if (arg.type === \"identifier\") return data => createAccessor(arg.value)(data);\r\n throw Error(`Unsupported argument type: ${(arg as any).type}`);\r\n });\r\n\r\n const name = expression.substring(0, pos);\r\n const fnAccessor = createAccessor(name);\r\n\r\n return (data, component) => {\r\n if (!component) throw Error(`Component context is required for calling '${name}'`);\r\n const fn = fnAccessor(component);\r\n if (typeof fn !== \"function\") throw Error(`Resolved '${name}' is not a function`);\r\n const evaluatedArgs = resolvedArgs.map(argFn => argFn(data));\r\n return fn.apply(component, evaluatedArgs);\r\n };\r\n}\r\n", "import { compileMustard } from \"./parseTemplate\";\r\nimport { ArgToken, tokenizeArgs } from \"./tokenizer\";\r\n\r\ntype RawBinding =\r\n | {\r\n type: 'text';\r\n path: number[];\r\n func: (context: Record<string, any>, component: Record<string, any>, node: Node) => void;\r\n }\r\n | {\r\n type: 'attribute';\r\n path: number[];\r\n name: string;\r\n func: (context: Record<string, any>, component: Record<string, any>, element: HTMLElement) => void;\r\n };\r\n\r\ntype ClickBinding = {\r\n path: number[];\r\n methodName: string;\r\n argTokens: ArgToken[];\r\n};\r\n\r\ntype BoundBinding =\r\n | {\r\n type: 'text';\r\n node: Node;\r\n func: (context: Record<string, any>, node: Node) => void;\r\n }\r\n | {\r\n type: 'attribute';\r\n element: HTMLElement;\r\n name: string;\r\n func: (context: Record<string, any>, element: HTMLElement) => void;\r\n };\r\n\r\nexport class BoundNode {\r\n constructor(\r\n private readonly root: HTMLElement,\r\n private readonly bindings: BoundBinding[],\r\n private readonly clickBindings: ClickBinding[],\r\n private readonly component?: Record<string, any>\r\n ) { }\r\n\r\n render(data: Record<string, any>): HTMLElement {\r\n for (const binding of this.bindings) {\r\n if (binding.type === 'text') {\r\n binding.func(data, binding.node);\r\n } else {\r\n binding.func(data, binding.element);\r\n }\r\n }\r\n\r\n for (const click of this.clickBindings) {\r\n const node = this.getNodeAtPath(this.root, click.path);\r\n const method = this.component?.[click.methodName];\r\n\r\n if (node instanceof HTMLElement && typeof method === 'function') {\r\n node.onclick = (evt: Event) => {\r\n const args = click.argTokens.map(token => {\r\n if (token.type === 'number' || token.type === 'string') {\r\n return token.value;\r\n }\r\n if (token.type === 'identifier') {\r\n if (token.value === 'event') {\r\n return evt;\r\n }\r\n\r\n const parts = token.value.split('.');\r\n return parts.reduce((obj, key) => obj?.[key], data);\r\n }\r\n });\r\n method.apply(this.component, args);\r\n };\r\n }\r\n }\r\n\r\n return this.root;\r\n }\r\n\r\n private getNodeAtPath(root: Node, path: number[]): Node {\r\n return path.reduce((node, index) => node.childNodes[index], root);\r\n }\r\n}\r\n\r\nexport function createBluePrint(html: string): Blueprint {\r\n var bp = new Blueprint(html);\r\n return bp;\r\n}\r\n\r\nexport class Blueprint {\r\n private readonly template: HTMLTemplateElement;\r\n private readonly bindings: RawBinding[];\r\n private readonly clickBindings: ClickBinding[];\r\n\r\n constructor(htmlOrTemplate: string | HTMLTemplateElement) {\r\n if (typeof htmlOrTemplate === 'string') {\r\n const trimmed = htmlOrTemplate.trim();\r\n if (trimmed.startsWith('<template')) {\r\n const wrapper = document.createElement('div');\r\n wrapper.innerHTML = trimmed;\r\n const found = wrapper.querySelector('template');\r\n if (!found) throw new Error('Could not find <template> in input string');\r\n this.template = found;\r\n } else {\r\n this.template = document.createElement('template');\r\n this.template.innerHTML = trimmed;\r\n }\r\n } else {\r\n this.template = htmlOrTemplate;\r\n }\r\n\r\n const rootElement = this.getRootElement();\r\n this.bindings = this.collectBindings(rootElement);\r\n this.clickBindings = this.collectClickBindings(rootElement);\r\n }\r\n\r\n createInstance(component?: Record<string, any>): BoundNode {\r\n const rootClone = this.getRootElement().cloneNode(true) as HTMLElement;\r\n\r\n const boundBindings: BoundBinding[] = this.bindings.map(binding => {\r\n const node = this.getNodeAtPath(rootClone, binding.path);\r\n if (binding.type === 'text') {\r\n return {\r\n type: 'text',\r\n node,\r\n func: (data, node) => binding.func(data, component, node)\r\n };\r\n } else {\r\n return {\r\n type: 'attribute',\r\n element: node as HTMLElement,\r\n name: binding.name,\r\n func: (data, node) => binding.func(data, component, node)\r\n };\r\n }\r\n });\r\n\r\n return new BoundNode(rootClone, boundBindings, this.clickBindings, component);\r\n }\r\n\r\n private getRootElement(): HTMLElement {\r\n const el = Array.from(this.template.content.childNodes).find(\r\n node => node.nodeType === Node.ELEMENT_NODE\r\n );\r\n if (!(el instanceof HTMLElement)) {\r\n throw new Error('Template must contain a single root element');\r\n }\r\n return el;\r\n }\r\n\r\n private collectBindings(root: HTMLElement): RawBinding[] {\r\n const bindings: RawBinding[] = [];\r\n\r\n const walk = (node: Node, path: number[] = []) => {\r\n if (node.nodeType === Node.TEXT_NODE && node.textContent) {\r\n if (node.textContent.match(/\\{\\{\\s*(.*?)\\s*\\}\\}/g)) {\r\n const func = compileMustard(node.textContent);\r\n bindings.push({\r\n type: 'text',\r\n path: [...path],\r\n func: (data, component, targetNode) => {\r\n targetNode.textContent = func(data, component);\r\n }\r\n });\r\n }\r\n }\r\n\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n\r\n if (element.tagName === 'TEMPLATE') return;\r\n\r\n for (let i = 0; i < element.attributes.length; i++) {\r\n const attr = element.attributes[i];\r\n if (attr.value.match(/\\{\\{\\s*(.*?)\\s*\\}\\}/g)) {\r\n const func = compileMustard(attr.value);\r\n bindings.push({\r\n type: 'attribute',\r\n path: [...path],\r\n name: attr.name,\r\n func: (data, component, el) => {\r\n el.setAttribute(attr.name, func(data, component));\r\n }\r\n });\r\n }\r\n }\r\n\r\n Array.from(node.childNodes).forEach((child, index) => {\r\n walk(child, [...path, index]);\r\n });\r\n }\r\n };\r\n\r\n walk(root);\r\n return bindings;\r\n }\r\n\r\n private collectClickBindings(root: Node): ClickBinding[] {\r\n const bindings: ClickBinding[] = [];\r\n\r\n const walk = (node: Node, path: number[] = []) => {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n const clickAttr = element.getAttribute('click');\r\n if (clickAttr?.trim()) {\r\n const trimmed = clickAttr.trim();\r\n\r\n const match = trimmed.match(/^([a-zA-Z_$][\\w$]*)\\s*\\((.*)\\)$/);\r\n if (match) {\r\n const methodName = match[1];\r\n const argTokens = tokenizeArgs(trimmed);\r\n bindings.push({ path: [...path], methodName, argTokens });\r\n } else {\r\n // No parentheses \u2014 treat as method with no args\r\n bindings.push({ path: [...path], methodName: trimmed, argTokens: [] });\r\n }\r\n }\r\n\r\n Array.from(node.childNodes).forEach((child, index) => {\r\n walk(child, [...path, index]);\r\n });\r\n }\r\n };\r\n\r\n walk(root);\r\n return bindings;\r\n }\r\n\r\n private getNodeAtPath(root: Node, path: number[]): Node {\r\n return path.reduce((node, index) => node.childNodes[index], root);\r\n }\r\n}\r\n", "export class TableRenderer {\r\n private table: HTMLTableElement;\r\n private template: HTMLTemplateElement;\r\n private component: HTMLElement;\r\n private dataMap = new Map<string, Record<string, any>>();\r\n private rowMap = new Map<string, HTMLTableRowElement>();\r\n\r\n public IdColumn: string;\r\n\r\n constructor(\r\n table: HTMLTableElement,\r\n template: HTMLTemplateElement,\r\n idColumn: string,\r\n component: HTMLElement\r\n ) {\r\n this.table = table;\r\n this.template = template;\r\n this.IdColumn = idColumn;\r\n this.component = component;\r\n }\r\n\r\n public render(data: Record<string, any>[]) {\r\n this.clearRows();\r\n for (const item of data) {\r\n this.renderRow(item);\r\n }\r\n }\r\n\r\n private clearRows(): void {\r\n this.table.tBodies[0].innerHTML = '';\r\n this.dataMap.clear();\r\n this.rowMap.clear();\r\n }\r\n\r\n private renderRow(data: Record<string, any>): void {\r\n const id = data[this.IdColumn];\r\n if (id === undefined || id === null) {\r\n throw new Error(`Missing IdColumn '${this.IdColumn}' in data`);\r\n }\r\n\r\n const row = this.template.content.firstElementChild?.cloneNode(true) as HTMLTableRowElement;\r\n if (!row) throw new Error(\"Template must have a <tr> as its first child\");\r\n\r\n this.populateRow(row, data);\r\n this.attachEventHandlers(row, data);\r\n\r\n this.table.tBodies[0].appendChild(row);\r\n this.dataMap.set(id, data);\r\n this.rowMap.set(id, row);\r\n }\r\n\r\n private populateRow(row: HTMLTableRowElement, data: Record<string, any>): void {\r\n const cells = row.querySelectorAll('[data-field]');\r\n cells.forEach((cell) => {\r\n const field = (cell as HTMLElement).dataset.field;\r\n if (field && field in data) {\r\n cell.textContent = String(data[field]);\r\n }\r\n });\r\n }\r\n\r\n private attachEventHandlers(row: HTMLElement, data: Record<string, any>): void {\r\n const interactiveElements = row.querySelectorAll('[onclick]');\r\n interactiveElements.forEach((el) => {\r\n const element = el as HTMLElement;\r\n const handlerAttr = element.getAttribute('onclick');\r\n if (!handlerAttr) return;\r\n\r\n const match = handlerAttr.match(/^(\\w+)(\\(([^)]*)\\))?$/);\r\n if (!match) return;\r\n\r\n const [, methodName, , argStr] = match;\r\n const args = argStr ? argStr.split(',').map(s => s.trim().replace(/^['\"]|['\"]$/g, '')) : [];\r\n\r\n if (typeof (this.component as any)[methodName] === 'function') {\r\n element.removeAttribute('onclick');\r\n element.addEventListener('click', (event) => {\r\n (this.component as any)[methodName](...args, data, event);\r\n });\r\n }\r\n });\r\n }\r\n\r\n public update(data: Record<string, any>) {\r\n const id = data[this.IdColumn];\r\n if (id === undefined || id === null) {\r\n throw new Error(`Missing IdColumn '${this.IdColumn}' in update data`);\r\n }\r\n\r\n const row = this.rowMap.get(id);\r\n if (!row) {\r\n this.renderRow(data);\r\n } else {\r\n this.populateRow(row, data);\r\n this.attachEventHandlers(row, data);\r\n this.dataMap.set(id, data);\r\n }\r\n }\r\n}\r\n\r\nexport class SortChangeEvent extends CustomEvent<SortColumn[]> {\r\n constructor(sortColumns: SortColumn[]) {\r\n super('sortchange', {\r\n detail: sortColumns,\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\n\r\ntype SortDirection = 'asc' | 'desc';\r\nexport type SortColumn = { column: string; direction: SortDirection };\r\n\r\nexport class TableSorter {\r\n private table: HTMLTableElement;\r\n private sortColumns: SortColumn[] = [];\r\n private component: HTMLElement;\r\n\r\n constructor(table: HTMLTableElement, component: HTMLElement) {\r\n this.table = table;\r\n this.component = component;\r\n this.setupListeners();\r\n }\r\n\r\n private setupListeners() {\r\n const headers = this.table.tHead?.querySelectorAll('th[name]');\r\n headers?.forEach((th) => {\r\n th.addEventListener('click', () => {\r\n const column = th.getAttribute('name')!;\r\n this.toggle(column);\r\n this.updateSortIndicators();\r\n this.emit();\r\n });\r\n });\r\n }\r\n\r\n private toggle(column: string) {\r\n const index = this.sortColumns.findIndex(c => c.column === column);\r\n\r\n if (index === -1) {\r\n this.sortColumns.push({ column, direction: 'asc' });\r\n } else if (this.sortColumns[index].direction === 'asc') {\r\n this.sortColumns[index].direction = 'desc';\r\n } else {\r\n this.sortColumns.splice(index, 1);\r\n }\r\n }\r\n\r\n private emit() {\r\n const event = new SortChangeEvent(this.sortColumns);\r\n this.component.dispatchEvent(event);\r\n }\r\n\r\n private updateSortIndicators() {\r\n const headers = this.table.tHead?.querySelectorAll('th[name]');\r\n headers?.forEach((th: HTMLElement) => {\r\n // Remove existing indicators\r\n const existingIndicator = th.querySelector('.sort-indicator') as HTMLElement;\r\n if (existingIndicator) {\r\n th.removeChild(existingIndicator);\r\n }\r\n\r\n // Get column name and find if it's sorted\r\n const column = th.getAttribute('name')!;\r\n const sortInfo = this.sortColumns.find(c => c.column === column);\r\n \r\n if (sortInfo) {\r\n // Create indicator element\r\n const indicator = document.createElement('span');\r\n indicator.className = 'sort-indicator';\r\n indicator.textContent = sortInfo.direction === 'asc' ? '\u2191' : '\u2193';\r\n \r\n // Style for right alignment\r\n indicator.style.float = 'right';\r\n indicator.style.marginLeft = '5px';\r\n \r\n // Append to header\r\n th.appendChild(indicator);\r\n }\r\n \r\n // Ensure header is positioned relatively for absolute positioning if needed\r\n if (!th.style.position) {\r\n th.style.position = 'relative';\r\n }\r\n });\r\n }\r\n\r\n public getSortColumns(): SortColumn[] {\r\n return [...this.sortColumns];\r\n }\r\n\r\n public clear() {\r\n this.sortColumns = [];\r\n this.updateSortIndicators();\r\n this.emit();\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLTableElementEventMap extends HTMLElementEventMap {\r\n 'sortchange': SortChangeEvent;\r\n }\r\n\r\n interface HTMLTableElement {\r\n addEventListener<K extends keyof HTMLTableElementEventMap>(\r\n type: K,\r\n listener: (this: HTMLTableElement, ev: HTMLTableElementEventMap[K]) => any,\r\n options?: boolean | AddEventListenerOptions\r\n ): void;\r\n }\r\n}", "type WebComponentConstructor = new (...args: any[]) => HTMLElement;\r\n\r\nexport enum GuardResult {\r\n /**\r\n * Handle route without checking more guards.\r\n */\r\n Allow,\r\n\r\n /**\r\n * Throw a RouteGuardError.\r\n */\r\n Deny,\r\n\r\n /**\r\n * Resume and check other guards.\r\n */\r\n Continue,\r\n\r\n /**\r\n * Do not invoke the rooute nor other guards.\r\n */\r\n Stop\r\n}\r\n\r\nexport interface RouteGuard {\r\n check(route: RouteMatchResult): GuardResult;\r\n}\r\n\r\nexport interface Route {\r\n name?: string;\r\n target?: string;\r\n path: string;\r\n\r\n /**\r\n * HTML file name (without extension).\r\n *\r\n * Define for instance if you have a route that requires a more limited layout. The library\r\n * will automatically load that HTML file and rewrite URL history so that the correct url is displayed.\r\n */\r\n layout?: string;\r\n\r\n /**\r\n * Name of the tag for your web component.\r\n */\r\n componentTagName?: string;\r\n\r\n /**\r\n * Guards used to check if this route can be visited.\r\n */\r\n guards?: RouteGuard[];\r\n\r\n component?: WebComponentConstructor;\r\n}\r\n\r\nexport type RouteParamType = string | number;\r\nexport type RouteData = Record<string, RouteParamType>;\r\n\r\n/**\r\n * Implement to receive typed route parameters via a `routeData` property.\r\n * RouteTarget assigns `routeData` after element creation but before DOM insertion.\r\n * Optional since it's not available at construction time.\r\n *\r\n * For convention-based usage without undefined checks, skip the interface\r\n * and declare `routeData` directly on your component.\r\n *\r\n * @example\r\n * class UserProfile extends HTMLElement implements Routable<{ userName: string }> {\r\n * routeData?: { userName: string };\r\n * }\r\n */\r\nexport interface Routable<T extends RouteData = RouteData> {\r\n routeData?: T;\r\n}\r\n\r\n/**\r\n * Implement to run async initialization before the component is added to the DOM.\r\n * RouteTarget calls `loadRoute()` and awaits it before inserting the element.\r\n *\r\n * @example\r\n * class OrderDetail extends HTMLElement implements LoadRoute<{ orderId: number }> {\r\n * async loadRoute(data: { orderId: number }) {\r\n * this.order = await fetchOrder(data.orderId);\r\n * }\r\n * }\r\n */\r\nexport interface LoadRoute<T extends RouteData = RouteData> {\r\n loadRoute(data: T): void | Promise<void>;\r\n}\r\n\r\n/**\r\n * Result from route matching operations.\r\n * Contains all information needed for navigation and rendering.\r\n */\r\nexport type RouteMatchResult = {\r\n /**\r\n * Matched route configuration\r\n */\r\n route: Route;\r\n\r\n /**\r\n * URL segments used for history state\r\n */\r\n urlSegments: string[];\r\n\r\n /**\r\n * Extracted and type-converted parameters\r\n */\r\n params: RouteData;\r\n};\r\n\r\n/**\r\n * Supported types of route segments\r\n */\r\nexport type RouteSegmentType = 'string' | 'number' | 'path' | 'regex';\r\n\r\n/**\r\n * Strongly typed route segment value\r\n */\r\nexport interface RouteValue {\r\n /**\r\n * Type of parameter for validation\r\n */\r\n type: RouteSegmentType;\r\n\r\n /**\r\n * Actual parameter value\r\n */\r\n value: any;\r\n}\r\n\r\nexport class RouteError extends Error {}\r\nexport class RouteGuardError extends RouteError {\r\n isGuard;\r\n}\r\n\r\nexport interface NavigateOptions {\r\n /**\r\n * Optional parameters when using route name\r\n */\r\n params?: Record<string, string | number>;\r\n\r\n /**\r\n * override for route's default target\r\n */\r\n target?: string;\r\n\r\n /**\r\n * When you want to override routes from the globally registered ones.\r\n */\r\n routes?: Route[];\r\n}\r\n", "import type { Route, RouteData } from './types';\r\n\r\n/**\r\n * Event sent to routing targets when a new route should be displayed.\r\n */\r\nexport class NavigateRouteEvent extends Event {\r\n static NAME: string = 'rlx.navigateRoute';\r\n constructor(\r\n /**\r\n * Matched route.\r\n */\r\n public route: Route,\r\n\r\n /**\r\n * The generated url sements which can be used to push the url into the browser history.\r\n */\r\n public urlSegments: string[],\r\n\r\n /**\r\n * Data supplied to the route.\r\n */\r\n public routeData?: RouteData,\r\n\r\n /**\r\n * The target can differ from the default target that is defined in the route.\r\n *\r\n * undefined means that the default (unnamed) target should be used.\r\n */\r\n public routeTarget?: string,\r\n\r\n eventInit?: EventInit\r\n ) {\r\n super(NavigateRouteEvent.NAME, eventInit);\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'rlx.navigateRoute': NavigateRouteEvent;\r\n }\r\n interface DocumentEventMap {\r\n 'rlx.navigateRoute': NavigateRouteEvent;\r\n }\r\n}\r\n", "import { reportError } from '../errors';\r\nimport { NavigateRouteEvent } from './NavigateRouteEvent';\r\n\r\ntype RouteTargetHandler = (evt: NavigateRouteEvent) => void;\r\nconst targetHandlers = new Map<string | undefined, RouteTargetHandler>();\r\nconst pendingEvents = new Map<string | undefined, NavigateRouteEvent>();\r\n\r\n/**\r\n * Registers a route target handler.\r\n * When a navigation event targets this name, the handler is called directly.\r\n * If a pending event exists for this target, it is replayed immediately.\r\n *\r\n * @param name - Target name, or `undefined` for the default (unnamed) target\r\n * @param handler - Callback that receives the `NavigateRouteEvent`\r\n *\r\n * @example\r\n * registerRouteTarget('sidebar', (evt) => renderComponent(evt));\r\n */\r\nexport function registerRouteTarget(\r\n name: string | undefined,\r\n handler: RouteTargetHandler,\r\n) {\r\n initRouteTargetListener();\r\n if (targetHandlers.has(name)) {\r\n const error = reportError('Duplicate route target', {\r\n target: name ?? 'default',\r\n });\r\n if (error) throw error;\r\n return;\r\n }\r\n targetHandlers.set(name, handler);\r\n\r\n const pending = pendingEvents.get(name);\r\n if (pending) {\r\n pendingEvents.delete(name);\r\n handler(pending);\r\n }\r\n}\r\n\r\n/**\r\n * Unregisters a previously registered route target handler.\r\n *\r\n * @param name - Target name that was passed to `registerRouteTarget`\r\n */\r\nexport function unregisterRouteTarget(name: string | undefined) {\r\n targetHandlers.delete(name);\r\n}\r\n\r\nexport function clearPendingNavigations() {\r\n pendingEvents.clear();\r\n targetHandlers.clear();\r\n}\r\n\r\nfunction dispatchToTarget(evt: NavigateRouteEvent) {\r\n const handler = targetHandlers.get(evt.routeTarget);\r\n if (handler) {\r\n handler(evt);\r\n } else {\r\n pendingEvents.set(evt.routeTarget, evt);\r\n }\r\n}\r\n\r\nlet listenerAttached = false;\r\n\r\nexport function initRouteTargetListener() {\r\n if (listenerAttached) return;\r\n listenerAttached = true;\r\n document.addEventListener(NavigateRouteEvent.NAME, (evt) => {\r\n dispatchToTarget(evt as NavigateRouteEvent);\r\n });\r\n}\r\n", "import type { Route, RouteData, RouteParamType, RouteMatchResult } from './types';\r\n\r\n/**\r\n * Route segment matcher interface.\r\n * Each segment type (string, number, path) implements this\r\n * for parameter extraction and validation.\r\n */\r\ninterface RouteSegment {\r\n /**\r\n * Parameter name when segment is dynamic (:name or ;id)\r\n */\r\n paramName?: string;\r\n\r\n /**\r\n * Validates if URL segment matches pattern\r\n * @param value Segment from URL to validate\r\n */\r\n isMatch(value: string): boolean;\r\n\r\n /**\r\n * Converts URL segment to typed parameter\r\n * @param pathValue Raw value from URL\r\n */\r\n getValue(pathValue: string): RouteParamType;\r\n}\r\n\r\n/**\r\n * Number parameter segment matcher.\r\n * Used for ;id style parameters that must be numbers.\r\n */\r\nclass NumberRouteSegment implements RouteSegment {\r\n constructor(public paramName: string) {}\r\n isMatch(value: string): boolean {\r\n if (/^\\d+$/.test(value)) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n getValue(pathValue: string): RouteParamType {\r\n if (/^\\d+$/.test(pathValue) === false) {\r\n throw new Error(\r\n `Path is not a number, parameter name '${this.paramName}', value: '${pathValue}'.`\r\n );\r\n }\r\n return parseInt(pathValue);\r\n }\r\n}\r\n\r\n/**\r\n * String parameter segment matcher.\r\n * Used for :name style parameters.\r\n */\r\nclass StringRouteSegment implements RouteSegment {\r\n constructor(public paramName: string) {}\r\n isMatch(value: string): boolean {\r\n return true;\r\n }\r\n\r\n /**\r\n *\r\n * @param pathValue the route data (for route by name) or segment extracted from the url (for url routing).\r\n * @returns\r\n */\r\n getValue(pathValue: string): RouteParamType {\r\n return pathValue;\r\n }\r\n}\r\n\r\n/**\r\n * Static path segment matcher.\r\n * Used for fixed URL parts like 'users' in /users/:id\r\n */\r\nclass PathRouteSegment implements RouteSegment {\r\n constructor(public value: string) {}\r\n isMatch(value: string): boolean {\r\n return value == this.value;\r\n }\r\n\r\n getValue(_pathValue: string): RouteParamType {\r\n return this.value;\r\n }\r\n}\r\n\r\n/**\r\n * Internal route implementation that handles segment matching\r\n * and parameter extraction.\r\n */\r\nclass RouteImp {\r\n constructor(public route: Route, private segments: RouteSegment[]) {}\r\n\r\n /**\r\n * Attempts to match URL segments against route pattern\r\n * @param segments URL parts to match\r\n * @returns Match result with parameters if successful\r\n */\r\n match(segments: string[]): RouteMatchResult | null {\r\n if (segments.length != this.segments.length) {\r\n return null;\r\n }\r\n\r\n const generatedSegments: string[] = [];\r\n var params: RouteData = {};\r\n for (let index = 0; index < segments.length; index++) {\r\n const urlSegment = segments[index];\r\n const ourSegment = this.segments[index];\r\n\r\n if (!ourSegment.isMatch(urlSegment)) {\r\n return null;\r\n }\r\n\r\n if (ourSegment.paramName) {\r\n const value = ourSegment.getValue(urlSegment);\r\n params[ourSegment.paramName] = value;\r\n generatedSegments.push(value.toString());\r\n } else {\r\n generatedSegments.push(urlSegment);\r\n }\r\n }\r\n\r\n return { route: this.route, params, urlSegments: generatedSegments };\r\n }\r\n\r\n /**\r\n * Routing by name and route data, so generate the url segments.\r\n * @param routeData Data to use in the URL.\r\n * @returns Match result with parameters if successful\r\n */\r\n buildUrl(routeData: RouteData): RouteMatchResult | null {\r\n const urlSegments: string[] = [];\r\n for (let index = 0; index < this.segments.length; index++) {\r\n const ourSegment = this.segments[index];\r\n if (ourSegment.paramName) {\r\n var value = routeData[ourSegment.paramName];\r\n if (!value) {\r\n throw new Error(\r\n `Route \"${\r\n this.route.name\r\n }\" did not get value for parameter \"${\r\n ourSegment.paramName\r\n } from the provided routeData: \"${JSON.stringify(\r\n routeData\r\n )}\".`\r\n );\r\n }\r\n\r\n urlSegments.push(value.toString());\r\n } else {\r\n urlSegments.push(ourSegment.getValue('').toString());\r\n }\r\n }\r\n\r\n return { route: this.route, params: routeData, urlSegments };\r\n }\r\n\r\n /**\r\n * Converts string parameters to proper types\r\n * @param routeParams Raw string parameters to convert\r\n */\r\n parseParameters(routeParams: Record<string, string>): RouteData {\r\n const d: Record<string, any> = {};\r\n\r\n this.segments.forEach((segment) => {\r\n if (!segment.paramName) {\r\n return;\r\n }\r\n\r\n if (!segment.isMatch(providedValue)) {\r\n throw new Error(\r\n `Failed to convert parameter ${segment.paramName}, or missing value: ${providedValue}, route: ${this.route.name}.`\r\n );\r\n }\r\n\r\n var providedValue = routeParams[segment.paramName];\r\n if (!providedValue) {\r\n throw new Error(\r\n `Parameter ${segment.paramName} was not provided, route: ${this.route.name}.`\r\n );\r\n }\r\n\r\n var convertedValue = segment.getValue(providedValue);\r\n d[segment.paramName] = convertedValue;\r\n });\r\n\r\n return d;\r\n }\r\n}\r\n\r\n/**\r\n * Match route by either name or URL pattern\r\n * @param routes Available routes\r\n * @param routeNameOrUrl Route name or URL to match\r\n * @param routeData Optional parameters for named routes\r\n */\r\nexport function matchRoute(\r\n routes: Route[],\r\n routeNameOrUrl: string,\r\n routeData?: Record<string, string | any>\r\n): RouteMatchResult | null {\r\n if (routeNameOrUrl === '' || routeNameOrUrl.indexOf('/') >= 0) {\r\n return findRouteByUrl(routes, routeNameOrUrl || '/');\r\n } else {\r\n return findRouteByName(routes, routeNameOrUrl, routeData!);\r\n }\r\n}\r\n\r\n/**\r\n * Find route by name and apply parameters\r\n * @param routes Available routes\r\n * @param name Route name to find\r\n * @param routeData Parameters to apply\r\n */\r\nexport function findRouteByName(\r\n routes: Route[],\r\n name: string,\r\n routeData?: Record<string, string | any>\r\n): RouteMatchResult | null {\r\n var route = routes.find((x) => x.name === name);\r\n if (!route) {\r\n return null;\r\n }\r\n\r\n var imp = generateRouteImp(route);\r\n var result = imp.buildUrl(routeData);\r\n return result;\r\n}\r\n\r\n/**\r\n * Find route matching URL pattern\r\n * @param routes Available routes\r\n * @param path URL to match\r\n */\r\nexport function findRouteByUrl(\r\n routes: Route[],\r\n path: string\r\n): RouteMatchResult | null {\r\n const urlSegments = path.replace(/^\\/|\\/$/g, '').split('/');\r\n const routeImps = generateRouteImps(routes);\r\n\r\n for (let index = 0; index < routeImps.length; index++) {\r\n const element = routeImps[index];\r\n const m = element.match(urlSegments);\r\n if (m) {\r\n return m;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Generate implementations for all routes\r\n */\r\nfunction generateRouteImps(routes: Route[]) {\r\n const routeImps: RouteImp[] = [];\r\n routes.forEach((route) => {\r\n var imp = generateRouteImp(route);\r\n routeImps.push(imp);\r\n });\r\n\r\n return routeImps;\r\n}\r\n\r\n/**\r\n * Generate implementation for single route\r\n * Parses URL pattern into segment matchers\r\n */\r\nfunction generateRouteImp(route: Route): RouteImp {\r\n var impSegments = [];\r\n const segments = route.path.replace(/^\\/|\\/$/g, '').split('/');\r\n segments.forEach((segment) => {\r\n if (segment.substring(0, 1) == ':') {\r\n impSegments.push(new StringRouteSegment(segment.substring(1)));\r\n } else if (segment.substring(0, 1) === ';') {\r\n impSegments.push(new NumberRouteSegment(segment.substring(1)));\r\n } else if (segment.substring(0, 1) === '{') {\r\n } else {\r\n impSegments.push(new PathRouteSegment(segment));\r\n }\r\n });\r\n\r\n var imp = new RouteImp(route, impSegments);\r\n return imp;\r\n}\r\n", "import { navigate, printRoutes } from './navigation';\r\nimport { RelaxError, reportError } from '../errors';\r\n\r\nexport class RouteLink extends HTMLElement {\r\n static get observedAttributes() {\r\n return ['name', 'target', 'params'];\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.addEventListener('click', e => this.handleClick(e));\r\n }\r\n\r\n private handleClick(e: MouseEvent) {\r\n e.preventDefault();\r\n \r\n const name = this.getAttribute('name');\r\n if (!name) return;\r\n\r\n console.log('Calling printRoutes from RouteLink in relaxjs/components');\r\n printRoutes();\r\n \r\n const params: Record<string, string> = {};\r\n for (const attr of Array.from(this.attributes)) {\r\n if (attr.name.startsWith('param-')) {\r\n const paramName = attr.name.substring(6);\r\n params[paramName] = attr.value;\r\n }\r\n }\r\n\r\n const paramsAttr = this.getAttribute('params');\r\n let additionalParams: Record<string, string | number> | undefined;\r\n if (paramsAttr) {\r\n try {\r\n const parsed = JSON.parse(paramsAttr);\r\n additionalParams = parsed as Record<string, string | number>;\r\n } catch (error) {\r\n const err = reportError('Failed to parse route params', {\r\n element: 'r-link',\r\n params: paramsAttr,\r\n cause: error,\r\n });\r\n if (err) throw err;\r\n }\r\n }\r\n\r\n const target = this.getAttribute('target');\r\n if (additionalParams){\r\n Object.assign(params, additionalParams);\r\n }\r\n\r\n try {\r\n navigate(name, { params, target: target || undefined });\r\n } catch (error) {\r\n if (error instanceof RelaxError) throw error;\r\n const reported = reportError('Navigation failed', {\r\n element: 'r-link',\r\n route: name,\r\n params,\r\n target,\r\n cause: error,\r\n });\r\n if (reported) throw reported;\r\n }\r\n }\r\n\r\n connectedCallback() {\r\n if (!this.hasAttribute('tabindex')) {\r\n this.setAttribute('tabindex', '0');\r\n }\r\n \r\n this.style.cursor = 'pointer';\r\n this.role = 'link';\r\n }\r\n\r\n disconnectedCallback() {\r\n this.removeEventListener('click', this.handleClick);\r\n }\r\n}", "import { registerRouteTarget, unregisterRouteTarget } from './routeTargetRegistry';\r\nimport type { NavigateRouteEvent } from './NavigateRouteEvent';\r\nimport type { RouteData, LoadRoute } from './types';\r\nimport { RelaxError, reportError } from '../errors';\r\n\r\n/**\r\n * WebComponent that listens on the `NavigateRouteEvent` event to be able to switch route.\r\n *\r\n * Use the \"name\" attribute to make this non-default target.\r\n * Use the \"dialog\" attribute to render routes inside a native `<dialog>` element\r\n * with built-in focus trapping, backdrop, and Escape-to-close.\r\n *\r\n * @example\r\n * <r-route-target></r-route-target>\r\n * <r-route-target name=\"modal\" dialog></r-route-target>\r\n */\r\nexport class RouteTarget extends HTMLElement {\r\n name?: string = undefined;\r\n private dialog?: HTMLDialogElement;\r\n\r\n connectedCallback() {\r\n this.name = this.getAttribute('name') ?? undefined;\r\n\r\n if (this.hasAttribute('dialog')) {\r\n this.dialog = document.createElement('dialog');\r\n this.dialog.addEventListener('close', () => {\r\n this.dialog!.replaceChildren();\r\n });\r\n this.appendChild(this.dialog);\r\n }\r\n\r\n registerRouteTarget(this.name, (evt) => this.onNavigate(evt));\r\n console.log('registered');\r\n }\r\n\r\n disconnectedCallback() {\r\n unregisterRouteTarget(this.name);\r\n }\r\n\r\n private onNavigate(evt: NavigateRouteEvent) {\r\n console.log('got nav', evt);\r\n this.loadComponent(evt).catch((error) => {\r\n if (!(error instanceof RelaxError)) {\r\n error = reportError('Route navigation failed', {\r\n route: evt.route.name,\r\n routeTarget: evt.routeTarget,\r\n cause: error,\r\n });\r\n }\r\n if (error) {\r\n console.error(error);\r\n }\r\n });\r\n }\r\n\r\n private async loadComponent(evt: NavigateRouteEvent) {\r\n const tagName = evt.route.componentTagName\r\n ?? customElements.getName(evt.route.component);\r\n\r\n if (!tagName) {\r\n const error = reportError('Failed to find component for route', {\r\n route: evt.route.name,\r\n componentTagName: evt.route.componentTagName,\r\n component: evt.route.component?.name,\r\n routeData: evt.routeData,\r\n });\r\n if (error) throw error;\r\n return;\r\n }\r\n\r\n await customElements.whenDefined(tagName);\r\n const element = document.createElement(tagName);\r\n\r\n await this.applyRouteData(element, evt.routeData);\r\n\r\n if (this.dialog) {\r\n this.dialog.replaceChildren(element);\r\n if (!this.dialog.open) {\r\n this.dialog.showModal();\r\n }\r\n } else if (document.startViewTransition) {\r\n document.startViewTransition(() => this.replaceChildren(element));\r\n } else {\r\n this.replaceChildren(element);\r\n }\r\n }\r\n\r\n /** Closes the dialog (only applies to dialog targets). */\r\n close() {\r\n this.dialog?.close();\r\n }\r\n\r\n private async applyRouteData(element: Element, data?: RouteData) {\r\n if ('loadRoute' in element) {\r\n const routeData = data\r\n ?? { error: 'loadRoute function without mapped route data in the routes' };\r\n await (element as unknown as LoadRoute).loadRoute(routeData);\r\n }\r\n\r\n if (data) {\r\n (element as any).routeData = data;\r\n }\r\n }\r\n}\r\n", "/**\r\n * Single Page Application routing system with multiple target support.\r\n * Designed for scenarios where you need:\r\n * - Multiple navigation targets (main content, modals, sidebars)\r\n * - Strongly typed route parameters\r\n * - History management with back/forward support\r\n *\r\n * @example\r\n * // Configure routes\r\n * const routes = [\r\n * { name: 'user', path: '/users/:id' }, // String parameter\r\n * { name: 'order', path: '/orders/;orderId' }, // Number parameter\r\n * { name: 'modal', path: '/detail/:id', target: 'modal' } // Custom target\r\n * ];\r\n */\r\n\r\nimport { reportError } from '../errors';\r\nimport {\r\n GuardResult,\r\n RouteError,\r\n RouteGuardError,\r\n type Route,\r\n type RouteData,\r\n type RouteParamType,\r\n type RouteMatchResult,\r\n type NavigateOptions,\r\n} from './types';\r\nimport { NavigateRouteEvent } from './NavigateRouteEvent';\r\nimport { matchRoute } from './routeMatching';\r\nimport { initRouteTargetListener } from './routeTargetRegistry';\r\nimport { RouteLink } from './RouteLink';\r\nimport { RouteTarget } from './RoutingTarget';\r\n\r\n/**\r\n * Used to keep track of current main HTML file,\r\n * used when different layouts are supported.\r\n *\r\n * The default page is ALWAYS loaded initially,\r\n * which means that we need to switch layout page\r\n * if someone else is configured for the route.\r\n */\r\nvar currentLayout = getLayout() ?? 'default';\r\nfunction getLayout() {\r\n const path = window.location.pathname;\r\n if (path == '/index.html') {\r\n return 'default';\r\n }\r\n\r\n return path.endsWith('.html') ? path.slice(1, -5) : null;\r\n}\r\n\r\nexport const internalRoutes: Route[] = [];\r\n\r\nexport const MyData = {\r\n routes: []\r\n};\r\n\r\n/**\r\n * Debug helper to print all registered routes to console.\r\n */\r\nexport function printRoutes() {\r\n console.log(internalRoutes);\r\n}\r\n\r\n/**\r\n * Registers application routes with the router.\r\n * Call this at application startup before routing begins.\r\n *\r\n * @param appRoutes - Array of route configurations\r\n * @throws Error if referenced components are not registered\r\n *\r\n * @example\r\n * const routes: Route[] = [\r\n * { name: 'home', path: '/', componentTagName: 'app-home' },\r\n * { name: 'user', path: '/users/:id', componentTagName: 'user-profile' },\r\n * { name: 'login', path: '/auth/', componentTagName: 'login-form', layout: 'noauth' }\r\n * ];\r\n * defineRoutes(routes);\r\n */\r\nexport function defineRoutes(appRoutes: Route[]) {\r\n console.log('defining routes1', appRoutes);\r\n initRouteTargetListener();\r\n if (!customElements.get('r-route-target')) {\r\n customElements.define('r-route-target', RouteTarget);\r\n }\r\n if (!customElements.get('r-link')) {\r\n customElements.define('r-link', RouteLink);\r\n }\r\n console.log('defining routes', appRoutes);\r\n internalRoutes.length = 0;\r\n internalRoutes.push(...appRoutes);\r\n\r\n var errs = [];\r\n appRoutes.forEach((route) => {\r\n if (\r\n route.componentTagName &&\r\n !customElements.get(route.componentTagName)\r\n ) {\r\n errs.push(\r\n `Component with tagName '${route.componentTagName}' is not defined in customElements.`\r\n );\r\n }\r\n if (route.component && !customElements.getName(route.component)) {\r\n errs.push(\r\n `Component '${route.component.name}' is not defined in customElements. Used in route '${JSON.stringify(route)}'.`\r\n );\r\n }\r\n if (route.layout === '') {\r\n console.log('should not use empty string layout.', route);\r\n route.layout = undefined;\r\n }\r\n });\r\n\r\n if (errs.length > 0) {\r\n throw new Error(errs.join('\\n'));\r\n }\r\n}\r\n\r\n/**\r\n * Initializes routing and navigates to the current URL.\r\n * Call this after DOM is ready and routes are defined.\r\n *\r\n * @example\r\n * // In your main application component\r\n * connectedCallback() {\r\n * defineRoutes(routes);\r\n * startRouting();\r\n * }\r\n */\r\nexport function startRouting() {\r\n let newPage = false;\r\n if (currentLayout == '') {\r\n const path = window.location.pathname;\r\n const match = path.match(/\\/([^\\/]+)\\.html$/);\r\n if (match && match[1] !== '') {\r\n console.log('setting current layut', match[1]);\r\n currentLayout = match[1];\r\n newPage = true;\r\n } else {\r\n console.log('Setting default layout name');\r\n currentLayout = 'default';\r\n }\r\n }\r\n\r\n if (tryLoadRouteFromLayoutNavigation()) {\r\n return;\r\n }\r\n\r\n const currentUrl = window.location.pathname.replace(/^\\/|\\/$/g, '') || '/';\r\n const routeResult = findRoute(currentUrl, {});\r\n\r\n const searchParams = new URLSearchParams(window.location.search);\r\n if (searchParams.size > 0) {\r\n routeResult.params ??= {};\r\n searchParams.forEach((value, key) => {\r\n routeResult.params[key] = value;\r\n });\r\n }\r\n\r\n if (navigateToLayout(routeResult)) {\r\n return;\r\n }\r\n\r\n history.replaceState(\r\n routeResult.urlSegments,\r\n '',\r\n '/' + routeResult.urlSegments.join('/')\r\n );\r\n\r\n const e = new NavigateRouteEvent(\r\n routeResult.route,\r\n routeResult.urlSegments,\r\n routeResult.params,\r\n routeResult.route.target\r\n );\r\n document.dispatchEvent(e);\r\n}\r\n\r\n/**\r\n * Navigates to a route by name or URL.\r\n * Updates browser history and dispatches navigation events.\r\n *\r\n * @param routeNameOrUrl - Route name or URL path to navigate to\r\n * @param options - Navigation options including params and target\r\n *\r\n * @example\r\n * // Navigate by route name\r\n * navigate('user', { params: { id: '123' } });\r\n *\r\n * // Navigate by URL\r\n * navigate('/users/123');\r\n *\r\n * // Navigate to specific target\r\n * navigate('detail', { params: { id: '42' }, target: 'modal' });\r\n */\r\nexport function navigate(routeNameOrUrl: string, options?: NavigateOptions) {\r\n console.log('navigating to ', routeNameOrUrl, options);\r\n const routeResult = findRoute(routeNameOrUrl, options);\r\n if (navigateToLayout(routeResult)) {\r\n return;\r\n }\r\n\r\n const target = options?.target ?? routeResult.route.target;\r\n const ourUrl = routeResult.urlSegments.join('/');\r\n const currentUrl = window.location.pathname.replace(/^\\/|\\/$/g, '');\r\n if (currentUrl != ourUrl) {\r\n history.pushState(\r\n routeResult.urlSegments,\r\n '',\r\n '/' + routeResult.urlSegments.join('/')\r\n );\r\n }\r\n const e = new NavigateRouteEvent(\r\n routeResult.route,\r\n routeResult.urlSegments,\r\n routeResult.params,\r\n target\r\n );\r\n document.dispatchEvent(e);\r\n}\r\n\r\nfunction findRoute(routeNameOrUrl: string, options?: NavigateOptions) {\r\n const theRoutes = options?.routes ?? internalRoutes;\r\n const params = options?.params;\r\n\r\n const routeResult = matchRoute(theRoutes, routeNameOrUrl, params);\r\n if (!routeResult) {\r\n const errorMsg = generateErrorMessage(\r\n routeNameOrUrl,\r\n params,\r\n theRoutes\r\n );\r\n console.error(errorMsg);\r\n throw new RouteError(errorMsg);\r\n }\r\n\r\n if (!checkRouteGuards(routeResult)) {\r\n throw new RouteGuardError('Route guards stopped navigation for route ' + routeNameOrUrl);\r\n }\r\n\r\n return routeResult;\r\n}\r\n\r\nfunction navigateToLayout(routeResult: RouteMatchResult): boolean {\r\n if (!routeResult) {\r\n console.error('Route result is null, cannot navigate to layout.');\r\n }\r\n\r\n const wantedLayout = (routeResult.route.layout ?? 'default').replace(\r\n /\\.html?$/,\r\n ''\r\n );\r\n if (wantedLayout === currentLayout) {\r\n return false;\r\n }\r\n\r\n console.log(\r\n 'Current layout: ' + currentLayout,\r\n 'Wanted layout: ' + wantedLayout\r\n );\r\n\r\n // The hash means that we attempted to redirect to the same layout once,\r\n // so if it's there and another redirect is requsted, something is wrong.\r\n //\r\n // Because the push history should remove it if everything worked out.\r\n if (window.location.hash) {\r\n throw Error(\r\n 'A redirect failed, does the requsted layout exist? \"' +\r\n wantedLayout +\r\n '\"?'\r\n );\r\n }\r\n\r\n console.log(\r\n `requires layout switch from ${currentLayout} to ${wantedLayout}`\r\n );\r\n const navigationState = {\r\n routeName: routeResult.route.name,\r\n params: routeResult.params || {}\r\n };\r\n\r\n sessionStorage.setItem('layoutNavigation', JSON.stringify(navigationState));\r\n const layoutUrl =\r\n wantedLayout.indexOf('.htm') > -1\r\n ? `/${wantedLayout}#layout`\r\n : `/${wantedLayout}.html#layout`;\r\n console.log('redirecting to ', layoutUrl);\r\n window.location.href = layoutUrl;\r\n return true;\r\n}\r\n/**\r\n * Checks session storage for route information and initiates proper navigation\r\n * Should be called when page loads to handle layout transitions\r\n *\r\n * @returns Whether navigation was initiated from session storage\r\n *\r\n * @example\r\n * // Call on page load\r\n * document.addEventListener('DOMContentLoaded', () => {\r\n * if (handleLayoutNavigation()) {\r\n * console.log('Navigation handled from session storage');\r\n * }\r\n * });\r\n */\r\nfunction tryLoadRouteFromLayoutNavigation(): boolean {\r\n try {\r\n const navigationStateJson = sessionStorage.getItem('layoutNavigation');\r\n if (!navigationStateJson) {\r\n return false;\r\n }\r\n\r\n const navigationState = JSON.parse(navigationStateJson);\r\n sessionStorage.removeItem('layoutNavigation');\r\n console.log('session store navigation ', navigationState);\r\n navigate(navigationState.routeName, {\r\n params: navigationState.params\r\n });\r\n\r\n return true;\r\n } catch (error) {\r\n sessionStorage.removeItem('layoutNavigation');\r\n reportError('Failed to navigate from session storage', {\r\n cause: error,\r\n });\r\n return false;\r\n }\r\n}\r\n\r\nfunction generateErrorMessage(\r\n routeNameOrUrl: string,\r\n routeParams: Record<string, RouteParamType>,\r\n allRoutes: Route[]\r\n): string {\r\n var routeData = '';\r\n if (routeParams) {\r\n routeData += Object.entries(routeParams)\r\n .map(([key, value]) => `${key}=${value}`)\r\n .join(', ');\r\n } else {\r\n routeData = '.';\r\n }\r\n\r\n var routesStr = allRoutes.map(\r\n (x) =>\r\n ` * Name: '${x.name}', path: '${x.path}', target: ${\r\n x.target ?? 'default'\r\n }\\n`\r\n );\r\n return `No route matched '${routeNameOrUrl}${routeData}'. Available routes:\\n${routesStr}`;\r\n}\r\n\r\nfunction checkRouteGuards(routeResult: RouteMatchResult): boolean {\r\n if (\r\n !routeResult ||\r\n !routeResult.route.guards ||\r\n routeResult.route.guards.length == 0\r\n ) {\r\n return true;\r\n }\r\n\r\n for (let index = 0; index < routeResult.route.guards.length; index++) {\r\n const element = routeResult.route.guards[index];\r\n var result = element.check(routeResult);\r\n if (result == GuardResult.Allow) {\r\n return true;\r\n }\r\n\r\n if (result == GuardResult.Stop) {\r\n return false;\r\n }\r\n\r\n if (result == GuardResult.Deny) {\r\n throw new RouteGuardError(\r\n `Guard ${element.constructor.name} said 'Deny' for ${routeResult.route.name}`\r\n );\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that collects property injection configuration.\r\n * Updates or creates the properties mapping in registration options.\r\n * \r\n * @example\r\n * @ContainerService({\r\n * inject: [Database],\r\n * properties: {\r\n * logger: Logger, // Inject by type\r\n * audit: 'auditLogger' // Inject by key\r\n * }\r\n * })\r\n * class UserService {\r\n * @Inject(Logger)\r\n * private logger!: Logger;\r\n * \r\n * @Inject('auditLogger')\r\n * private audit!: Logger;\r\n * \r\n * constructor(db: Database) {}\r\n * }\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n var instance = container.resolve(typeOrKey);\r\n return function(this: any) {\r\n return instance;\r\n }\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that automatically registers a service in the global DI container.\r\n * Use this to declaratively register services without manual registration calls.\r\n *\r\n * Services are registered at module load time, so ensure this file is imported\r\n * before attempting to resolve the decorated service.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Simple service with constructor injection\r\n * @ContainerService({ inject: [DatabaseConnection] })\r\n * class UserRepository {\r\n * constructor(private db: DatabaseConnection) {}\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope, options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);", "/**\r\n * Finds the closest parent element of a specific Web Component type.\r\n * Traverses up the DOM tree looking for an ancestor matching the constructor.\r\n *\r\n * Useful for child components that need to communicate with or access\r\n * their parent container component, common in composite component patterns.\r\n *\r\n * @template T - The type of HTMLElement to find\r\n * @param node - The starting node to search from\r\n * @param constructor - The class constructor of the desired element type\r\n * @returns The matching parent element or null if not found\r\n *\r\n * @example\r\n * // Inside a child component, find the parent container\r\n * class ListItem extends HTMLElement {\r\n * connectedCallback() {\r\n * const list = getParentComponent(this, ListContainer);\r\n * if (list) {\r\n * list.registerItem(this);\r\n * }\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Access parent component's methods\r\n * class TabPanel extends HTMLElement {\r\n * activate() {\r\n * const tabs = getParentComponent(this, TabContainer);\r\n * tabs?.selectPanel(this);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Handle case where parent might not exist\r\n * const form = getParentComponent(input, FormContainer);\r\n * if (!form) {\r\n * console.warn('Input must be inside a FormContainer');\r\n * return;\r\n * }\r\n */\r\nexport function getParentComponent<T extends HTMLElement>(\r\n node: Node,\r\n constructor: { new (...args: any[]): T }\r\n): T | null {\r\n let current = node.parentElement;\r\n\r\n while (current) {\r\n if (current instanceof constructor) {\r\n return current;\r\n }\r\n current = current.parentElement;\r\n }\r\n\r\n return null;\r\n} ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n ", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed", "Node", "value", "removeCallback", "LinkedList", "newNode", "getFieldName", "element", "id", "form", "label", "FormValidator", "options", "event", "formElements", "isFormValid", "errorMessages", "fieldName", "messages", "errorList", "message", "listItem", "errorSummary", "firstInvalidElement", "i", "child", "pluralRulesCache", "getPluralRule", "locale", "escapeRegex", "s", "defaultFormatICU", "message", "values", "_", "key", "type", "categoriesPart", "value", "exact", "category", "match", "escaped", "formatICU", "fallbackLocale", "currentLocale", "translations", "missingHandler", "t", "fullKey", "values", "namespace", "key", "message", "translations", "missingHandler", "currentLocale", "formatICU", "getCurrentLocale", "mapFormToClass", "form", "instance", "options", "formElements", "element", "booleanAttr", "propertyName", "value", "readElementValue", "SKIP", "formFieldNames", "prop", "getDataConverter", "dataType", "createConverterFromDataType", "createConverterFromInputType", "BooleanConverter", "str", "readData", "data", "formData", "seen", "_", "name", "values", "converter", "v", "i", "el", "lower", "NumberConverter", "nr", "getLocaleDateOrder", "locale", "p", "DateConverter", "date", "numericParts", "getCurrentLocale", "order", "mapped", "type", "inputType", "year", "month", "week", "hours", "minutes", "seconds", "attr", "o", "validators", "RegisterValidator", "validationName", "validInputTypes", "target", "getValidator", "name", "_RequiredValidation_decorators", "_init", "_RequiredValidation", "rule", "value", "context", "t", "__decoratorStart", "__decorateElement", "__runInitializers", "RequiredValidation", "_RangeValidation_decorators", "_RangeValidation", "min", "max", "rangeMatch", "num", "actual", "RangeValidation", "_DigitsValidation_decorators", "_DigitsValidation", "DigitsValidation", "setFormData", "form", "data", "element", "name", "arrayName", "arrayValue", "getValueByComplexPath", "el", "type", "boolAttr", "val", "option", "opt", "allWithName", "idx", "value", "setElementValue", "obj", "path", "segments", "currentSegment", "inBrackets", "i", "char", "result", "segment", "index", "setElementValue", "element", "value", "el", "type", "pad", "n", "boolAttr", "options", "vals", "opt", "name", "attr", "uppercasePipe", "value", "trimPipe", "lowercasePipe", "capitalizePipe", "str", "shortenPipe", "length", "maxLength", "currencyPipe", "currency", "locale", "getCurrentLocale", "datePipe", "format", "date", "daysAgoPipe", "inputDate", "today", "diffTime", "diffDays", "t", "piecesPipe", "count", "joinPipe", "separator", "firstPipe", "lastPipe", "keysPipe", "defaultPipe", "defaultValue", "ternaryPipe", "trueValue", "falseValue", "createPipeRegistry", "pipes", "name", "pipe", "defaultPipes", "applyPipes", "registry", "currentValue", "pipeName", "args", "p", "error", "pipes", "defaultPipes", "html", "templateStrings", "substitutions", "template", "resolvedTemplate", "resolveTemplate", "bindings", "walker", "node", "element", "processElement", "myNode", "text", "result", "parseTemplate", "startMarker", "endMarker", "insertedNodes", "instance", "value", "n", "temp", "nodes", "parent", "context", "x", "str", "i", "attrBindings", "attr", "attrValue", "regex", "match", "index", "func", "boundFunction", "attributeCallback", "attrBinding", "parseArguments", "argsStr", "arg", "parts", "part", "lastIndex", "textBindings", "_instance", "sub", "mustacheName", "matchingPipes", "pipe", "args", "val", "_", "binding", "parseExpression", "expr", "pipesSplit", "mainExpr", "pipes", "fnMatch", "fnName", "argsStr", "fnArgs", "a", "resolvePath", "ctx", "path", "segments", "current", "key", "handleError", "config", "message", "context", "shouldThrow", "formattedMessage", "createGetter", "debugInfo", "err", "errorMessage", "evaluateExpression", "parsed", "fns", "value", "registry", "defaultPipes", "fn", "resolvedArgs", "arg", "resolved", "applyPipes", "expressionCache", "textNodePatcher", "node", "_get", "raw", "part", "exprs", "result", "literal", "attributeInterpolationPatcher", "element", "setters", "attributes", "attr", "match", "name", "createConditionalPatcher", "get", "attrName", "shouldRender", "templateNode", "placeholder", "parent", "currentElement", "currentRenderer", "cachedElement", "cachedRenderer", "shouldBeVisible", "clone", "compileDOM", "ifPatcher", "unlessPatcher", "loopPatcher", "loopDef", "alias", "source", "tpl", "slots", "items", "reuseCount", "i", "frag", "newSlots", "instance", "childRenderer", "insertAfter", "structuralPatchers", "contentPatchers", "root", "processNode", "patch", "setter", "child", "lastCtx", "lastFns", "compileTemplate", "templateStr", "content", "render", "parsePath", "notation", "options", "delimiter", "escapeChar", "segments", "current", "inBrackets", "bracketContent", "char", "currentInDelimLength", "nextChar", "nextInDelimLength", "createAccessorFromPath", "path", "record", "segment", "index", "createAccessor", "tokenize", "input", "tokens", "i", "char", "pipeTarget", "quote", "value", "hasDecimal", "isFunctionCall", "bracketCount", "wsCount", "parenCount", "lastToken", "isDotAfterConstant", "tokenizeArgs", "start", "end", "argsStr", "quoteType", "numStr", "ident", "tokenizeMustache", "template", "currentIndex", "openTagIndex", "createStringToken", "mustache", "endIndex", "balanced", "extractMustache", "createMustacheToken", "startIndex", "open", "close", "depth", "compileMustard", "template", "options", "segments", "tokenizeMustache", "token", "_data", "_component", "compileExpression", "data", "component", "fn", "tokens", "tokenize", "chain", "buildExpressionChain", "renderFromChain", "sourceText", "pipeRegistry", "defaultPipes", "createAccessor", "resolveFunction", "pipeName", "args", "p", "pipe", "value", "initial", "result", "acc", "expression", "pos", "resolvedArgs", "tokenizeArgs", "arg", "name", "fnAccessor", "evaluatedArgs", "argFn", "BoundNode", "root", "bindings", "clickBindings", "component", "data", "binding", "click", "node", "method", "evt", "args", "token", "obj", "key", "path", "index", "createBluePrint", "html", "bp", "Blueprint", "htmlOrTemplate", "trimmed", "wrapper", "found", "rootElement", "rootClone", "boundBindings", "el", "walk", "func", "compileMustard", "targetNode", "element", "i", "attr", "child", "clickAttr", "match", "methodName", "argTokens", "tokenizeArgs", "TableRenderer", "table", "template", "idColumn", "component", "data", "item", "id", "row", "cell", "field", "el", "element", "handlerAttr", "match", "methodName", "argStr", "args", "s", "event", "SortChangeEvent", "sortColumns", "TableSorter", "th", "column", "index", "c", "existingIndicator", "sortInfo", "indicator", "GuardResult", "RouteError", "RouteGuardError", "NavigateRouteEvent", "_NavigateRouteEvent", "route", "urlSegments", "routeData", "routeTarget", "eventInit", "targetHandlers", "pendingEvents", "registerRouteTarget", "name", "handler", "initRouteTargetListener", "error", "reportError", "pending", "unregisterRouteTarget", "clearPendingNavigations", "dispatchToTarget", "evt", "listenerAttached", "NavigateRouteEvent", "NumberRouteSegment", "paramName", "value", "pathValue", "StringRouteSegment", "PathRouteSegment", "_pathValue", "RouteImp", "route", "segments", "generatedSegments", "params", "index", "urlSegment", "ourSegment", "routeData", "urlSegments", "routeParams", "d", "segment", "providedValue", "convertedValue", "matchRoute", "routes", "routeNameOrUrl", "findRouteByUrl", "findRouteByName", "name", "x", "imp", "generateRouteImp", "result", "path", "routeImps", "generateRouteImps", "m", "impSegments", "RouteLink", "e", "name", "printRoutes", "params", "attr", "paramName", "paramsAttr", "additionalParams", "error", "err", "reportError", "target", "navigate", "RelaxError", "reported", "RouteTarget", "registerRouteTarget", "evt", "unregisterRouteTarget", "error", "RelaxError", "reportError", "tagName", "element", "data", "routeData", "currentLayout", "getLayout", "path", "internalRoutes", "printRoutes", "internalRoutes", "defineRoutes", "appRoutes", "initRouteTargetListener", "RouteTarget", "RouteLink", "errs", "route", "startRouting", "newPage", "currentLayout", "match", "tryLoadRouteFromLayoutNavigation", "currentUrl", "routeResult", "findRoute", "searchParams", "value", "key", "navigateToLayout", "e", "NavigateRouteEvent", "navigate", "routeNameOrUrl", "options", "target", "ourUrl", "theRoutes", "params", "matchRoute", "errorMsg", "generateErrorMessage", "RouteError", "checkRouteGuards", "RouteGuardError", "wantedLayout", "navigationState", "layoutUrl", "navigationStateJson", "error", "reportError", "routeParams", "allRoutes", "routeData", "routesStr", "x", "index", "element", "result", "Inject", "typeOrKey", "_", "context", "instance", "container", "ContainerService", "options", "target", "opts", "serviceCollection", "Registration", "classConstructor", "scope", "inject", "properties", "key", "ServiceCollection", "constructor", "reg", "existing", "error", "reportError", "existingByKey", "service", "ServiceContainer", "serviceCollection", "keyOrType", "key", "registration", "error", "reportError", "inst", "instance", "constructor", "dependencies", "dep", "fieldName", "ServiceCollection", "container", "getParentComponent", "node", "constructor", "current", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "resolveValue", "path", "context", "value", "key", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn", "i"]
|
|
3
|
+
"sources": ["../src/i18n/locales/en/r-common.json", "../src/i18n/locales/en/r-pipes.json", "../src/i18n/locales/en/r-validation.json", "../src/i18n/locales/sv/r-common.json", "../src/i18n/locales/sv/r-pipes.json", "../src/i18n/locales/sv/r-validation.json", "../src/errors.ts", "../src/collections/LinkedList.ts", "../src/collections/Pager.ts", "../src/forms/FormValidator.ts", "../src/i18n/icu.ts", "../src/i18n/i18n.ts", "../src/forms/FormReader.ts", "../src/forms/ValidationRules.ts", "../src/forms/setFormData.ts", "../src/pipes.ts", "../src/html/html.ts", "../src/html/template.ts", "../src/templates/accessorParser.ts", "../src/templates/tokenizer.ts", "../src/templates/parseTemplate.ts", "../src/templates/NodeTemplate.ts", "../src/html/TableRenderer.ts", "../src/routing/types.ts", "../src/routing/NavigateRouteEvent.ts", "../src/routing/routeTargetRegistry.ts", "../src/routing/routeMatching.ts", "../src/routing/RouteLink.ts", "../src/routing/RoutingTarget.ts", "../src/routing/navigation.ts", "../src/DependencyInjection.ts", "../src/getParentComponent.ts", "../src/SequentialId.ts", "../src/http/http.ts", "../src/http/ServerSentEvents.ts", "../src/tools.ts"],
|
|
4
|
+
"sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n", "/**\r\n * A node in the @see LinkedList.\r\n */\r\nexport class Node<T> {\r\n /**\r\n * Next node unless last one.\r\n */\r\n public next: Node<T> | null = null;\r\n /**\r\n * Previous node unless first one.\r\n */\r\n public prev: Node<T> | null = null;\r\n\r\n /**\r\n * Constructor.\r\n * @param value Value contained in the node.\r\n */\r\n constructor(public value: T, private removeCallback: () => void) {}\r\n\r\n /**\r\n * Remove this node.\r\n * Will notify the list of the update to ensure correct element count.\r\n */\r\n remove() {\r\n this.prev.next = this.next;\r\n this.next.prev = this.prev;\r\n this.removeCallback();\r\n }\r\n}\r\n\r\n/**\r\n * A trivial linked list implementation.\r\n */\r\nexport class LinkedList<T> {\r\n private _first?: Node<T>;\r\n private _last?: Node<T>;\r\n private _length = 0;\r\n\r\n /**\r\n * Add a value to the beginning of the list.\r\n * @param value Value that should be contained in the node.\r\n */\r\n addFirst(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.next = this._first;\r\n this._first.prev = newNode;\r\n this._first = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Add a value to the end of the list.\r\n * @param value Value that should be contained in a node.\r\n */\r\n addLast(value: T) {\r\n const newNode = new Node(value, () => this._length--);\r\n if (!this._first) {\r\n this._first = newNode;\r\n this._last = this._first;\r\n } else {\r\n newNode.prev = this._last;\r\n this._last.next = newNode;\r\n this._last = newNode;\r\n }\r\n\r\n this._length++;\r\n }\r\n\r\n /**\r\n * Remove a node from the beginning of the list.\r\n * @returns Value contained in the first node.\r\n */\r\n removeFirst(): T {\r\n if (!this.first) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._first.value;\r\n this._first = this._first.next;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Remove a node from the end of the list.\r\n * @returns Value contained in the last node.\r\n */\r\n removeLast(): T {\r\n if (!this.last) {\r\n throw new Error('The list is empty.');\r\n }\r\n\r\n const value = this._last.value;\r\n this._last = this._last.prev;\r\n this._length--;\r\n return value;\r\n }\r\n\r\n /**\r\n * Number of nodes in the list.\r\n *\r\n * The count works as long as you do not manually remove nodes (by assigning next/prev to the neighbors).\r\n */\r\n get length(): number {\r\n return this._length;\r\n }\r\n\r\n /**\r\n * First ndoe.\r\n */\r\n get first(): Node<T> | undefined {\r\n return this._first;\r\n }\r\n\r\n /**\r\n * Contained value of the first node.\r\n */\r\n get firstValue(): T | undefined {\r\n return this._first?.value;\r\n }\r\n\r\n /**\r\n * Last node.\r\n */\r\n get last(): Node<T> | undefined {\r\n return this._last;\r\n }\r\n\r\n /**\r\n * Contained value of the last node.\r\n */\r\n get lastValue(): T | undefined {\r\n return this._last?.value;\r\n }\r\n}\r\n", "export class PageSelectedEvent extends Event {\r\n constructor(public page: number) {\r\n super('pageselected', {\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'pageselected': PageSelectedEvent;\r\n }\r\n}\r\n\r\nexport class Pager {\r\n private container: HTMLElement;\r\n private totalCount: number;\r\n private pageSize: number;\r\n private currentPage: number = 1;\r\n\r\n constructor(container: HTMLElement, totalCount: number, pageSize: number) {\r\n this.container = container;\r\n this.totalCount = totalCount;\r\n this.pageSize = pageSize;\r\n\r\n this.render();\r\n }\r\n\r\n private render() {\r\n this.container.innerHTML = '';\r\n\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n\r\n const createButton = (label: string, page: number, disabled: boolean = false) => {\r\n const btn = document.createElement('button');\r\n btn.textContent = label;\r\n btn.disabled = disabled;\r\n btn.addEventListener('click', () => this.selectPage(page));\r\n return btn;\r\n };\r\n\r\n this.container.appendChild(\r\n createButton('Previous', this.currentPage - 1, this.currentPage === 1)\r\n );\r\n\r\n for (let i = 1; i <= pageCount; i++) {\r\n const btn = createButton(i.toString(), i);\r\n if (i === this.currentPage) {\r\n btn.classList.add('selected');\r\n }\r\n this.container.appendChild(btn);\r\n }\r\n\r\n this.container.appendChild(\r\n createButton('Next', this.currentPage + 1, this.currentPage === pageCount)\r\n );\r\n }\r\n\r\n private selectPage(page: number) {\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (page < 1 || page > pageCount || page === this.currentPage) return;\r\n\r\n this.currentPage = page;\r\n this.render();\r\n\r\n this.container.dispatchEvent(new PageSelectedEvent(this.currentPage));\r\n }\r\n\r\n public update(totalCount: number) {\r\n this.totalCount = totalCount;\r\n const pageCount = Math.max(1, Math.ceil(this.totalCount / this.pageSize));\r\n if (this.currentPage > pageCount) {\r\n this.currentPage = pageCount;\r\n }\r\n this.render();\r\n }\r\n\r\n public getCurrentPage(): number {\r\n return this.currentPage;\r\n }\r\n}\r\n", "/**\r\n * @module FormValidator\r\n * Form validation with support for native HTML5 validation and error summaries.\r\n * Provides automatic validation on submit with customizable behavior.\r\n *\r\n * @example\r\n * // Basic usage with submit callback\r\n * const form = document.querySelector('form');\r\n * const validator = new FormValidator(form, {\r\n * submitCallback: () => saveData()\r\n * });\r\n *\r\n * @example\r\n * // With auto-validation on input\r\n * const validator = new FormValidator(form, {\r\n * autoValidate: true,\r\n * useSummary: true\r\n * });\r\n */\r\n\r\n/**\r\n * Gets the human-readable field name from its associated label.\r\n */\r\nfunction getFieldName(element: HTMLElement): string | null {\r\n const id = element.getAttribute('id');\r\n if (id) {\r\n const form = element.closest('form');\r\n if (form) {\r\n const label = form.querySelector(`label[for=\"${id}\"]`) as HTMLLabelElement | null;\r\n if (label) {\r\n return label.textContent?.trim() || null;\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Configuration options for FormValidator.\r\n */\r\nexport interface ValidatorOptions {\r\n /** Validate on every input event, not just submit */\r\n autoValidate?: boolean;\r\n /** Show errors in a summary element instead of browser tooltips */\r\n useSummary?: boolean;\r\n /** Custom validation function called before native validation */\r\n customChecks?: (form: HTMLFormElement) => void;\r\n /** Always prevent default form submission */\r\n preventDefault?: boolean;\r\n /** Prevent default on validation failure (default: true) */\r\n preventDefaultOnFailed?: boolean;\r\n /** Callback invoked when form passes validation */\r\n submitCallback?: () => void;\r\n}\r\n\r\n/**\r\n * Form validation helper that integrates with HTML5 validation.\r\n * Supports error summaries, auto-validation, and custom submit handling.\r\n *\r\n * @example\r\n * // Prevent submission and handle manually\r\n * class MyComponent extends HTMLElement {\r\n * private validator: FormValidator;\r\n *\r\n * connectedCallback() {\r\n * const form = this.querySelector('form');\r\n * this.validator = new FormValidator(form, {\r\n * submitCallback: () => this.handleSubmit()\r\n * });\r\n * }\r\n *\r\n * private async handleSubmit() {\r\n * const data = readData(this.form);\r\n * await fetch('/api/save', { method: 'POST', body: JSON.stringify(data) });\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // With error summary display\r\n * const validator = new FormValidator(form, {\r\n * useSummary: true,\r\n * autoValidate: true\r\n * });\r\n */\r\nexport class FormValidator {\r\n private errorSummary: HTMLDivElement;\r\n\r\n constructor(\r\n private form: HTMLFormElement,\r\n private options?: ValidatorOptions\r\n ) {\r\n if (!this.form) {\r\n throw new Error('Form must be specified.');\r\n }\r\n\r\n this.form.addEventListener('submit', (event) => {\r\n if (\r\n options?.preventDefault ||\r\n this.options?.submitCallback != null\r\n ) {\r\n event.preventDefault();\r\n }\r\n if (this.options?.customChecks) {\r\n this.options.customChecks(form);\r\n }\r\n\r\n if (this.validateForm()) {\r\n this.options?.submitCallback?.apply(this);\r\n } else {\r\n if (options?.preventDefaultOnFailed !== false) {\r\n event.preventDefault();\r\n }\r\n }\r\n });\r\n\r\n if (options?.autoValidate) {\r\n form.addEventListener('input', (/*e: InputEvent*/) => {\r\n this.validateForm();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Validates all form fields.\r\n * Uses native HTML5 validation and optionally displays an error summary.\r\n *\r\n * @returns true if form is valid, false otherwise\r\n */\r\n public validateForm(): boolean {\r\n const formElements = Array.from(\r\n this.form.querySelectorAll('input,textarea,select')\r\n ) as (HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement)[];\r\n let isFormValid = true;\r\n\r\n if (this.options?.useSummary !== true) {\r\n if (this.form.checkValidity()) {\r\n return true;\r\n }\r\n\r\n this.form.reportValidity();\r\n this.focusFirstErrorElement();\r\n return false;\r\n }\r\n\r\n const errorMessages: string[] = [];\r\n\r\n formElements.forEach((element) => {\r\n if (!element.checkValidity()) {\r\n isFormValid = false;\r\n const fieldName =\r\n getFieldName.call(this, element) ||\r\n element.name ||\r\n 'Unnamed Field';\r\n errorMessages.push(\r\n `${fieldName}: ${element.validationMessage}`\r\n );\r\n }\r\n });\r\n\r\n if (!isFormValid) {\r\n this.displayErrorSummary(errorMessages);\r\n this.focusFirstErrorElement();\r\n } else {\r\n this.clearErrorSummary();\r\n }\r\n\r\n return isFormValid;\r\n }\r\n\r\n /**\r\n * Displays a list of error messages in the summary element.\r\n *\r\n * @param messages - Array of error messages to display\r\n */\r\n public displayErrorSummary(messages: string[]) {\r\n this.clearErrorSummary();\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n\r\n const errorList = this.errorSummary.querySelector('ul');\r\n messages.forEach((message) => {\r\n const listItem = document.createElement('li');\r\n listItem.textContent = message;\r\n errorList.appendChild(listItem);\r\n });\r\n }\r\n\r\n private createErrorSummary() {\r\n const errorSummary = document.createElement('div');\r\n errorSummary.className = 'error-summary';\r\n errorSummary.style.color = 'red';\r\n errorSummary.setAttribute('role', 'alert');\r\n errorSummary.setAttribute('aria-live', 'assertive');\r\n errorSummary.setAttribute('aria-atomic', 'true');\r\n this.errorSummary = errorSummary;\r\n\r\n const errorList = document.createElement('ul');\r\n this.errorSummary.appendChild(errorList);\r\n\r\n this.form.prepend(errorSummary);\r\n }\r\n /**\r\n * Adds a single error to the summary display.\r\n *\r\n * @param fieldName - The name of the field with the error\r\n * @param message - The error message\r\n */\r\n public addErrorToSummary(fieldName: string, message: string) {\r\n if (!this.errorSummary){\r\n this.createErrorSummary();\r\n }\r\n const errorList = this.errorSummary.querySelector('ul');\r\n const listItem = document.createElement('li');\r\n listItem.textContent = `${fieldName}: ${message}`;\r\n errorList.appendChild(listItem);\r\n }\r\n\r\n /**\r\n * Clears all errors from the summary display.\r\n */\r\n public clearErrorSummary() {\r\n if (this.errorSummary){\r\n this.errorSummary.querySelector('ul').innerHTML='';\r\n }\r\n }\r\n\r\n private focusFirstErrorElement() {\r\n const firstInvalidElement = this.form.querySelector(':invalid');\r\n if (\r\n firstInvalidElement instanceof HTMLElement &&\r\n document.activeElement !== firstInvalidElement\r\n ) {\r\n firstInvalidElement.focus();\r\n }\r\n }\r\n\r\n /**\r\n * Finds a form element relative to the given element.\r\n * Searches parent first, then direct children.\r\n *\r\n * @param element - The element to search from\r\n * @returns The found form element\r\n * @throws Error if no form is found\r\n *\r\n * @example\r\n * class MyComponent extends HTMLElement {\r\n * connectedCallback() {\r\n * const form = FormValidator.FindForm(this);\r\n * new FormValidator(form);\r\n * }\r\n * }\r\n */\r\n public static FindForm(element: HTMLElement): HTMLFormElement {\r\n if (element.parentElement?.tagName == 'FORM') {\r\n return <HTMLFormElement>element.parentElement;\r\n } else {\r\n for (let i = 0; i < element.children.length; i++) {\r\n const child = element.children[i];\r\n if (child.tagName == 'FORM') {\r\n return <HTMLFormElement>child;\r\n }\r\n }\r\n }\r\n\r\n throw new Error(\r\n 'Parent or a direct child must be a FORM for class ' +\r\n element.constructor.name\r\n );\r\n }\r\n}\r\n", "/**\r\n * @module icu\r\n * ICU message format support for internationalization.\r\n * Provides pluralization, select, and value interpolation.\r\n *\r\n * @example\r\n * // Simple interpolation\r\n * formatICU('Hello, {name}!', { name: 'World' });\r\n * // Returns: 'Hello, World!'\r\n *\r\n * @example\r\n * // Pluralization\r\n * formatICU('{count, plural, one {# item} other {# items}}', { count: 5 });\r\n * // Returns: '5 items'\r\n *\r\n * @example\r\n * // Select\r\n * formatICU('{gender, select, male {He} female {She} other {They}}', { gender: 'female' });\r\n * // Returns: 'She'\r\n */\r\n\r\nconst pluralRulesCache = new Map<string, Intl.PluralRules>();\r\n\r\n/**\r\n * Function type for message formatters.\r\n * Implement this to provide custom message formatting.\r\n */\r\nexport type MessageFormatter = (\r\n message: string,\r\n values?: Record<string, any>,\r\n locale?: string\r\n) => string;\r\n\r\n\r\nfunction getPluralRule(locale: string): Intl.PluralRules {\r\n if (!pluralRulesCache.has(locale)) {\r\n pluralRulesCache.set(locale, new Intl.PluralRules(locale));\r\n }\r\n return pluralRulesCache.get(locale)!;\r\n}\r\n\r\nfunction escapeRegex(s: string): string {\r\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n\r\n/**\r\n * Default ICU message formatter implementation.\r\n * Supports simple interpolation, pluralization with exact matches, and select.\r\n *\r\n * @param message - ICU format message string\r\n * @param values - Values to interpolate\r\n * @param locale - Locale for plural rules (default: 'en')\r\n * @returns Formatted message string\r\n *\r\n * @example\r\n * defaultFormatICU('{n, plural, =0 {none} one {# item} other {# items}}', { n: 0 }, 'en');\r\n * // Returns: 'none'\r\n *\r\n * @example\r\n * defaultFormatICU('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' });\r\n * // Returns: 'Full access'\r\n */\r\nexport function defaultFormatICU(\r\n message: string,\r\n values: Record<string, any>,\r\n locale: string = 'en'\r\n): string {\r\n return message.replace(\r\n /\\{(\\w+)(?:, (plural|select),((?:[^{}]*\\{[^{}]*\\})+))?\\}/g,\r\n (_, key, type, categoriesPart) => {\r\n const value = values[key];\r\n\r\n if (type === 'plural') {\r\n const exact = new RegExp(\r\n `=${escapeRegex(String(value))}\\\\s*\\\\{([^{}]*)\\\\}`\r\n ).exec(categoriesPart);\r\n if (exact) {\r\n return exact[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n\r\n const rules = getPluralRule(locale);\r\n const category = rules.select(value);\r\n const match =\r\n new RegExp(`${category}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`other\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n if (match) {\r\n return match[1]\r\n .replace(`{${key}}`, String(value))\r\n .replace('#', String(value));\r\n }\r\n return String(value);\r\n }\r\n\r\n if (type === 'select') {\r\n const escaped = escapeRegex(String(value));\r\n const match =\r\n new RegExp(`\\\\b${escaped}\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart) ||\r\n new RegExp(`\\\\bother\\\\s*\\\\{([^{}]*)\\\\}`).exec(categoriesPart);\r\n return match ? match[1] : String(value);\r\n }\r\n\r\n return value !== undefined ? String(value) : `{${key}}`;\r\n },\r\n );\r\n}\r\n\r\n/**\r\n * The active message formatter. Defaults to `defaultFormatICU`.\r\n * Can be replaced with `setMessageFormatter` for custom formatting.\r\n */\r\nexport let formatICU: MessageFormatter = defaultFormatICU;\r\n\r\n/**\r\n * Replaces the default message formatter with a custom implementation.\r\n * Use this to integrate with external i18n libraries like FormatJS.\r\n *\r\n * @param formatter - The custom formatter function\r\n *\r\n * @example\r\n * // Use FormatJS IntlMessageFormat\r\n * import { IntlMessageFormat } from 'intl-messageformat';\r\n *\r\n * setMessageFormatter((message, values, locale) => {\r\n * const fmt = new IntlMessageFormat(message, locale);\r\n * return fmt.format(values);\r\n * });\r\n */\r\nexport function setMessageFormatter(formatter: MessageFormatter) {\r\n formatICU = formatter;\r\n}", "/**\r\n * @module i18n\r\n * Internationalization support with namespace-based translations.\r\n * Uses ICU message format for pluralization, select, and formatting.\r\n *\r\n * @example\r\n * // Initialize locale\r\n * await setLocale('sv');\r\n *\r\n * // Use translations\r\n * const greeting = t('r-common:greeting', { name: 'John' });\r\n * const items = t('shop:items', { count: 5 });\r\n */\r\n\r\nimport { formatICU } from './icu';\r\n\r\ntype Locale = string;\r\ntype Namespace = string;\r\ntype TranslationMap = Record<string, string>;\r\ntype Translations = Record<Namespace, TranslationMap>;\r\n\r\nexport type MissingTranslationHandler = (\r\n key: string,\r\n namespace: string,\r\n locale: string,\r\n) => void;\r\n\r\n/**\r\n * Dispatched on `document` after `setLocale()` completes.\r\n * The `locale` property contains the new normalized locale code.\r\n *\r\n * @example\r\n * document.addEventListener('localechange', (e) => {\r\n * console.log(`Locale changed to ${e.locale}`);\r\n * this.render();\r\n * });\r\n */\r\nexport class LocaleChangeEvent extends Event {\r\n readonly locale: string;\r\n constructor(locale: string) {\r\n super('localechange', { bubbles: false });\r\n this.locale = locale;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface DocumentEventMap {\r\n localechange: LocaleChangeEvent;\r\n }\r\n}\r\n\r\nconst fallbackLocale: Locale = 'en';\r\nlet currentLocale: Locale = fallbackLocale;\r\nconst loadedNamespaces = new Set<Namespace>();\r\nconst translations: Translations = {};\r\nlet missingHandler: MissingTranslationHandler | null = null;\r\n\r\nfunction normalizeLocale(locale: string): string {\r\n return locale.toLowerCase().split('-')[0];\r\n}\r\n\r\n/**\r\n * Sets the current locale and loads the common namespace.\r\n * Clears previously loaded translations and dispatches a `localechange` event.\r\n *\r\n * @param locale - The locale code (e.g., 'en', 'sv', 'en-US')\r\n *\r\n * @example\r\n * await setLocale('sv');\r\n */\r\nexport async function setLocale(locale: string): Promise<void> {\r\n const normalized = normalizeLocale(locale);\r\n currentLocale = normalized;\r\n loadedNamespaces.clear();\r\n Object.keys(translations).forEach(ns => delete translations[ns]);\r\n await loadNamespace('r-common');\r\n if (typeof document !== 'undefined') {\r\n document.dispatchEvent(new LocaleChangeEvent(normalized));\r\n }\r\n}\r\n\r\n/**\r\n * Loads a translation namespace on demand.\r\n * Falls back to the default locale if translations are not found.\r\n *\r\n * @param namespace - The namespace to load (e.g., 'shop', 'errors')\r\n *\r\n * @example\r\n * await loadNamespace('shop');\r\n * const price = t('shop:priceLabel');\r\n */\r\nexport async function loadNamespace(namespace: Namespace): Promise<void> {\r\n if (loadedNamespaces.has(namespace)) return;\r\n\r\n try {\r\n const module = await import(`./locales/${currentLocale}/${namespace}.json`);\r\n translations[namespace] = module.default;\r\n loadedNamespaces.add(namespace);\r\n } catch (err) {\r\n if (currentLocale !== fallbackLocale) {\r\n const fallback = await import(`./locales/${fallbackLocale}/${namespace}.json`);\r\n translations[namespace] = fallback.default;\r\n loadedNamespaces.add(namespace);\r\n } else {\r\n console.warn(`i18n: Failed to load namespace '${namespace}' for locale '${currentLocale}'`);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Loads multiple translation namespaces in parallel.\r\n *\r\n * @param namespaces - Array of namespace names to load\r\n *\r\n * @example\r\n * await loadNamespaces(['r-pipes', 'r-validation']);\r\n */\r\nexport async function loadNamespaces(namespaces: Namespace[]): Promise<void> {\r\n await Promise.all(namespaces.map(ns => loadNamespace(ns)));\r\n}\r\n\r\n/**\r\n * Translates a key with optional value interpolation.\r\n * Supports ICU message format for pluralization and select.\r\n *\r\n * @param fullKey - Translation key in format 'namespace:key' or just 'key' (uses 'r-common')\r\n * @param values - Values to interpolate into the message\r\n * @returns The translated string, or the key if not found\r\n *\r\n * @example\r\n * // Simple translation\r\n * t('greeting'); // Uses r-common:greeting\r\n *\r\n * // With namespace\r\n * t('errors:notFound');\r\n *\r\n * // With interpolation\r\n * t('welcome', { name: 'John' }); // \"Welcome, John!\"\r\n *\r\n * // With pluralization (ICU format)\r\n * t('items', { count: 5 }); // \"5 items\" or \"5 f\u00F6rem\u00E5l\"\r\n */\r\nexport function t(fullKey: string, values?: Record<string, any>): string {\r\n const [namespace, key] = fullKey.includes(':')\r\n ? fullKey.split(':')\r\n : ['r-common', fullKey];\r\n const message = translations[namespace]?.[key];\r\n if (!message) {\r\n if (missingHandler) missingHandler(key, namespace, currentLocale);\r\n return fullKey;\r\n }\r\n try {\r\n return formatICU(message, values, currentLocale) as string;\r\n } catch {\r\n return fullKey;\r\n }\r\n}\r\n\r\n/**\r\n * Returns the current locale code.\r\n *\r\n * @returns The normalized locale code (e.g., 'en', 'sv')\r\n */\r\nexport function getCurrentLocale(): string {\r\n return currentLocale;\r\n}\r\n\r\n/**\r\n * Registers a handler called when `t()` encounters a missing translation key.\r\n * Pass `null` to remove the handler.\r\n *\r\n * @param handler - Callback receiving the key, namespace, and locale\r\n *\r\n * @example\r\n * onMissingTranslation((key, ns, locale) => {\r\n * console.warn(`Missing: ${ns}:${key} [${locale}]`);\r\n * });\r\n */\r\nexport function onMissingTranslation(handler: MissingTranslationHandler | null): void {\r\n missingHandler = handler;\r\n}\r\n", "/**\r\n * @module FormReader\r\n * Utilities for reading form data into typed objects.\r\n * Handles type conversion based on input types and data-type attributes.\r\n *\r\n * @example\r\n * // Basic form reading\r\n * const form = document.querySelector('form');\r\n * const data = readData(form);\r\n *\r\n * // Type-safe mapping to a class instance\r\n * const user = mapFormToClass(form, new UserDTO());\r\n */\r\n\r\nimport { getCurrentLocale } from '../i18n/i18n';\r\n\r\n/**\r\n * Maps form field values to a class instance's properties.\r\n * Automatically converts values based on input types (checkbox, number, date).\r\n *\r\n * Form field names must match property names on the target instance.\r\n *\r\n * @template T - The type of the class instance\r\n * @param form - The HTML form element to read from\r\n * @param instance - The class instance to populate\r\n * @param options - Configuration options\r\n * @param options.throwOnMissingProperty - Throw if form field has no matching property\r\n * @param options.throwOnMissingField - Throw if class property has no matching form field\r\n * @returns The populated instance\r\n *\r\n * @example\r\n * class UserDTO {\r\n * name: string = '';\r\n * email: string = '';\r\n * age: number = 0;\r\n * newsletter: boolean = false;\r\n * }\r\n *\r\n * const form = document.querySelector('form');\r\n * const user = mapFormToClass(form, new UserDTO());\r\n * console.log(user.name, user.age, user.newsletter);\r\n *\r\n * @example\r\n * // With validation\r\n * const user = mapFormToClass(form, new UserDTO(), {\r\n * throwOnMissingProperty: true, // Catch typos in form field names\r\n * throwOnMissingField: true // Ensure all DTO fields are in form\r\n * });\r\n */\r\nexport function mapFormToClass<T extends object>(\r\n form: HTMLFormElement,\r\n instance: T,\r\n options: {\r\n throwOnMissingProperty?: boolean;\r\n throwOnMissingField?: boolean;\r\n } = {}\r\n): T {\r\n const formElements = form.querySelectorAll('input, select, textarea');\r\n\r\n formElements.forEach((element) => {\r\n if (!element.hasAttribute('name')) return;\r\n if (booleanAttr(element, 'disabled')) return;\r\n\r\n const propertyName = element.getAttribute('name')!;\r\n\r\n if (!(propertyName in instance)) {\r\n if (options.throwOnMissingProperty) {\r\n throw new Error(\r\n `Form field \"${propertyName}\" has no matching property in class instance`\r\n );\r\n }\r\n return;\r\n }\r\n\r\n const value = readElementValue(element);\r\n if (value === SKIP) return;\r\n\r\n (instance as Record<string, unknown>)[propertyName] = value;\r\n });\r\n\r\n if (options.throwOnMissingField) {\r\n const formFieldNames = new Set<string>();\r\n formElements.forEach((element) => {\r\n if (element.hasAttribute('name')) {\r\n formFieldNames.add(element.getAttribute('name')!);\r\n }\r\n });\r\n\r\n for (const prop in instance) {\r\n if (\r\n typeof instance[prop] !== 'function' &&\r\n Object.prototype.hasOwnProperty.call(instance, prop) &&\r\n !formFieldNames.has(prop)\r\n ) {\r\n throw new Error(\r\n `Class property \"${prop}\" has no matching form field`\r\n );\r\n }\r\n }\r\n }\r\n\r\n return instance;\r\n}\r\n\r\n/**\r\n * Configuration options for form reading operations.\r\n */\r\nexport interface FormReaderOptions {\r\n /** Prefix to strip from field names when mapping to properties */\r\n prefix?: string;\r\n /** If true, checkboxes return their value instead of true/false */\r\n disableBinaryCheckbox?: boolean;\r\n /** If true, radio buttons return their value instead of true/false */\r\n disableBinaryRadioButton?: boolean;\r\n}\r\n\r\n/**\r\n * Gets the appropriate type converter function for a form element.\r\n * Uses the `data-type` attribute if present, otherwise infers from input type.\r\n *\r\n * @param element - The form element to get a converter for\r\n * @returns A function that converts string values to the appropriate type\r\n *\r\n * @example\r\n * // With data-type attribute\r\n * <input name=\"age\" data-type=\"number\" />\r\n * const converter = getDataConverter(input);\r\n * converter('42'); // Returns: 42 (number)\r\n *\r\n * @example\r\n * // Inferred from input type\r\n * <input type=\"checkbox\" name=\"active\" />\r\n * const converter = getDataConverter(checkbox);\r\n * converter('true'); // Returns: true (boolean)\r\n */\r\nexport function getDataConverter(element: HTMLElement): ConverterFunc {\r\n const dataType = element.getAttribute('data-type') as DataType | null;\r\n if (dataType) {\r\n return createConverterFromDataType(dataType);\r\n }\r\n\r\n if (element instanceof HTMLInputElement) {\r\n return createConverterFromInputType(element.type as InputType);\r\n }\r\n\r\n // Handle custom form-associated elements with checked property (boolean values)\r\n if ('checked' in element && typeof (element as any).checked === 'boolean') {\r\n return BooleanConverter as ConverterFunc;\r\n }\r\n\r\n return (str) => str;\r\n}\r\n\r\n\r\n/**\r\n * Reads all form data into a plain object with automatic type conversion.\r\n * Handles multiple values (e.g., multi-select) and custom form-associated elements.\r\n *\r\n * Type conversion is based on:\r\n * 1. `data-type` attribute if present (number, boolean, string, Date)\r\n * 2. Input type (checkbox, number, date, etc.)\r\n * 3. Falls back to string\r\n *\r\n * @param form - The HTML form element to read\r\n * @returns Object with property names matching field names\r\n *\r\n * @example\r\n * // HTML form\r\n * <form>\r\n * <input name=\"username\" value=\"john\" />\r\n * <input name=\"age\" type=\"number\" value=\"25\" />\r\n * <input name=\"active\" type=\"checkbox\" checked />\r\n * <select name=\"colors\" multiple>\r\n * <option value=\"red\" selected>Red</option>\r\n * <option value=\"blue\" selected>Blue</option>\r\n * </select>\r\n * </form>\r\n *\r\n * // Reading the form\r\n * const data = readData(form);\r\n * // Returns: { username: 'john', age: 25, active: true, colors: ['red', 'blue'] }\r\n *\r\n * @example\r\n * // With custom form elements\r\n * <form>\r\n * <r-input name=\"email\" value=\"test@example.com\" />\r\n * <r-checkbox name=\"terms\" checked />\r\n * </form>\r\n * const data = readData(form);\r\n 1*/\r\nexport function readData<T = Record<string, unknown>>(form: HTMLFormElement): T{\r\n const data: Record<string, unknown> = {};\r\n const formData = new FormData(form);\r\n const seen = new Set<string>();\r\n\r\n formData.forEach((_, name) => {\r\n if (seen.has(name)) return;\r\n seen.add(name);\r\n\r\n const values = formData.getAll(name);\r\n const element = form.elements.namedItem(name);\r\n const converter = element ? getDataConverter(element as HTMLElement) : (v: string) => v;\r\n\r\n if (values.length === 1) {\r\n const v = values[0];\r\n data[name] = typeof v === 'string' ? converter(v) : v;\r\n } else {\r\n data[name] = values.map(v => typeof v === 'string' ? converter(v) : v);\r\n }\r\n });\r\n\r\n for (let i = 0; i < form.elements.length; i++) {\r\n const el = form.elements[i] as HTMLInputElement;\r\n if (el.type === 'checkbox' && el.name && !seen.has(el.name)) {\r\n seen.add(el.name);\r\n data[el.name] = false;\r\n }\r\n }\r\n\r\n return data as T;\r\n}\r\n\r\n/**\r\n * Function type for converting string form values to typed values.\r\n */\r\nexport type ConverterFunc = (value: string) => unknown;\r\n\r\n/**\r\n * Supported data-type attribute values for explicit type conversion.\r\n */\r\nexport type DataType = 'number' | 'boolean' | 'string' | 'Date';\r\n\r\n/**\r\n * Supported HTML input types for automatic type inference.\r\n */\r\nexport type InputType =\r\n | 'tel'\r\n | 'text'\r\n | 'checkbox'\r\n | 'radio'\r\n | 'number'\r\n | 'color'\r\n | 'date'\r\n | 'datetime-local'\r\n | 'month'\r\n | 'week'\r\n | 'time';\r\n\r\n/**\r\n * Converts string values to booleans.\r\n * Handles 'true'/'false' strings and numeric values (>0 is true).\r\n *\r\n * @param value - String value to convert\r\n * @returns Boolean value or undefined if empty\r\n * @throws Error if value cannot be interpreted as boolean\r\n */\r\nexport function BooleanConverter(value?: string): boolean | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n\r\n const lower = value.toLowerCase();\r\n\r\n if (lower === 'true' || lower === 'on' || Number(value) > 0) {\r\n return true;\r\n }\r\n\r\n if (lower === 'false' || lower === 'off' || Number(value) <= 0) {\r\n return false;\r\n }\r\n\r\n throw new Error(\"Could not convert value '\" + value + \"' to boolean.\");\r\n}\r\n\r\n/**\r\n * Converts string values to numbers.\r\n *\r\n * @param value - String value to convert\r\n * @returns Number value or undefined if empty\r\n * @throws Error if value is not a valid number\r\n */\r\nexport function NumberConverter(value?: string): number | undefined {\r\n if (!value || value == '') {\r\n return undefined;\r\n }\r\n const nr = Number(value);\r\n if (!isNaN(nr)) {\r\n return nr;\r\n }\r\n throw new Error(\"Could not convert value '\" + value + \"' to number.\");\r\n}\r\n\r\n/**\r\n * Detects the order of day/month/year parts for a given locale\r\n * using `Intl.DateTimeFormat.formatToParts`.\r\n *\r\n * @example\r\n * getLocaleDateOrder('en-US') // ['month', 'day', 'year']\r\n * getLocaleDateOrder('sv') // ['year', 'month', 'day']\r\n * getLocaleDateOrder('de') // ['day', 'month', 'year']\r\n */\r\nfunction getLocaleDateOrder(locale: string): ('day' | 'month' | 'year')[] {\r\n const parts = new Intl.DateTimeFormat(locale).formatToParts(new Date(2024, 0, 15));\r\n return parts\r\n .filter((p): p is Intl.DateTimeFormatPart & { type: 'day' | 'month' | 'year' } =>\r\n p.type === 'day' || p.type === 'month' || p.type === 'year')\r\n .map(p => p.type);\r\n}\r\n\r\n/**\r\n * Converts string values to Date objects.\r\n * Supports both ISO format (`2024-01-15`) and locale-specific formats\r\n * (`01/15/2024` for en-US, `15.01.2024` for de, etc.) based on the\r\n * current i18n locale.\r\n *\r\n * @param value - Date string in ISO or locale format\r\n * @returns Date object\r\n * @throws Error if value is not a valid date\r\n *\r\n * @example\r\n * // ISO format (from <input type=\"date\">)\r\n * DateConverter('2024-01-15') // Date(2024, 0, 15)\r\n *\r\n * // Locale format (from <input type=\"text\" data-type=\"Date\">)\r\n * // with locale set to 'sv': 2024-01-15\r\n * // with locale set to 'en-US': 01/15/2024\r\n * // with locale set to 'de': 15.01.2024\r\n */\r\nexport function DateConverter(value: string): Date | undefined {\r\n if (!value || value === '') return undefined;\r\n\r\n if (/^\\d{4}-\\d{2}-\\d{2}(T|$)/.test(value)) {\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n\r\n const numericParts = value.split(/[\\/.\\-\\s]/);\r\n if (numericParts.length >= 3 && numericParts.every(p => /^\\d+$/.test(p))) {\r\n const locale = getCurrentLocale();\r\n const order = getLocaleDateOrder(locale);\r\n const mapped: Record<string, number> = {};\r\n order.forEach((type, i) => {\r\n mapped[type] = parseInt(numericParts[i], 10);\r\n });\r\n\r\n if (mapped.year !== undefined && mapped.month !== undefined && mapped.day !== undefined) {\r\n if (mapped.year < 100) mapped.year += 2000;\r\n const date = new Date(mapped.year, mapped.month - 1, mapped.day);\r\n if (!isNaN(date.getTime())) return date;\r\n }\r\n }\r\n\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) {\r\n throw new Error('Invalid date format');\r\n }\r\n return date;\r\n}\r\n\r\n/**\r\n * Creates a converter function based on the data-type attribute value.\r\n *\r\n * @param dataType - The data-type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromDataType(dataType: DataType): ConverterFunc {\r\n switch (dataType) {\r\n case 'boolean':\r\n return BooleanConverter as ConverterFunc;\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n case 'Date':\r\n return DateConverter;\r\n case 'string':\r\n return (value) => (!value || value == '' ? undefined : value);\r\n default:\r\n throw new Error(`Unknown data-type \"${dataType}\".`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a converter function based on HTML input type.\r\n * Handles special types like checkbox, date, time, week, and month.\r\n *\r\n * @param inputType - The HTML input type attribute value\r\n * @returns Appropriate converter function for the type\r\n */\r\nexport function createConverterFromInputType(inputType: InputType): ConverterFunc {\r\n switch (inputType) {\r\n case 'checkbox':\r\n return BooleanConverter as ConverterFunc;\r\n\r\n case 'number':\r\n return NumberConverter as ConverterFunc;\r\n\r\n case 'date':\r\n case 'datetime-local':\r\n return DateConverter;\r\n\r\n case 'month':\r\n return (value) => {\r\n const [year, month] = value.split('-').map(Number);\r\n return new Date(year, month - 1);\r\n };\r\n\r\n case 'week':\r\n return (value) => {\r\n const [year, week] = value.split('-W').map(Number);\r\n return { year, week };\r\n };\r\n\r\n case 'time':\r\n return (value) => {\r\n const [hours, minutes, seconds = 0] = value.split(':').map(Number);\r\n return { hours, minutes, seconds };\r\n };\r\n\r\n default:\r\n return (value) => (!value || value == '' ? undefined : value);\r\n }\r\n}\r\n\r\nfunction booleanAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n}\r\n\r\nconst SKIP = Symbol('skip');\r\n\r\nfunction readElementValue(element: Element): unknown {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n return booleanAttr(element, 'checked');\r\n }\r\n\r\n if (type === 'radio') {\r\n if (!booleanAttr(element, 'checked')) return SKIP;\r\n return el.value;\r\n }\r\n\r\n if (type === 'number') {\r\n return el.value ? Number(el.value) : null;\r\n }\r\n\r\n if (type === 'date') {\r\n return el.value ? new Date(el.value) : null;\r\n }\r\n\r\n if ('selectedOptions' in el && booleanAttr(element, 'multiple')) {\r\n return Array.from(el.selectedOptions as NodeListOf<HTMLOptionElement>)\r\n .map((o: HTMLOptionElement) => o.value);\r\n }\r\n\r\n if ('value' in el) {\r\n return el.value;\r\n }\r\n\r\n return undefined;\r\n}", "/**\r\n * @module ValidationRules\r\n * Form validation rules for use with FormValidator.\r\n * Provides declarative validation through decorators.\r\n *\r\n * Validation messages use the i18n system. Load the 'r-validation' namespace\r\n * for localized error messages:\r\n *\r\n * @example\r\n * await loadNamespace('r-validation');\r\n *\r\n * @example\r\n * // In HTML, use validation attributes\r\n * <input name=\"age\" data-validate=\"required range(0-120)\" />\r\n */\r\n\r\nimport { t } from '../i18n/i18n';\r\n\r\n/**\r\n * Context provided to validators during validation.\r\n */\r\nexport interface ValidationContext {\r\n /** The HTML input type (text, number, email, etc.) */\r\n inputType: string;\r\n /** The data-type attribute value if present */\r\n dataType?: string;\r\n /** Adds an error message to the validation result */\r\n addError(message: string): void;\r\n}\r\n\r\n/**\r\n * Interface for custom validators.\r\n */\r\ninterface Validator {\r\n /**\r\n * Validates the given value.\r\n * @param value - The string value to validate\r\n * @param context - Validation context with type info and error reporting\r\n */\r\n validate(value: string, context: ValidationContext): void;\r\n}\r\n\r\ninterface ValidatorRegistryEntry {\r\n validator: { new (): Validator };\r\n validInputTypes: string[];\r\n}\r\n\r\nconst validators: Map<string, ValidatorRegistryEntry> = new Map();\r\n\r\n/**\r\n * Decorator to register a validator class for a specific validation name.\r\n *\r\n * @param validationName - The name used in data-validate attribute\r\n * @param validInputTypes - Optional list of input types this validator applies to\r\n *\r\n * @example\r\n * @RegisterValidator('email')\r\n * class EmailValidation implements Validator {\r\n * validate(value: string, context: ValidationContext) {\r\n * if (!value.includes('@')) {\r\n * context.addError('Invalid email address');\r\n * }\r\n * }\r\n * }\r\n */\r\nexport function RegisterValidator(validationName: string, validInputTypes: string[] = []) {\r\n return function (target: { new (...args: unknown[]): Validator }) {\r\n validators.set(validationName, { validator: target, validInputTypes });\r\n };\r\n}\r\n\r\n/**\r\n * Looks up a registered validator by name.\r\n *\r\n * @param name - The validator name used in `data-validate`\r\n * @returns The registry entry, or `undefined` if not found\r\n */\r\nexport function getValidator(name: string): ValidatorRegistryEntry | undefined {\r\n return validators.get(name);\r\n}\r\n\r\n/**\r\n * Validates that a field has a non-empty value.\r\n * Use with `data-validate=\"required\"`.\r\n */\r\n@RegisterValidator('required')\r\nexport class RequiredValidation implements Validator {\r\n static create(rule: string): RequiredValidation | null {\r\n return rule === 'required' ? new RequiredValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() !== ''){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:required');\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a numeric value falls within a specified range.\r\n * Use with `data-validate=\"range(min-max)\"`.\r\n *\r\n * @example\r\n * <input name=\"age\" type=\"number\" data-validate=\"range(0-120)\" />\r\n */\r\n@RegisterValidator('range', ['number'])\r\nexport class RangeValidation implements Validator {\r\n min: number;\r\n max: number;\r\n\r\n constructor(min: number, max: number) {\r\n this.min = min;\r\n this.max = max;\r\n }\r\n\r\n static create(rule: string): RangeValidation | null {\r\n const rangeMatch = rule.match(/^range\\((-?\\d+(?:\\.\\d+)?)-(-?\\d+(?:\\.\\d+)?)\\)$/);\r\n if (rangeMatch) {\r\n const [, min, max] = rangeMatch;\r\n return new RangeValidation(parseFloat(min), parseFloat(max));\r\n }\r\n return null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (value.trim() === '') return;\r\n\r\n const num = parseFloat(value);\r\n if (!isNaN(num) && num >= this.min && num <= this.max){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage(value));\r\n }\r\n\r\n getMessage(actual: string): string {\r\n return t('r-validation:range', { min: this.min, max: this.max, actual });\r\n }\r\n}\r\n\r\n/**\r\n * Validates that a value contains only numeric digits (0-9).\r\n * Use with `data-validate=\"digits\"`.\r\n */\r\n@RegisterValidator('digits', ['number'])\r\nexport class DigitsValidation implements Validator {\r\n static create(rule: string): DigitsValidation | null {\r\n return rule === 'digits' ? new DigitsValidation() : null;\r\n }\r\n\r\n validate(value: string, context: ValidationContext) {\r\n if (/^\\d+$/.test(value)){\r\n return;\r\n }\r\n\r\n context.addError(this.getMessage());\r\n }\r\n\r\n getMessage(): string {\r\n return t('r-validation:digits');\r\n }\r\n}\r\n", "/**\r\n * Sets form field values from a data object using the name attribute.\r\n * Supports dot notation for accessing nested properties and array handling.\r\n * \r\n * @param form - The HTML form element to populate\r\n * @param data - The data object containing values to set in the form\r\n * \r\n * @example\r\n * // Basic usage with flat object\r\n * const form = document.querySelector('form');\r\n * const data = { name: 'John', email: 'john@example.com' };\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with nested objects via dot notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * user: { \r\n * name: 'John', \r\n * contact: { \r\n * email: 'john@example.com' \r\n * } \r\n * } \r\n * };\r\n * // Form has fields with names like \"user.name\" and \"user.contact.email\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with simple arrays using [] notation\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * hobbies: ['Reading', 'Cycling', 'Cooking']\r\n * };\r\n * // Form has multiple fields with names like \"hobbies[]\"\r\n * setFormData(form, data);\r\n * \r\n * @example\r\n * // Using with array of objects using numeric indexers\r\n * const form = document.querySelector('form');\r\n * const data = { \r\n * users: [\r\n * { name: 'John', email: 'john@example.com' },\r\n * { name: 'Jane', email: 'jane@example.com' }\r\n * ]\r\n * };\r\n * // Form has fields with names like \"users[0].name\", \"users[1].email\", etc.\r\n * setFormData(form, data);\r\n */\r\nexport function setFormData(form: HTMLFormElement, data: object): void {\r\n const formElements = form.querySelectorAll('[name]');\r\n\r\n formElements.forEach(element => {\r\n\r\n const name = element.getAttribute('name');\r\n if (!name) return;\r\n\r\n // Handle simple array notation (e.g., hobbies[])\r\n if (name.endsWith('[]')) {\r\n const arrayName = name.slice(0, -2);\r\n const arrayValue = getValueByComplexPath(data, arrayName);\r\n\r\n if (Array.isArray(arrayValue)) {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox' || type === 'radio') {\r\n el.checked = arrayValue.includes(el.value);\r\n } else if ('options' in el && boolAttr(element, 'multiple')) {\r\n arrayValue.forEach(val => {\r\n const option = Array.from(el.options as HTMLOptionElement[])\r\n .find((opt: HTMLOptionElement) => opt.value === String(val));\r\n if (option) (option as HTMLOptionElement).selected = true;\r\n });\r\n } else if ('value' in el) {\r\n const allWithName = form.querySelectorAll(`[name=\"${name}\"]`);\r\n const idx = Array.from(allWithName).indexOf(element);\r\n if (idx >= 0 && idx < arrayValue.length) {\r\n el.value = String(arrayValue[idx]);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n // Handle complex paths with array indexers and dot notation\r\n const value = getValueByComplexPath(data, name);\r\n if (value === undefined || value === null) return;\r\n\r\n setElementValue(element, value);\r\n });\r\n }\r\n \r\n function getValueByComplexPath(obj: object, path: string): any {\r\n // Handle array indexers like users[0].name\r\n const segments = [];\r\n let currentSegment = '';\r\n let inBrackets = false;\r\n \r\n for (let i = 0; i < path.length; i++) {\r\n const char = path[i];\r\n \r\n if (char === '[' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n inBrackets = true;\r\n currentSegment += char;\r\n } else if (char === ']' && inBrackets) {\r\n currentSegment += char;\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n inBrackets = false;\r\n } else if (char === '.' && !inBrackets) {\r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n currentSegment = '';\r\n }\r\n } else {\r\n currentSegment += char;\r\n }\r\n }\r\n \r\n if (currentSegment) {\r\n segments.push(currentSegment);\r\n }\r\n \r\n return segments.reduce((result, segment) => {\r\n if (!result || typeof result !== 'object') return undefined;\r\n \r\n // Handle array indexer segments like [0]\r\n if (segment.startsWith('[') && segment.endsWith(']')) {\r\n const index = segment.slice(1, -1);\r\n return result[index];\r\n }\r\n \r\n return result[segment];\r\n }, obj);\r\n }\r\n \r\n function getValueByPath(obj: object, path: string): any {\r\n return path.split('.').reduce((o, key) => {\r\n return o && typeof o === 'object' ? o[key] : undefined;\r\n }, obj);\r\n }\r\n \r\n function setElementValue(element: Element, value: any): void {\r\n const el = element as Record<string, any>;\r\n const type = el.type || element.getAttribute('type') || '';\r\n\r\n if (type === 'checkbox') {\r\n el.checked = Boolean(value);\r\n } else if (type === 'radio') {\r\n el.checked = el.value === String(value);\r\n } else if (type === 'date' && value instanceof Date) {\r\n el.value = value.toISOString().split('T')[0];\r\n } else if (type === 'datetime-local' && value instanceof Date) {\r\n const pad = (n: number) => String(n).padStart(2, '0');\r\n el.value = `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;\r\n } else if ('options' in el && boolAttr(element, 'multiple') && Array.isArray(value)) {\r\n const options = Array.from(el.options as HTMLOptionElement[]);\r\n const vals = value.map(String);\r\n options.forEach((opt: HTMLOptionElement) => {\r\n opt.selected = vals.includes(opt.value);\r\n });\r\n } else if ('value' in el) {\r\n el.value = String(value);\r\n }\r\n }\r\n\r\n function boolAttr(element: Element, name: string): boolean {\r\n const el = element as Record<string, any>;\r\n if (name in el && typeof el[name] === 'boolean') return el[name];\r\n const attr = element.getAttribute(name);\r\n if (attr === null) return false;\r\n if (attr === '' || attr.toLowerCase() === 'true' || attr.toLowerCase() === name) return true;\r\n return false;\r\n }", "/**\r\n * @module pipes\r\n * Data transformation functions (pipes) for use in template expressions.\r\n * Pipes transform values for display, like formatting dates, currencies, or text.\r\n *\r\n * Locale-aware pipes (currency, date, daysAgo, pieces) use the i18n system\r\n * for formatting and translations. Call `setLocale()` before using these pipes.\r\n *\r\n * Pipes can be chained in templates: `{{value | uppercase | shorten:20}}`\r\n *\r\n * @example\r\n * // In templates\r\n * <span>{{user.name | uppercase}}</span>\r\n * <span>{{price | currency}}</span>\r\n * <span>{{createdAt | daysAgo}}</span>\r\n *\r\n * @example\r\n * // Programmatic usage\r\n * import { applyPipes, defaultPipes } from 'relaxjs';\r\n * const result = applyPipes('hello world', ['uppercase', 'shorten:8']);\r\n * // Returns: 'HELLO...'\r\n */\r\n\r\nimport { getCurrentLocale, t } from './i18n/i18n';\r\n\r\n/**\r\n * Type definition for pipe transformation functions.\r\n * Pipes take a value and optional arguments, returning a transformed value.\r\n *\r\n * @example\r\n * // Define a custom pipe\r\n * const reversePipe: PipeFunction = (value: string) => {\r\n * return value.split('').reverse().join('');\r\n * };\r\n */\r\nexport type PipeFunction = (value: any, ...args: any[]) => any;\r\n\r\n\r\n// =============================== Text manipulation pipes ===========================\r\n\r\n\r\n\r\n/**\r\n * Converts a string to uppercase\r\n * @param value The string to convert\r\n * @returns The uppercase string\r\n */\r\nexport function uppercasePipe(value: string): string {\r\n return String(value).toUpperCase();\r\n}\r\n\r\n/**\r\n * Converts a string to uppercase\r\n * @param value The string to convert\r\n * @returns The uppercase string\r\n */\r\nexport function trimPipe(value: string): string {\r\n return String(value).trimEnd().trimStart();\r\n}\r\n\r\n\r\n/**\r\n * Converts a string to lowercase\r\n * @param value The string to convert\r\n * @returns The lowercase string\r\n */\r\nexport function lowercasePipe(value: string): string {\r\n return String(value).toLowerCase();\r\n}\r\n\r\n/**\r\n * Capitalizes the first character of a string\r\n * @param value The string to capitalize\r\n * @returns The capitalized string\r\n */\r\nexport function capitalizePipe(value: string): string {\r\n const str = String(value);\r\n return str.charAt(0).toUpperCase() + str.slice(1);\r\n}\r\n\r\n/**\r\n * Shortens a string to a specified length and adds ellipsis.\r\n * @param value The string to shorten\r\n * @param length Maximum length including ellipsis\r\n * @returns The shortened string with ellipsis if needed\r\n */\r\nexport function shortenPipe(value: string, length: string): string {\r\n const str = String(value);\r\n const maxLength = parseInt(length, 10);\r\n return str.length > maxLength\r\n ? str.substring(0, maxLength - 3) + '...'\r\n : str;\r\n}\r\n\r\n// Formatting pipes\r\n/**\r\n * Formats a number as currency using the current locale.\r\n * Uses the i18n system's current locale for formatting.\r\n *\r\n * @param value The number to format\r\n * @param currency Currency code (defaults to USD)\r\n * @returns Formatted currency string\r\n *\r\n * @example\r\n * // In template: {{price | currency}} or {{price | currency:EUR}}\r\n * currencyPipe(1234.56); // \"$1,234.56\" (en) or \"1 234,56 $\" (sv)\r\n * currencyPipe(1234.56, 'SEK'); // \"SEK 1,234.56\" (en) or \"1 234,56 kr\" (sv)\r\n */\r\nexport function currencyPipe(value: number, currency: string = 'USD'): string {\r\n const locale = getCurrentLocale();\r\n return new Intl.NumberFormat(locale, {\r\n style: 'currency',\r\n currency\r\n }).format(value);\r\n}\r\n\r\n/**\r\n * Formats a date value according to the specified format.\r\n * Uses the i18n system's current locale for formatting.\r\n *\r\n * @param value Date value (string, number, or Date object)\r\n * @param format Format type: 'short', 'long', or default (ISO)\r\n * @returns Formatted date string\r\n *\r\n * @example\r\n * // In template: {{date | date:short}} or {{date | date:long}}\r\n * datePipe(new Date(), 'short'); // \"1/15/2024\" (en) or \"2024-01-15\" (sv)\r\n * datePipe(new Date(), 'long'); // \"Monday, January 15, 2024\" (en) or \"m\u00E5ndag 15 januari 2024\" (sv)\r\n */\r\nexport function datePipe(value: string | number | Date, format?: string): string {\r\n const date = new Date(value);\r\n const locale = getCurrentLocale();\r\n if (format === 'short') {\r\n return date.toLocaleDateString(locale);\r\n } else if (format === 'long') {\r\n return date.toLocaleDateString(locale, {\r\n weekday: 'long',\r\n year: 'numeric',\r\n month: 'long',\r\n day: 'numeric'\r\n });\r\n }\r\n return date.toISOString();\r\n}\r\n\r\n/**\r\n * Prints today, yesterday or X days ago.\r\n * Uses the i18n system for translations (requires pipes namespace loaded).\r\n *\r\n * @param value Date value (string, number, or Date object)\r\n * @returns Formatted relative date string\r\n *\r\n * @example\r\n * // In template: {{createdAt | daysAgo}}\r\n * // English: \"today\", \"yesterday\", \"3 days ago\"\r\n * // Swedish: \"idag\", \"ig\u00E5r\", \"3 dagar sedan\"\r\n */\r\nexport function daysAgoPipe(value: string | number | Date): string {\r\n if (!value) {\r\n return 'n/a';\r\n }\r\n\r\n const inputDate = new Date(value);\r\n const today = new Date();\r\n\r\n // Normalize times to midnight to compare only dates\r\n inputDate.setHours(0, 0, 0, 0);\r\n today.setHours(0, 0, 0, 0);\r\n\r\n const diffTime = today.getTime() - inputDate.getTime();\r\n const diffDays = Math.round(diffTime / (1000 * 60 * 60 * 24));\r\n\r\n if (diffDays === 0) return t('r-pipes:today');\r\n if (diffDays === 1) return t('r-pipes:yesterday');\r\n return t('r-pipes:daysAgo', { count: diffDays });\r\n}\r\n\r\n/**\r\n * Formats a count as pieces/items.\r\n * Uses the i18n system for translations (requires pipes namespace loaded).\r\n *\r\n * @param value Count value\r\n * @returns Formatted piece count string\r\n *\r\n * @example\r\n * // In template: {{quantity | pieces}}\r\n * // English: \"none\", \"one\", \"3 pcs\"\r\n * // Swedish: \"inga\", \"en\", \"3 st\"\r\n */\r\nexport function piecesPipe(value: string | number): string {\r\n if (value === null || value === undefined) {\r\n return 'n/a';\r\n }\r\n\r\n const count = Number(value);\r\n return t('r-pipes:pieces', { count });\r\n}\r\n\r\n\r\n\r\n// =============================== Array operation pipes ===========================\r\n\r\n\r\n\r\n/**\r\n * Joins array elements with the specified separator\r\n * @param value Array to join\r\n * @param separator Character(s) to use between elements (defaults to comma)\r\n * @returns Joined string or original value if not an array\r\n */\r\nexport function joinPipe(value: any[], separator: string = ','): string | any {\r\n if (!Array.isArray(value)) return value;\r\n return value.join(separator);\r\n}\r\n\r\n/**\r\n * Returns the first element of an array\r\n * @param value Array to extract from\r\n * @returns First element or empty string if array is empty/invalid\r\n */\r\nexport function firstPipe(value: any[]): any {\r\n if (!Array.isArray(value) || value.length === 0) return '';\r\n return value[0];\r\n}\r\n\r\n/**\r\n * Returns the last element of an array\r\n * @param value Array to extract from\r\n * @returns Last element or empty string if array is empty/invalid\r\n */\r\nexport function lastPipe(value: any[]): any {\r\n if (!Array.isArray(value) || value.length === 0) return '';\r\n return value[value.length - 1];\r\n}\r\n\r\n// Object operation pipes\r\n/**\r\n * Returns the keys of an object\r\n * @param value Object to extract keys from\r\n * @returns Array of object keys or empty array if not an object\r\n */\r\nexport function keysPipe(value: object): string[] {\r\n if (typeof value !== 'object' || value === null) return [];\r\n return Object.keys(value);\r\n}\r\n\r\n// Conditional pipes\r\n/**\r\n * Returns a default value if the input is falsy\r\n * @param value Input value to check\r\n * @param defaultValue Value to return if input is falsy\r\n * @returns Original value or default value\r\n */\r\nexport function defaultPipe(value: any, defaultValue: string): any {\r\n return value || defaultValue;\r\n}\r\n\r\n/**\r\n * Implements ternary operator as a pipe\r\n * @param value Condition to evaluate\r\n * @param trueValue Value to return if condition is truthy\r\n * @param falseValue Value to return if condition is falsy\r\n * @returns Selected value based on condition\r\n */\r\nexport function ternaryPipe(value: any, trueValue: string, falseValue: string): string {\r\n return value ? trueValue : falseValue;\r\n}\r\n\r\n\r\n\r\n// =============================== Pipe registry and application ===========================\r\n\r\n\r\n/**\r\n * Interface for a collection of pipe functions.\r\n * Use this to look up pipes by name for template processing.\r\n *\r\n * @example\r\n * // Check if a pipe exists before using\r\n * if (registry.has('currency')) {\r\n * const formatted = registry.get('currency')(price);\r\n * }\r\n */\r\nexport interface PipeRegistry {\r\n /**\r\n * Looks up a pipe by name, returning null if not found.\r\n */\r\n lookup(name: string): PipeFunction | null;\r\n\r\n /**\r\n * Gets a pipe by name, throwing if not found.\r\n */\r\n get(name: string): PipeFunction;\r\n\r\n /**\r\n * Checks if a pipe with the given name exists.\r\n */\r\n has(name: string): boolean;\r\n}\r\n\r\n\r\n/**\r\n * Creates a new pipe registry with all built-in pipes registered.\r\n * Built-in pipes include:\r\n *\r\n * **Text:** uppercase, lowercase, capitalize, trim, shorten\r\n * **Formatting:** currency, date, daysAgo, pieces\r\n * **Arrays:** join, first, last\r\n * **Objects:** keys\r\n * **Conditionals:** default, ternary\r\n *\r\n * @returns A new pipe registry instance\r\n *\r\n * @example\r\n * const registry = createPipeRegistry();\r\n * const upperPipe = registry.get('uppercase');\r\n * console.log(upperPipe('hello')); // 'HELLO'\r\n */\r\nexport function createPipeRegistry(): PipeRegistry {\r\n const pipes = new Map<string, PipeFunction>();\r\n\r\n // Text manipulation\r\n pipes.set('uppercase', uppercasePipe);\r\n pipes.set('lowercase', lowercasePipe);\r\n pipes.set('capitalize', capitalizePipe);\r\n pipes.set('trim', trimPipe);\r\n pipes.set('shorten', shortenPipe);\r\n\r\n // Formatting\r\n pipes.set('currency', currencyPipe);\r\n pipes.set('date', datePipe);\r\n pipes.set('daysAgo', daysAgoPipe);\r\n pipes.set('pieces', piecesPipe);\r\n\r\n // Array operations\r\n pipes.set('join', joinPipe);\r\n pipes.set('first', firstPipe);\r\n pipes.set('last', lastPipe);\r\n\r\n // Object operations\r\n pipes.set('keys', keysPipe);\r\n\r\n // Conditional formatting\r\n pipes.set('default', defaultPipe);\r\n pipes.set('ternary', ternaryPipe);\r\n\r\n return {\r\n lookup(name) {\r\n return pipes.get(name);\r\n },\r\n get(name) {\r\n var pipe = pipes.get(name);\r\n if (!pipe) {\r\n throw Error(\"Pipe '\" + name + \"' not found.\");\r\n }\r\n return pipe;\r\n },\r\n has(name) {\r\n return pipes.has(name);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Default pipe registry instance with all built-in pipes.\r\n * Used by template engines unless a custom registry is provided.\r\n *\r\n * @example\r\n * import { defaultPipes } from 'relaxjs';\r\n *\r\n * if (defaultPipes.has('uppercase')) {\r\n * const result = defaultPipes.get('uppercase')('hello');\r\n * }\r\n */\r\nexport const defaultPipes = createPipeRegistry();\r\n\r\n/**\r\n * Applies a series of pipes to a value sequentially.\r\n * Each pipe transforms the output of the previous pipe.\r\n *\r\n * Pipe arguments are specified after a colon: `shorten:20`\r\n *\r\n * @param value - Initial value to transform\r\n * @param pipes - Array of pipe strings (name and optional arguments separated by ':')\r\n * @param registry - Optional custom pipe registry (uses defaultPipes if not provided)\r\n * @returns The transformed value after applying all pipes\r\n *\r\n * @example\r\n * // Apply single pipe\r\n * applyPipes('hello', ['uppercase']); // 'HELLO'\r\n *\r\n * @example\r\n * // Chain multiple pipes\r\n * applyPipes('hello world', ['uppercase', 'shorten:8']); // 'HELLO...'\r\n *\r\n * @example\r\n * // With pipe arguments\r\n * applyPipes(1234.56, ['currency']); // '$1,234.56'\r\n */\r\nexport function applyPipes(\r\n value: any,\r\n pipes: string[],\r\n registry: PipeRegistry = defaultPipes\r\n): any {\r\n\r\n return pipes.reduce((currentValue, pipe) => {\r\n const [pipeName, ...args] = pipe.split(':').map((p) => p.trim());\r\n\r\n if (!registry.has(pipeName)) {\r\n return `[Pipe ${pipeName} not found]`;\r\n }\r\n\r\n try {\r\n return registry.get(pipeName)(currentValue, ...args);\r\n } catch (error) {\r\n return `[Pipe ${pipeName}, value: ${value}, error: ${error}]`;\r\n }\r\n }, value);\r\n}", "/**\r\n * @module html\r\n * HTML template engine with update capabilities.\r\n * Creates templates that can be re-rendered with new data without recreating DOM nodes.\r\n */\r\n\r\nimport { defaultPipes } from \"../pipes\";\r\n\r\nconst pipes = defaultPipes;\r\n\r\ninterface Binding {\r\n originalValue?: unknown;\r\n setter: (instance: unknown) => void;\r\n}\r\n\r\n/**\r\n * Result of rendering a template.\r\n * Provides the DOM fragment and an update function for re-rendering.\r\n */\r\nexport interface RenderTemplate {\r\n /** The rendered DOM fragment */\r\n fragment: DocumentFragment;\r\n /** Updates the DOM with new data without recreating elements */\r\n update(context: any): void;\r\n}\r\n\r\n/**\r\n * Creates an updateable HTML template using tagged template literals.\r\n * Returns an object with the fragment and an update method for efficient re-rendering.\r\n *\r\n * Supports:\r\n * - Template literal substitutions (`${}`)\r\n * - Mustache-style bindings (`{{property}}`)\r\n * - Pipe transformations (`{{value|uppercase}}`)\r\n * - Event handler binding\r\n *\r\n * @param templateStrings - The static parts of the template literal\r\n * @param substitutions - The dynamic values interpolated into the template\r\n * @returns A function that takes context and returns a RenderTemplate\r\n *\r\n * @example\r\n * // Create and render a template\r\n * const template = html`\r\n * <div class=\"user\">\r\n * <h2>{{name}}</h2>\r\n * <p>{{email}}</p>\r\n * <span>{{createdAt|daysAgo}}</span>\r\n * </div>\r\n * `;\r\n *\r\n * const result = template({ name: 'John', email: 'john@example.com', createdAt: new Date() });\r\n * container.appendChild(result.fragment);\r\n *\r\n * // Later, update with new data\r\n * result.update({ name: 'Jane', email: 'jane@example.com', createdAt: new Date() });\r\n *\r\n * @example\r\n * // With event handlers\r\n * const row = html`\r\n * <tr>\r\n * <td>{{name}}</td>\r\n * <td><button onclick=${function() { this.edit(this.id) }}>Edit</button></td>\r\n * </tr>\r\n * `;\r\n */\r\nexport function html(\r\n templateStrings: TemplateStringsArray,\r\n ...substitutions: any[]\r\n): (context: any) => RenderTemplate {\r\n // Preprocess template strings\r\n const template = document.createElement(\"template\");\r\n const resolvedTemplate = resolveTemplate(templateStrings);\r\n template.innerHTML = resolvedTemplate;\r\n const bindings: Binding[] = [];\r\n\r\n const walker = document.createTreeWalker(\r\n template.content,\r\n NodeFilter.SHOW_ALL\r\n );\r\n let node: Node | null;\r\n\r\n while ((node = walker.nextNode())) {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n processElement(element, substitutions, bindings);\r\n if (customElements.get(element.tagName.toLowerCase())) {\r\n customElements.upgrade(element);\r\n }\r\n } else if (node.nodeType === Node.TEXT_NODE) {\r\n const myNode = node;\r\n const text = myNode.textContent!;\r\n const result = parseTemplate(text, substitutions);\r\n if (result) {\r\n const hasSubstitutions = /\u20AC\u20AC\\d+\u20AC\u20AC/.test(text);\r\n if (hasSubstitutions) {\r\n let startMarker: Comment | null = null;\r\n let endMarker: Comment | null = null;\r\n let insertedNodes: Node[] = [];\r\n bindings.push({\r\n originalValue: text,\r\n setter(instance) {\r\n var value = result(instance);\r\n if (!startMarker) {\r\n startMarker = document.createComment('');\r\n endMarker = document.createComment('');\r\n myNode.parentNode?.replaceChild(endMarker, myNode);\r\n endMarker.parentNode?.insertBefore(startMarker, endMarker);\r\n }\r\n insertedNodes.forEach(n => n.parentNode?.removeChild(n));\r\n insertedNodes = [];\r\n const temp = document.createElement('template');\r\n temp.innerHTML = value;\r\n const nodes = Array.from(temp.content.childNodes);\r\n const parent = endMarker!.parentNode!;\r\n nodes.forEach(n => {\r\n parent.insertBefore(n, endMarker);\r\n insertedNodes.push(n);\r\n });\r\n },\r\n });\r\n } else {\r\n bindings.push({\r\n originalValue: text,\r\n setter(instance) {\r\n var value = result(instance);\r\n myNode.textContent = value;\r\n },\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Return a function for binding\r\n return function bind(context: any): RenderTemplate {\r\n bindings.forEach((x) => {\r\n x.setter(context);\r\n });\r\n\r\n return {\r\n fragment: template.content,\r\n update(context: any) {\r\n bindings.forEach((x) => {\r\n x.setter(context);\r\n });\r\n },\r\n };\r\n };\r\n}\r\n\r\nfunction resolveTemplate(templateStrings: TemplateStringsArray): string {\r\n return templateStrings.raw\r\n .map((str, i) =>\r\n i < templateStrings.raw.length - 1 ? `${str}\u20AC\u20AC${i}\u20AC\u20AC` : str\r\n )\r\n .join(\"\");\r\n}\r\n\r\nfunction processElement(\r\n element: HTMLElement,\r\n substitutions: any[],\r\n bindings: Binding[]\r\n) {\r\n const attrBindings: Binding[] = [];\r\n\r\n for (const attr of Array.from(element.attributes)) {\r\n var attrValue = attr.value;\r\n if (attrValue == \"\") {\r\n continue;\r\n }\r\n\r\n const regex = /\u20AC\u20AC(\\d+)\u20AC\u20AC/;\r\n const match = attrValue.match(regex);\r\n if (match) {\r\n const index = parseInt(match[1], 10);\r\n const func = substitutions[index];\r\n if (typeof func === \"function\") {\r\n attrBindings.push({\r\n setter(instance) {\r\n const boundFunction = func.bind(instance);\r\n element.removeAttribute(attr.name);\r\n element[attr.name] = boundFunction;\r\n },\r\n });\r\n\r\n continue;\r\n }\r\n }\r\n\r\n var attributeCallback = parseTemplate(attrValue, substitutions);\r\n if (attributeCallback == null) {\r\n continue;\r\n }\r\n\r\n attrBindings.push({\r\n originalValue: attrValue,\r\n setter(instance) {\r\n const value = attributeCallback!(instance) ?? attrValue;\r\n if (attr.name in element) {\r\n element[attr.name] = value;\r\n } else {\r\n attr.value = value;\r\n }\r\n },\r\n });\r\n }\r\n\r\n if (attrBindings.length > 0) {\r\n bindings.push({\r\n originalValue: element.tagName,\r\n setter(instance) {\r\n attrBindings.forEach((attrBinding) => attrBinding.setter(instance));\r\n },\r\n });\r\n }\r\n}\r\n\r\ntype TemplateCallback = (instance: any) => string;\r\n\r\n\r\n/**\r\n * Parse arguments for function calls in mustache expressions\r\n * Handles dot notation like row.id and nested properties\r\n */\r\nfunction parseArguments(argsStr: string, instance: any): any[] {\r\n return argsStr.split(',').map(arg => {\r\n arg = arg.trim();\r\n\r\n if ((arg.startsWith('\"') && arg.endsWith('\"')) ||\r\n (arg.startsWith(\"'\") && arg.endsWith(\"'\"))) {\r\n return arg.slice(1, -1);\r\n }\r\n\r\n if (!isNaN(Number(arg))) {\r\n return Number(arg);\r\n }\r\n\r\n if (arg.includes('.')) {\r\n const parts = arg.split('.');\r\n let value = instance;\r\n for (const part of parts) {\r\n if (value === undefined || value === null) return undefined;\r\n value = value[part];\r\n }\r\n return value;\r\n }\r\n\r\n // Handle simple variable references\r\n return instance[arg];\r\n });\r\n}\r\n\r\n\r\nfunction parseTemplate(\r\n template: string,\r\n substitutions: any[]\r\n): TemplateCallback | null {\r\n const regex = /\u20AC\u20AC(\\d+)\u20AC\u20AC|{{\\s*([^|]+?)(?:\\|([\\w|]+))?\\s*}}/g;\r\n let lastIndex = 0;\r\n let match;\r\n\r\n const textBindings: TemplateCallback[] = [];\r\n while ((match = regex.exec(template)) !== null) {\r\n var value = template.slice(lastIndex, match.index);\r\n if (value.length > 0) {\r\n textBindings.push((_instance) => {\r\n return value;\r\n });\r\n }\r\n\r\n // ${}\r\n if (match[1]) {\r\n const index = parseInt(match[1], 10);\r\n const sub = substitutions[index];\r\n if (!sub) {\r\n continue;\r\n }\r\n\r\n if (typeof sub === \"function\") {\r\n const func = sub as Function;\r\n textBindings.push((instance) => {\r\n var result = func.apply(instance);\r\n return result;\r\n });\r\n } else {\r\n if (sub && sub.length > 0) {\r\n textBindings.push((instance) => {\r\n return sub;\r\n });\r\n }\r\n }\r\n } else if (match[2]) {\r\n // {{mustache|pipes}} case\r\n const mustacheName = match[2].trim();\r\n const argsStr = match[3] ? match[3].trim() : null;\r\n const matchingPipes = match[4]\r\n ? match[4].split(\"|\").map((pipe) => pipe.trim())\r\n : [];\r\n\r\n textBindings.push((instance) => {\r\n var value = instance[mustacheName];\r\n\r\n if (typeof value === \"function\") {\r\n if (argsStr) {\r\n const args = parseArguments(argsStr, instance);\r\n value = value.apply(instance, args);\r\n } else {\r\n value = value.call(instance);\r\n }\r\n }\r\n\r\n matchingPipes.forEach((pipe) => {\r\n value = pipes[pipe](value);\r\n });\r\n return value;\r\n });\r\n }\r\n\r\n lastIndex = regex.lastIndex;\r\n }\r\n\r\n if (textBindings.length == 0) {\r\n return null;\r\n }\r\n\r\n var val = template.slice(lastIndex);\r\n if (val.length > 0) {\r\n textBindings.push((_) => {\r\n return val;\r\n });\r\n }\r\n return (instance) => {\r\n var result = \"\";\r\n textBindings.forEach((binding) => {\r\n var value = binding(instance);\r\n result += value;\r\n });\r\n\r\n return result;\r\n };\r\n}\r\n", "/**\r\n * @module template\r\n * DOM-based template engine with reactive rendering capabilities.\r\n *\r\n * Compiles HTML templates with mustache-style expressions into efficient\r\n * render functions that update the DOM when data changes.\r\n *\r\n * **Features:**\r\n * - Text interpolation: `{{name}}`, `{{user.profile.email}}`\r\n * - Attribute binding: `<div class=\"{{className}}\">`\r\n * - Pipes: `{{price | currency}}`, `{{name | uppercase | shorten:20}}`\r\n * - Function calls: `{{formatDate(createdAt)}}`, `{{add(5, 3)}}`\r\n * - Array indexing: `{{items[0]}}`, `{{users[1].name}}`\r\n * - Conditionals: `<div if=\"isVisible\">`, `<div unless=\"isHidden\">`\r\n * - Loops: `<li loop=\"item in items\">{{item.name}}</li>`\r\n *\r\n * @example\r\n * // Basic usage\r\n * import { compileTemplate } from './m';\r\n *\r\n * const { content, render } = compileTemplate(`\r\n * <div class=\"card\">\r\n * <h2>{{title}}</h2>\r\n * <p>{{description}}</p>\r\n * </div>\r\n * `);\r\n *\r\n * render({ title: 'Hello', description: 'World' });\r\n * document.body.appendChild(content);\r\n *\r\n * @example\r\n * // With pipes and functions\r\n * import { createPipeRegistry } from '../pipes';\r\n *\r\n * const pipeRegistry = createPipeRegistry();\r\n * const { content, render } = compileTemplate(`\r\n * <span>{{user.name | uppercase}}</span>\r\n * <span>{{formatDate(user.createdAt)}}</span>\r\n * `, { strict: false, pipeRegistry });\r\n *\r\n * render(\r\n * { user: { name: 'john', createdAt: new Date() } },\r\n * { formatDate: (d) => d.toLocaleDateString() }\r\n * );\r\n *\r\n * @example\r\n * // With loops and conditionals\r\n * const { content, render } = compileTemplate(`\r\n * <ul>\r\n * <li loop=\"item in items\" if=\"item.visible\">\r\n * {{item.name}}: {{item.price | currency}}\r\n * </li>\r\n * </ul>\r\n * `);\r\n *\r\n * render({ items: [\r\n * { name: 'Apple', price: 1.5, visible: true },\r\n * { name: 'Hidden', price: 0, visible: false }\r\n * ]});\r\n */\r\n\r\nimport { PipeRegistry, defaultPipes, applyPipes } from '../pipes';\r\n\r\n/**\r\n * Configuration options for the template engine.\r\n *\r\n * @example\r\n * const config: EngineConfig = {\r\n * strict: true,\r\n * onError: (msg) => console.error(msg),\r\n * pipeRegistry: createPipeRegistry()\r\n * };\r\n */\r\nexport interface EngineConfig {\r\n /** When true, throws errors for missing paths/functions. When false, returns empty string. */\r\n strict: boolean;\r\n /** Optional callback invoked when errors occur, receives formatted error message. */\r\n onError?: (msg: string) => void;\r\n /** Custom pipe registry for transformations. Defaults to built-in pipes. */\r\n pipeRegistry?: PipeRegistry;\r\n}\r\n\r\nexport type Path = string;\r\nexport type TemplateValue = string | number | boolean | null | undefined;\r\n\r\n/**\r\n * Data context object passed to render function.\r\n * Contains the data values that expressions resolve against.\r\n *\r\n * @example\r\n * const ctx: Context = {\r\n * user: { name: 'John', age: 30 },\r\n * items: ['a', 'b', 'c'],\r\n * isActive: true\r\n * };\r\n */\r\nexport interface Context {\r\n [key: string]: ContextValue;\r\n}\r\n\r\n/**\r\n * Functions context object passed as second argument to render.\r\n * Contains callable functions that can be invoked from templates.\r\n *\r\n * @example\r\n * const fns: FunctionsContext = {\r\n * formatDate: (d) => d.toLocaleDateString(),\r\n * add: (a, b) => a + b,\r\n * greet: (name) => `Hello, ${name}!`\r\n * };\r\n */\r\nexport interface FunctionsContext {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n [key: string]: (...args: any[]) => any;\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type ContextValue = TemplateValue | any[] | Context | ((...args: any[]) => any);\r\n\r\nexport type Getter = (ctx: Context, path: Path, debugInfo?: string) => TemplateValue;\r\nexport type Setter = (ctx: Context, fns?: FunctionsContext) => void;\r\nexport type Patcher = (node: Node, get: Getter, config: EngineConfig) => Setter | void;\r\nexport type ExpressionFn = (ctx: Context, fns?: FunctionsContext) => TemplateValue;\r\n\r\ninterface ParsedExpression {\r\n type: 'path' | 'function';\r\n path?: string;\r\n fnName?: string;\r\n fnArgs?: string[];\r\n pipes: string[];\r\n}\r\n\r\nfunction parseExpression(expr: string): ParsedExpression {\r\n const pipesSplit = expr.split('|').map(s => s.trim());\r\n const mainExpr = pipesSplit[0];\r\n const pipes = pipesSplit.slice(1);\r\n\r\n // Check if it's a function call: functionName(args)\r\n const fnMatch = mainExpr.match(/^(\\w+)\\s*\\((.*)\\)$/);\r\n if (fnMatch) {\r\n const [, fnName, argsStr] = fnMatch;\r\n const fnArgs = argsStr\r\n ? argsStr.split(',').map(a => a.trim())\r\n : [];\r\n return { type: 'function', fnName, fnArgs, pipes };\r\n }\r\n\r\n return { type: 'path', path: mainExpr, pipes };\r\n}\r\n\r\n// Resolve a path with support for array indexing: items[0].name\r\nfunction resolvePath(ctx: ContextValue, path: string): ContextValue {\r\n // Handle array indexing by converting items[0] to items.0\r\n const normalizedPath = path.replace(/\\[(\\d+)\\]/g, '.$1');\r\n const segments = normalizedPath.split('.');\r\n let current = ctx;\r\n\r\n for (const key of segments) {\r\n if (current && typeof current === 'object' && key in current) {\r\n current = (current as Record<string, ContextValue>)[key];\r\n } else {\r\n return undefined;\r\n }\r\n }\r\n\r\n return current;\r\n}\r\n \r\n function handleError(config: EngineConfig, message: string, context: string, shouldThrow = false): void {\r\n const formattedMessage = `[template error] ${message} (at ${context})`;\r\n \r\n if (config.onError) config.onError(formattedMessage);\r\n if (config.strict || shouldThrow) throw new Error(formattedMessage);\r\n }\r\n \r\nfunction createGetter(config: EngineConfig): Getter {\r\n return function get(ctx: ContextValue, path: Path, debugInfo = ''): TemplateValue {\r\n try {\r\n const current = resolvePath(ctx, path);\r\n\r\n if (current === undefined) {\r\n handleError(config, `Cannot resolve \"${path}\"`, debugInfo);\r\n return '';\r\n }\r\n\r\n // Return primitive values as-is for conditional checks\r\n if (current === null) {\r\n return '';\r\n } else if (Array.isArray(current)) {\r\n return current.length > 0 ? JSON.stringify(current) : '';\r\n } else if (typeof current === 'object') {\r\n return JSON.stringify(current);\r\n } else {\r\n return current as TemplateValue;\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : String(err);\r\n handleError(config, `Exception resolving \"${path}\": ${errorMessage}`, debugInfo, true);\r\n return '';\r\n }\r\n };\r\n}\r\n\r\nfunction evaluateExpression(\r\n parsed: ParsedExpression,\r\n ctx: Context,\r\n fns: FunctionsContext | undefined,\r\n config: EngineConfig,\r\n debugInfo: string\r\n): TemplateValue {\r\n let value: TemplateValue;\r\n const registry = config.pipeRegistry ?? defaultPipes;\r\n\r\n if (parsed.type === 'function') {\r\n const fn = fns?.[parsed.fnName!];\r\n if (typeof fn !== 'function') {\r\n handleError(config, `Function \"${parsed.fnName}\" not found`, debugInfo);\r\n return '';\r\n }\r\n\r\n // Resolve function arguments - could be literals or paths\r\n const resolvedArgs = (parsed.fnArgs ?? []).map(arg => {\r\n // String literal\r\n if ((arg.startsWith('\"') && arg.endsWith('\"')) ||\r\n (arg.startsWith(\"'\") && arg.endsWith(\"'\"))) {\r\n return arg.slice(1, -1);\r\n }\r\n // Number literal\r\n if (!isNaN(Number(arg))) {\r\n return Number(arg);\r\n }\r\n // Path reference - resolve from context\r\n const resolved = resolvePath(ctx, arg);\r\n return resolved;\r\n });\r\n\r\n try {\r\n value = fn(...resolvedArgs) as TemplateValue;\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : String(err);\r\n handleError(config, `Error calling \"${parsed.fnName}\": ${errorMessage}`, debugInfo);\r\n return '';\r\n }\r\n } else {\r\n // Path resolution\r\n const resolved = resolvePath(ctx, parsed.path!);\r\n if (resolved === undefined) {\r\n handleError(config, `Cannot resolve \"${parsed.path}\"`, debugInfo);\r\n return '';\r\n }\r\n if (resolved === null) {\r\n value = '';\r\n } else if (typeof resolved === 'object') {\r\n value = JSON.stringify(resolved);\r\n } else {\r\n value = resolved as TemplateValue;\r\n }\r\n }\r\n\r\n // Apply pipes if any\r\n if (parsed.pipes.length > 0) {\r\n value = applyPipes(value, parsed.pipes, registry);\r\n }\r\n\r\n return value;\r\n}\r\n \r\n// Improved text node patcher with expression memoization\r\nconst expressionCache = new Map<string, { parsed: ParsedExpression; literal: string }[]>();\r\n\r\nfunction textNodePatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.TEXT_NODE || !node.textContent?.includes('{{')) return;\r\n\r\n const raw = node.textContent;\r\n\r\n // Use cached parsed expressions if available\r\n if (!expressionCache.has(raw)) {\r\n const parts = raw.split(/(\\{\\{.*?\\}\\})/);\r\n const parsed = parts.map(part => {\r\n if (part.startsWith('{{')) {\r\n const expr = part.slice(2, -2).trim();\r\n return { parsed: parseExpression(expr), literal: '' };\r\n } else {\r\n return { parsed: null as unknown as ParsedExpression, literal: part };\r\n }\r\n });\r\n expressionCache.set(raw, parsed);\r\n }\r\n\r\n const exprs = expressionCache.get(raw)!;\r\n const debugInfo = `TextNode: \"${raw}\"`;\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const result = exprs.map(({ parsed, literal }) => {\r\n if (parsed) {\r\n return String(evaluateExpression(parsed, ctx, fns, config, debugInfo));\r\n }\r\n return literal;\r\n }).join('');\r\n (node as Text).textContent = result;\r\n };\r\n}\r\n \r\nfunction attributeInterpolationPatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as Element;\r\n const setters: Setter[] = [];\r\n\r\n // Use Array.from to safely iterate over NamedNodeMap\r\n const attributes = Array.from(element.attributes);\r\n for (const attr of attributes) {\r\n const match = attr.value.match(/\\{\\{(.+?)\\}\\}/);\r\n if (match) {\r\n const expr = match[1].trim();\r\n const parsed = parseExpression(expr);\r\n const name = attr.name;\r\n const debugInfo = `Attribute: ${name} on <${element.tagName.toLowerCase()}>`;\r\n setters.push((ctx: Context, fns?: FunctionsContext) => {\r\n const value = evaluateExpression(parsed, ctx, fns, config, debugInfo);\r\n element.setAttribute(name, String(value));\r\n });\r\n }\r\n }\r\n\r\n if (setters.length > 0) {\r\n return (ctx: Context, fns?: FunctionsContext) => setters.forEach(fn => fn(ctx, fns));\r\n }\r\n}\r\n \r\n/**\r\n * Caches the detached element+renderer when hiding so that re-showing\r\n * skips the clone + compile overhead. Render-before-insert order is\r\n * preserved for both fresh and cached paths.\r\n */\r\nfunction createConditionalPatcher(\r\n node: Node,\r\n get: Getter,\r\n config: EngineConfig,\r\n attrName: string,\r\n shouldRender: (value: TemplateValue) => boolean\r\n): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE || !(node as Element).hasAttribute(attrName)) return;\r\n\r\n const element = node as Element;\r\n const expr = element.getAttribute(attrName)!;\r\n const templateNode = element.cloneNode(true) as Element;\r\n const placeholder = document.createComment(`${attrName}: ${expr}`);\r\n const parent = element.parentNode!;\r\n\r\n parent.insertBefore(placeholder, element);\r\n element.remove();\r\n\r\n let currentElement: Element | null = null;\r\n let currentRenderer: ((ctx: Context, fns?: FunctionsContext) => void) | null = null;\r\n let cachedElement: Element | null = null;\r\n let cachedRenderer: ((ctx: Context, fns?: FunctionsContext) => void) | null = null;\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const value = get(ctx, expr, `${attrName}=\"${expr}\"`);\r\n const shouldBeVisible = shouldRender(value);\r\n\r\n if (shouldBeVisible && !currentElement) {\r\n if (cachedElement && cachedRenderer) {\r\n currentElement = cachedElement;\r\n currentRenderer = cachedRenderer;\r\n cachedElement = null;\r\n cachedRenderer = null;\r\n } else {\r\n const clone = templateNode.cloneNode(true) as Element;\r\n clone.removeAttribute(attrName);\r\n currentElement = clone;\r\n currentRenderer = compileDOM(clone, config);\r\n }\r\n currentRenderer(ctx, fns);\r\n parent.insertBefore(currentElement, placeholder.nextSibling);\r\n } else if (shouldBeVisible && currentRenderer) {\r\n currentRenderer(ctx, fns);\r\n }\r\n\r\n if (!shouldBeVisible && currentElement) {\r\n currentElement.remove();\r\n cachedElement = currentElement;\r\n cachedRenderer = currentRenderer;\r\n currentElement = null;\r\n currentRenderer = null;\r\n }\r\n };\r\n}\r\n\r\nfunction ifPatcher(node: Node, get: Getter, config: EngineConfig): Setter | void {\r\n return createConditionalPatcher(node, get, config, 'if', value => !!value);\r\n}\r\n\r\nfunction unlessPatcher(node: Node, get: Getter, config: EngineConfig): Setter | void {\r\n return createConditionalPatcher(node, get, config, 'unless', value => !value);\r\n}\r\n \r\ninterface LoopSlot {\r\n element: Element;\r\n renderer: (ctx: Context, fns?: FunctionsContext) => void;\r\n}\r\n\r\n/**\r\n * Rendering order for loop items:\r\n *\r\n * 1. Clone from template (detached, attributes still contain mustache)\r\n * 2. Compile the clone \u2014 creates setters for mustache in attributes/text\r\n * 3. Render \u2014 resolves mustache against the iteration context\r\n * 4. Insert into DOM \u2014 custom elements upgrade with final attribute values\r\n *\r\n * Steps 2-3 MUST happen before step 4. If we insert first, the browser\r\n * upgrades custom elements immediately (connectedCallback fires) while\r\n * attributes still contain raw \"{{expr}}\" strings.\r\n *\r\n * Slot reuse: existing elements are re-rendered in place (already in DOM,\r\n * already compiled). Only new items go through the full clone-compile-render-\r\n * insert sequence. Excess items are removed.\r\n */\r\nfunction loopPatcher(node: Node, _get: Getter, config: EngineConfig): Setter | void {\r\n if (node.nodeType !== Node.ELEMENT_NODE || !(node as Element).hasAttribute('loop')) return;\r\n\r\n const element = node as Element;\r\n const loopDef = element.getAttribute('loop')!;\r\n const match = loopDef.match(/(\\w+)\\s+in\\s+(.+)/);\r\n if (!match) {\r\n handleError(config, `Invalid loop syntax: \"${loopDef}\"`, `Element: <${element.tagName.toLowerCase()}>`);\r\n return;\r\n }\r\n\r\n const [, alias, source] = match;\r\n const tpl = element.cloneNode(true) as Element;\r\n tpl.removeAttribute('loop');\r\n\r\n const parent = element.parentNode!;\r\n const placeholder = document.createComment(`loop: ${loopDef}`);\r\n parent.insertBefore(placeholder, element);\r\n element.remove();\r\n\r\n let slots: LoopSlot[] = [];\r\n\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n const items = resolvePath(ctx, source);\r\n\r\n if (items === undefined) {\r\n handleError(config, `Cannot resolve \"${source}\"`, `Loop source: \"${loopDef}\"`);\r\n return;\r\n }\r\n\r\n if (!Array.isArray(items)) {\r\n handleError(config, `\"${source}\" is not an array in loop: \"${loopDef}\"`,\r\n `Element: <${tpl.tagName.toLowerCase()}>`);\r\n return;\r\n }\r\n\r\n const reuseCount = Math.min(slots.length, items.length);\r\n\r\n // Re-render existing slots in place\r\n for (let i = 0; i < reuseCount; i++) {\r\n slots[i].renderer({ ...ctx, [alias]: items[i] }, fns);\r\n }\r\n\r\n // Remove excess slots\r\n for (let i = slots.length - 1; i >= items.length; i--) {\r\n slots[i].element.remove();\r\n }\r\n\r\n // Create new slots via DocumentFragment for batch insertion\r\n if (items.length > reuseCount) {\r\n const frag = document.createDocumentFragment();\r\n const newSlots: LoopSlot[] = [];\r\n\r\n for (let i = reuseCount; i < items.length; i++) {\r\n // 1. Clone (detached \u2014 no connectedCallback yet)\r\n const instance = tpl.cloneNode(true) as Element;\r\n\r\n // 2-3. Compile + render while detached \u2014 resolves mustache\r\n const childRenderer = compileDOM(instance, config);\r\n childRenderer({ ...ctx, [alias]: items[i] }, fns);\r\n\r\n frag.appendChild(instance);\r\n newSlots.push({ element: instance, renderer: childRenderer });\r\n }\r\n\r\n // 4. Batch-insert into live DOM \u2014 custom elements upgrade with final values\r\n const insertAfter = reuseCount > 0\r\n ? slots[reuseCount - 1].element\r\n : placeholder;\r\n parent.insertBefore(frag, insertAfter.nextSibling);\r\n\r\n slots = slots.slice(0, reuseCount).concat(newSlots);\r\n } else {\r\n slots.length = items.length;\r\n }\r\n };\r\n}\r\n \r\n/**\r\n * Structural patchers (loop, if, unless) take full ownership of a node.\r\n * They replace the original with a placeholder, then on each render they\r\n * clone, compile, and resolve the node independently. When one matches,\r\n * content patchers and child traversal are skipped for that node.\r\n */\r\nconst structuralPatchers: Patcher[] = [\r\n loopPatcher,\r\n ifPatcher,\r\n unlessPatcher\r\n];\r\n\r\n/** Content patchers resolve mustache expressions in text nodes and attributes. */\r\nconst contentPatchers: Patcher[] = [\r\n textNodePatcher,\r\n attributeInterpolationPatcher,\r\n];\r\n\r\n/**\r\n * Walks the DOM tree and collects setters from patchers.\r\n *\r\n * Processing order per node:\r\n * 1. Try structural patchers \u2014 if one matches, it owns the node (skip steps 2-3)\r\n * 2. Run content patchers (text interpolation, attribute interpolation)\r\n * 3. Recurse into child nodes\r\n */\r\nfunction compileDOM(root: Node, config: EngineConfig): (ctx: Context, fns?: FunctionsContext) => void {\r\n const setters: Setter[] = [];\r\n const get = createGetter(config);\r\n\r\n function processNode(node: Node) {\r\n // Structural directives own the node \u2014 they clone + compileDOM internally\r\n for (const patch of structuralPatchers) {\r\n const setter = patch(node, get, config);\r\n if (setter) {\r\n setters.push(setter);\r\n return;\r\n }\r\n }\r\n\r\n // Content patchers \u2014 resolve {{expr}} in text and attributes\r\n for (const patch of contentPatchers) {\r\n const setter = patch(node, get, config);\r\n if (setter) setters.push(setter);\r\n }\r\n\r\n for (const child of Array.from(node.childNodes)) {\r\n processNode(child);\r\n }\r\n }\r\n\r\n processNode(root);\r\n\r\n // Return memoized render function\r\n let lastCtx: Context | null = null;\r\n let lastFns: FunctionsContext | undefined = undefined;\r\n return (ctx: Context, fns?: FunctionsContext) => {\r\n // Only re-render if context has changed\r\n if (lastCtx !== ctx || lastFns !== fns) {\r\n setters.forEach(fn => fn(ctx, fns));\r\n lastCtx = ctx;\r\n lastFns = fns;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Result of compiling a template.\r\n * Contains the DOM content and a render function for updating it with data.\r\n */\r\nexport interface CompiledTemplate {\r\n /** The compiled DOM element containing the template structure. */\r\n content: DocumentFragment | HTMLElement;\r\n /**\r\n * Updates the DOM with the provided data context.\r\n * Memoized: only re-renders when context object reference changes.\r\n * @param ctx - Data context with values for template expressions\r\n * @param fns - Optional functions context for callable expressions\r\n */\r\n render: (ctx: Context, fns?: FunctionsContext) => void;\r\n}\r\n\r\n/**\r\n * Compiles an HTML template string into a reusable render function.\r\n *\r\n * The template supports mustache-style expressions `{{expression}}` for:\r\n * - Path resolution: `{{user.name}}`, `{{items[0].title}}`\r\n * - Pipes: `{{value | uppercase}}`, `{{price | currency}}`\r\n * - Function calls: `{{formatDate(createdAt)}}`, `{{add(a, b)}}`\r\n *\r\n * Directive attributes for control flow:\r\n * - `if=\"condition\"` - Renders element only when condition is truthy\r\n * - `unless=\"condition\"` - Renders element only when condition is falsy\r\n * - `loop=\"item in items\"` - Repeats element for each array item\r\n *\r\n * @param templateStr - HTML template string with mustache expressions\r\n * @param config - Optional engine configuration\r\n * @returns Compiled template with content and render function\r\n *\r\n * @example\r\n * // Simple data binding\r\n * const { content, render } = compileTemplate('<h1>{{title}}</h1>');\r\n * render({ title: 'Hello World' });\r\n * document.body.appendChild(content);\r\n *\r\n * @example\r\n * // Re-rendering with new data\r\n * const { content, render } = compileTemplate('<span>Count: {{count}}</span>');\r\n * render({ count: 0 });\r\n * render({ count: 1 }); // DOM updates automatically\r\n *\r\n * @example\r\n * // With strict mode and error handling\r\n * const { render } = compileTemplate('{{missing}}', {\r\n * strict: true,\r\n * onError: (msg) => console.error(msg)\r\n * });\r\n * render({}); // Throws error for missing path\r\n */\r\nexport function compileTemplate(templateStr: string, config: EngineConfig = { strict: false }): CompiledTemplate {\r\n const parser = new DOMParser();\r\n const doc = parser.parseFromString(`<template><div>${templateStr}</div></template>`, 'text/html');\r\n const content = doc.querySelector('template')!.content.firstElementChild as HTMLElement;\r\n const render = compileDOM(content, config);\r\n\r\n return { content, render };\r\n}", "/**\r\n * Represents a single step in a property access path\r\n * Can be either a property name or an array index access\r\n * @example { type: \"property\", key: \"user\" }\r\n * @example { type: \"index\", key: \"0\" }\r\n */\r\ntype PathSegment = {\r\n type: \"property\" | \"index\";\r\n key: string;\r\n};\r\n\r\n/**\r\n * Represents the result of parsing a dot-notation string into path segments\r\n * Used internally by the parser to break down property access chains including arrays\r\n * @example [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }] for \"users[0].name\"\r\n */\r\ntype PropertyPath = PathSegment[];\r\n\r\n/**\r\n * Function type that accesses nested properties safely from a record\r\n * Returns undefined if any property in the chain is missing or null/undefined\r\n * @example\r\n * const accessor = createAccessor(\"user.name\");\r\n * const result = accessor(data); // string | undefined\r\n */\r\ntype PropertyAccessor<T = unknown> = (\r\n record: Record<string, any>\r\n) => T | undefined;\r\n\r\n/**\r\n * Parser configuration options for customizing dot-notation parsing behavior\r\n * Used to modify how the parser handles property paths and edge cases\r\n * @example { delimiter: \".\", escapeChar: \"\\\\\" }\r\n */\r\ninterface ParserOptions {\r\n delimiter?: string;\r\n escapeChar?: string;\r\n}\r\n\r\n/**\r\n * Parses a dot-notation string with array support into path segments\r\n * Handles escaped delimiters, array indices, and validates input format\r\n * @param notation - Notation string with dots and brackets (e.g., \"users[0].profile.name\")\r\n * @param options - Parser configuration options\r\n * @returns Array of path segments for property and array access\r\n * @example\r\n * parsePath(\"user.profile.name\") // [{ type: \"property\", key: \"user\" }, { type: \"property\", key: \"profile\" }, { type: \"property\", key: \"name\" }]\r\n * parsePath(\"users[0].name\") // [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }]\r\n * parsePath(\"data\\\\.file[1]\", { escapeChar: \"\\\\\" }) // [{ type: \"property\", key: \"data.file\" }, { type: \"index\", key: \"1\" }]\r\n */\r\nfunction parsePath(\r\n notation: string,\r\n options: ParserOptions = {}\r\n): PropertyPath {\r\n const { delimiter = \".\", escapeChar = \"\\\\\" } = options;\r\n\r\n if (!notation || typeof notation !== \"string\") {\r\n throw new Error(\"Notation must be a non-empty string\");\r\n }\r\n\r\n const segments: PathSegment[] = [];\r\n let current = \"\";\r\n let i = 0;\r\n let inBrackets = false;\r\n let bracketContent = \"\";\r\n\r\n while (i < notation.length) {\r\n const char = notation[i];\r\n const currentInDelimLength = notation.substring(i, delimiter.length + i);\r\n const nextChar = notation[i + 1];\r\n const nextInDelimLength = notation.substring(i + 1, delimiter.length + i + 1);\r\n\r\n if (\r\n char === escapeChar &&\r\n (nextInDelimLength === delimiter || nextChar === \"[\" || nextChar === \"]\")\r\n ) {\r\n if (inBrackets) {\r\n bracketContent += nextChar;\r\n } else {\r\n current += nextChar;\r\n }\r\n i += 2;\r\n } else if (char === \"[\" && !inBrackets) {\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n current = \"\";\r\n }\r\n inBrackets = true;\r\n bracketContent = \"\";\r\n i++;\r\n } else if (char === \"]\" && inBrackets) {\r\n if (!/^\\d+$/.test(bracketContent.trim())) {\r\n throw new Error(\r\n `Invalid array index: [${bracketContent}]. Only numeric indices are supported.`\r\n );\r\n }\r\n segments.push({ type: \"index\", key: bracketContent.trim() });\r\n inBrackets = false;\r\n bracketContent = \"\";\r\n i++;\r\n } else if (currentInDelimLength === delimiter && !inBrackets) {\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n current = \"\";\r\n }\r\n i += delimiter.length;\r\n } else if (inBrackets) {\r\n bracketContent += char;\r\n i++;\r\n } else {\r\n current += char;\r\n i++;\r\n }\r\n }\r\n\r\n if (inBrackets) {\r\n throw new Error(\"Unclosed bracket in notation\");\r\n }\r\n\r\n if (current) {\r\n segments.push({ type: \"property\", key: current });\r\n }\r\n\r\n if (segments.length === 0) {\r\n throw new Error(\r\n \"Invalid notation: must contain at least one property or index\"\r\n );\r\n }\r\n\r\n return segments;\r\n}\r\n\r\n/**\r\n * Creates an accessor function from a parsed property path with array support\r\n * The returned function safely navigates nested objects and arrays using the parsed path\r\n * @param path - Array of path segments to access in sequence\r\n * @returns Function that takes a record and returns the nested value or undefined\r\n * @example\r\n * const path = [{ type: \"property\", key: \"users\" }, { type: \"index\", key: \"0\" }, { type: \"property\", key: \"name\" }];\r\n * const accessor = createAccessorFromPath(path);\r\n * accessor({ users: [{ name: \"John\" }] }) // \"John\"\r\n */\r\nfunction createAccessorFromPath<T = unknown>(\r\n path: PropertyPath\r\n): PropertyAccessor<T> {\r\n return (record: Record<string, any>): T | undefined => {\r\n let current: any = record;\r\n\r\n for (const segment of path) {\r\n if (current == null) {\r\n return undefined;\r\n }\r\n\r\n if (segment.type === \"property\") {\r\n if (typeof current !== \"object\") {\r\n return undefined;\r\n }\r\n current = current[segment.key];\r\n } else if (segment.type === \"index\") {\r\n if (!Array.isArray(current)) {\r\n return undefined;\r\n }\r\n const index = parseInt(segment.key, 10);\r\n if (index < 0 || index >= current.length) {\r\n return undefined;\r\n }\r\n current = current[index];\r\n }\r\n }\r\n\r\n return current as T;\r\n };\r\n}\r\n\r\n/**\r\n * Main parser function that creates an accessor from notation string with array support\r\n * Combines path parsing and accessor creation into a single operation\r\n * @param notation - Notation string with dots and brackets (e.g., \"users[0].profile.name\")\r\n * @param options - Parser configuration options\r\n * @returns Accessor function for the specified property path\r\n * @example\r\n * const accessor = createAccessor(\"user.profile.name\");\r\n * const name = accessor(userData); // safely gets nested property\r\n *\r\n * const arrayAccessor = createAccessor(\"users[0].name\");\r\n * const userName = arrayAccessor(data); // safely accesses array elements\r\n *\r\n * const complexAccessor = createAccessor(\"items[2].meta\\\\.data.values[1]\", { escapeChar: \"\\\\\" });\r\n * const value = complexAccessor(response); // handles escaped dots and nested arrays\r\n */\r\nfunction createAccessor<T = unknown>(\r\n notation: string,\r\n options: ParserOptions = {}\r\n): PropertyAccessor<T> {\r\n const path = parsePath(notation, options);\r\n return createAccessorFromPath<T>(path);\r\n}\r\n\r\n/**\r\n * Utility function to test if a property path exists in a record (with array support)\r\n * Useful for validation before attempting to access nested properties or array elements\r\n * @param notation - Notation string with dots and brackets to test\r\n * @param record - Record to test against\r\n * @param options - Parser configuration options\r\n * @returns Boolean indicating if the complete path exists\r\n * @example\r\n * hasProperty(\"user.name\", data) // true if data.user.name exists\r\n * hasProperty(\"users[0].name\", data) // true if data.users[0].name exists\r\n * hasProperty(\"missing.path\", data) // false if any part is undefined\r\n */\r\nfunction hasProperty(\r\n notation: string,\r\n record: Record<string, any>,\r\n options: ParserOptions = {}\r\n): boolean {\r\n const accessor = createAccessor(notation, options);\r\n return accessor(record) !== undefined;\r\n}\r\n\r\nexport {\r\n createAccessor,\r\n createAccessorFromPath,\r\n parsePath,\r\n hasProperty,\r\n type PropertyAccessor,\r\n type PropertyPath,\r\n type PathSegment,\r\n type ParserOptions,\r\n};\r\n", "/**\r\n * Represents different token types that can be identified by the tokenizer\r\n * @example\r\n * // Use to classify what kind of syntax element was found\r\n * const tokenType = TokenType.Constant;\r\n */\r\nexport enum TokenType {\r\n Constant = 0,\r\n FunctionCall = 1,\r\n Variable = 2,\r\n Pipe = 3,\r\n}\r\n\r\n/**\r\n * Represents a token with its type and value\r\n * @example\r\n * // Creating a token for a number constant\r\n * const token: Token = { type: TokenType.Constant, value: '42' };\r\n */\r\nexport interface Token {\r\n type: TokenType;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Tokenizes an input string into constants, function calls, and variables\r\n * @example\r\n * // Basic usage\r\n * const tokens = tokenize('myVar.property + func(42)');\r\n * \r\n * @example\r\n * // Handling complex expressions\r\n * const tokens = tokenize('math.sin(angle) + \"hello\".length');\r\n * \r\n * @example\r\n * // Handling pipes\r\n * const tokens = tokenize('input | transform | display');\r\n */\r\nexport function tokenize(input: string): Token[] {\r\n const tokens: Token[] = [];\r\n let i = 0;\r\n\r\n while (i < input.length) {\r\n let char = input[i];\r\n\r\n // Skip whitespace\r\n if (/\\s/.test(char)) {\r\n i++;\r\n continue;\r\n }\r\n\r\n // Handle pipe operator (\"|\")\r\n if (char === '|') {\r\n i++;\r\n\r\n // Skip whitespace after pipe\r\n while (i < input.length && /\\s/.test(input[i])) {\r\n i++;\r\n }\r\n\r\n // Capture the pipe target (everything up to the next whitespace or special character)\r\n let pipeTarget = '';\r\n while (i < input.length && !/[\\s\\(\\)\\[\\]\\{\\}\\|\\+\\-\\*\\/\\=\\;\\,\\.]/.test(input[i])) {\r\n pipeTarget += input[i];\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Pipe, value: pipeTarget });\r\n continue;\r\n }\r\n\r\n // Handle string constants\r\n if (char === '\"' || char === \"'\") {\r\n const quote = char;\r\n let value = quote;\r\n i++;\r\n\r\n while (i < input.length && input[i] !== quote) {\r\n // Handle escaped quotes\r\n if (input[i] === '\\\\' && i + 1 < input.length && input[i + 1] === quote) {\r\n value += '\\\\' + quote;\r\n i += 2;\r\n } else {\r\n value += input[i];\r\n i++;\r\n }\r\n }\r\n\r\n if (i < input.length) {\r\n value += quote;\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Constant, value });\r\n continue;\r\n }\r\n\r\n // Handle numeric constants\r\n if (/[0-9]/.test(char)) {\r\n let value = '';\r\n let hasDecimal = false;\r\n\r\n while (i < input.length && (/[0-9]/.test(input[i]) || (input[i] === '.' && !hasDecimal))) {\r\n if (input[i] === '.') {\r\n hasDecimal = true;\r\n }\r\n value += input[i];\r\n i++;\r\n }\r\n\r\n tokens.push({ type: TokenType.Constant, value });\r\n continue;\r\n }\r\n\r\n // Handle identifiers (variables and function calls with property/array access)\r\n if (/[a-zA-Z_$]/.test(char)) {\r\n let value = '';\r\n let isFunctionCall = false;\r\n\r\n // Capture identifier, including dots and bracket access\r\n while (i < input.length) {\r\n if (/[a-zA-Z0-9_$.]/.test(input[i])) {\r\n value += input[i];\r\n i++;\r\n } else if (input[i] === '[') {\r\n // Include array index expression like [0] or ['key']\r\n let bracketCount = 1;\r\n value += input[i++];\r\n while (i < input.length && bracketCount > 0) {\r\n if (input[i] === '[') bracketCount++;\r\n if (input[i] === ']') bracketCount--;\r\n value += input[i++];\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n\r\n // Skip whitespace to check for function call\r\n let wsCount = 0;\r\n while (i < input.length && /\\s/.test(input[i])) {\r\n wsCount++;\r\n i++;\r\n }\r\n\r\n // Check if this is a function call\r\n if (i < input.length && input[i] === '(') {\r\n isFunctionCall = true;\r\n\r\n value += '(';\r\n i++;\r\n\r\n let parenCount = 1;\r\n while (i < input.length && parenCount > 0) {\r\n if (input[i] === '(') parenCount++;\r\n if (input[i] === ')') parenCount--;\r\n value += input[i++];\r\n }\r\n } else {\r\n // Restore skipped whitespace\r\n i -= wsCount;\r\n }\r\n\r\n const lastToken = tokens[tokens.length - 1];\r\n const isDotAfterConstant = input[i - value.length - 1] === '.' && lastToken?.type === TokenType.Constant;\r\n\r\n tokens.push({\r\n type: isFunctionCall || isDotAfterConstant ? TokenType.FunctionCall : TokenType.Variable,\r\n value\r\n });\r\n continue;\r\n }\r\n\r\n // Handle operators and other characters\r\n i++;\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n/** Functions */\r\n\r\nexport type ArgToken =\r\n | { type: 'number'; value: number }\r\n | { type: 'string'; value: string }\r\n | { type: 'identifier'; value: string };\r\n\r\nexport function tokenizeArgs(input: string): ArgToken[] {\r\n const tokens: ArgToken[] = [];\r\n\r\n const start = input.indexOf('(');\r\n const end = input.lastIndexOf(')');\r\n if (start === -1 || end === -1 || end <= start) {\r\n throw new Error('Invalid function call syntax');\r\n }\r\n\r\n const argsStr = input.slice(start + 1, end);\r\n let i = 0;\r\n\r\n while (i < argsStr.length) {\r\n const char = argsStr[i];\r\n\r\n if (/\\s/.test(char)) {\r\n i++;\r\n continue;\r\n }\r\n\r\n if (char === '\"' || char === \"'\") {\r\n const quoteType = char;\r\n let value = '';\r\n i++;\r\n while (i < argsStr.length && argsStr[i] !== quoteType) {\r\n if (argsStr[i] === '\\\\') {\r\n i++;\r\n if (i < argsStr.length) {\r\n value += argsStr[i];\r\n }\r\n } else {\r\n value += argsStr[i];\r\n }\r\n i++;\r\n }\r\n if (i >= argsStr.length) {\r\n throw new Error('Unterminated string in arguments');\r\n }\r\n\r\n i++; // skip closing quote\r\n tokens.push({ type: 'string', value });\r\n continue;\r\n }\r\n\r\n\r\n if (/[0-9]/.test(char)) {\r\n let numStr = '';\r\n while (i < argsStr.length && /[0-9.]/.test(argsStr[i])) {\r\n numStr += argsStr[i];\r\n i++;\r\n }\r\n tokens.push({ type: 'number', value: parseFloat(numStr) });\r\n continue;\r\n }\r\n\r\n if (/[a-zA-Z_]/.test(char)) {\r\n let ident = '';\r\n while (i < argsStr.length && /[a-zA-Z0-9_\\.]/.test(argsStr[i])) {\r\n ident += argsStr[i];\r\n i++;\r\n }\r\n tokens.push({ type: 'identifier', value: ident });\r\n continue;\r\n }\r\n\r\n if (char === ',') {\r\n i++;\r\n continue;\r\n }\r\n\r\n throw new Error(`Unexpected character in arguments: ${char}`);\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n/** For STRING/MUSTACHE */\r\n\r\nexport type MustacheTokenType = 'string' | 'mustache';\r\n\r\n/**\r\n * Represents a token extracted from a template string\r\n * @typedef {Object} MustahceToken\r\n * @property {MustacheTokenType} type - Either 'string' for plain text or 'mustache' for mustache expressions\r\n * @property {string} value - The actual content of the token\r\n */\r\nexport interface MustacheToken {\r\n type: MustacheTokenType;\r\n value: string;\r\n}\r\n\r\n/**\r\n * Tokenizes a template string into an array of string and mustache tokens\r\n * @param {string} template - The template string containing text and mustache expressions\r\n * @returns {MustacheToken[]} An array of tokens representing the parsed template\r\n *\r\n * @example\r\n * // Returns tokens for a simple greeting template\r\n * tokenizeTemplate(\"Hello, {{name}}!\");\r\n * // [\r\n * // { type: 'string', value: 'Hello, ' },\r\n * // { type: 'mustache', value: '{{name}}' },\r\n * // { type: 'string', value: '!' }\r\n * // ]\r\n */\r\nexport function tokenizeMustache(template: string): MustacheToken[] {\r\n const tokens: MustacheToken[] = [];\r\n let currentIndex = 0;\r\n\r\n while (currentIndex < template.length) {\r\n const openTagIndex = template.indexOf('{{', currentIndex);\r\n\r\n if (openTagIndex === -1) {\r\n tokens.push(createStringToken(template.slice(currentIndex)));\r\n break;\r\n }\r\n\r\n if (openTagIndex > currentIndex) {\r\n tokens.push(createStringToken(template.slice(currentIndex, openTagIndex)));\r\n }\r\n\r\n const { value: mustache, endIndex, balanced } = extractMustache(template, openTagIndex);\r\n if (!balanced) {\r\n throw new Error(`Unclosed mustache tag starting at index ${openTagIndex}, template: ${template}`);\r\n }\r\n tokens.push(createMustacheToken(mustache));\r\n currentIndex = endIndex;\r\n }\r\n\r\n return tokens;\r\n}\r\n\r\nfunction createStringToken(value: string): MustacheToken {\r\n return { type: 'string', value };\r\n}\r\n\r\nfunction createMustacheToken(value: string): MustacheToken {\r\n return { type: 'mustache', value };\r\n}\r\n\r\nfunction extractMustache(template: string, startIndex: number): {\r\n value: string;\r\n endIndex: number;\r\n balanced: boolean;\r\n} {\r\n const open = '{{';\r\n const close = '}}';\r\n let i = startIndex + open.length;\r\n let depth = 1;\r\n\r\n while (i < template.length && depth > 0) {\r\n if (template.slice(i, i + open.length) === open) {\r\n depth++;\r\n i += open.length;\r\n } else if (template.slice(i, i + close.length) === close) {\r\n depth--;\r\n i += close.length;\r\n } else {\r\n i++;\r\n }\r\n }\r\n\r\n const balanced = depth === 0;\r\n const endIndex = balanced ? i : template.length;\r\n const value = template.slice(startIndex, endIndex);\r\n\r\n return { value, endIndex, balanced };\r\n}\r\n", "import { defaultPipes, PipeFunction, PipeRegistry } from \"../pipes\";\r\nimport { createAccessor } from \"./accessorParser\";\r\nimport {\r\n MustacheToken,\r\n Token,\r\n tokenize,\r\n tokenizeArgs,\r\n tokenizeMustache,\r\n TokenType,\r\n} from \"./tokenizer\";\r\n\r\nexport type RenderTemplate = (data: Record<string, any>, component?: any) => string;\r\ntype ResolveValue = (data: Record<string, any>, component?: any) => any;\r\ntype ResolveFunctionValue = (data: Record<string, any>, component: any) => any;\r\ntype RenderPart = (data: Record<string, any>, component: any) => string;\r\n\r\nexport interface TemplateParserOptions {\r\n pipeRegistry?: PipeRegistry;\r\n}\r\n\r\ninterface ExpressionChain {\r\n source: ResolveValue;\r\n pipes: PipeFunction[];\r\n}\r\n\r\nexport function compileMustard(template: string, options?: TemplateParserOptions): RenderTemplate {\r\n const segments: RenderPart[] = tokenizeMustache(template).map(token =>\r\n token.type === \"string\"\r\n ? (_data, _component) => token.value\r\n : compileExpression(token, options)\r\n );\r\n\r\n return (data, component) => segments.map(fn => fn(data, component)).join(\"\");\r\n}\r\n\r\nfunction compileExpression(token: MustacheToken, options?: TemplateParserOptions): RenderPart {\r\n const tokens = tokenize(token.value);\r\n const chain = buildExpressionChain(tokens, token.value, options?.pipeRegistry);\r\n return renderFromChain(chain);\r\n}\r\n\r\nfunction buildExpressionChain(\r\n tokens: Token[],\r\n sourceText: string,\r\n pipeRegistry?: PipeRegistry\r\n): ExpressionChain {\r\n let chain: ExpressionChain | null = null;\r\n if (!pipeRegistry){\r\n pipeRegistry = defaultPipes;\r\n }\r\n\r\n for (const token of tokens) {\r\n switch (token.type) {\r\n case TokenType.Constant:\r\n throw Error(`Constants not supported: ${token.value}`);\r\n\r\n case TokenType.Variable: {\r\n const accessor = createAccessor(token.value);\r\n chain = { source: accessor, pipes: [] };\r\n break;\r\n }\r\n\r\n case TokenType.FunctionCall: {\r\n const func = resolveFunction(token.value);\r\n chain = {\r\n source: func,\r\n pipes: []\r\n };\r\n break;\r\n }\r\n\r\n case TokenType.Pipe: {\r\n if (!chain) throw Error(`Pipe '${token.value}' has no input expression in: ${sourceText}`);\r\n if (!token.value || token.value === ''){\r\n throw Error('Pipe symbol was provided, but no pipes. Template: ' + sourceText);\r\n }\r\n\r\n const [pipeName, ...args] = token.value.split(':').map((p) => p.trim());\r\n const pipe = pipeRegistry.lookup(pipeName);\r\n if (!pipe) throw Error(`Pipe not found: ${pipeName}`);\r\n chain.pipes.push(value => pipe(value, args));\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!chain) throw Error(`Invalid expression: ${sourceText}`);\r\n return chain;\r\n}\r\n\r\nfunction renderFromChain(chain: ExpressionChain): RenderPart {\r\n return (data, component) => {\r\n const initial = chain.source(data, component);\r\n const result = chain.pipes.reduce((acc, fn) => fn(acc), initial);\r\n return result != null ? result.toString() : \"\";\r\n };\r\n}\r\n\r\nfunction resolveFunction(expression: string): ResolveFunctionValue {\r\n const pos = expression.indexOf(\"(\");\r\n if (pos === -1) throw Error(`Invalid function: ${expression}`);\r\n\r\n const args = tokenizeArgs(expression);\r\n const resolvedArgs: ((data: Record<string, any>) => any)[] = args.map(arg => {\r\n if (arg.type === \"number\" || arg.type === \"string\") return () => arg.value;\r\n if (arg.type === \"identifier\") return data => createAccessor(arg.value)(data);\r\n throw Error(`Unsupported argument type: ${(arg as any).type}`);\r\n });\r\n\r\n const name = expression.substring(0, pos);\r\n const fnAccessor = createAccessor(name);\r\n\r\n return (data, component) => {\r\n if (!component) throw Error(`Component context is required for calling '${name}'`);\r\n const fn = fnAccessor(component);\r\n if (typeof fn !== \"function\") throw Error(`Resolved '${name}' is not a function`);\r\n const evaluatedArgs = resolvedArgs.map(argFn => argFn(data));\r\n return fn.apply(component, evaluatedArgs);\r\n };\r\n}\r\n", "import { compileMustard } from \"./parseTemplate\";\r\nimport { ArgToken, tokenizeArgs } from \"./tokenizer\";\r\n\r\ntype RawBinding =\r\n | {\r\n type: 'text';\r\n path: number[];\r\n func: (context: Record<string, any>, component: Record<string, any>, node: Node) => void;\r\n }\r\n | {\r\n type: 'attribute';\r\n path: number[];\r\n name: string;\r\n func: (context: Record<string, any>, component: Record<string, any>, element: HTMLElement) => void;\r\n };\r\n\r\ntype ClickBinding = {\r\n path: number[];\r\n methodName: string;\r\n argTokens: ArgToken[];\r\n};\r\n\r\ntype BoundBinding =\r\n | {\r\n type: 'text';\r\n node: Node;\r\n func: (context: Record<string, any>, node: Node) => void;\r\n }\r\n | {\r\n type: 'attribute';\r\n element: HTMLElement;\r\n name: string;\r\n func: (context: Record<string, any>, element: HTMLElement) => void;\r\n };\r\n\r\nexport class BoundNode {\r\n constructor(\r\n private readonly root: HTMLElement,\r\n private readonly bindings: BoundBinding[],\r\n private readonly clickBindings: ClickBinding[],\r\n private readonly component?: Record<string, any>\r\n ) { }\r\n\r\n render(data: Record<string, any>): HTMLElement {\r\n for (const binding of this.bindings) {\r\n if (binding.type === 'text') {\r\n binding.func(data, binding.node);\r\n } else {\r\n binding.func(data, binding.element);\r\n }\r\n }\r\n\r\n for (const click of this.clickBindings) {\r\n const node = this.getNodeAtPath(this.root, click.path);\r\n const method = this.component?.[click.methodName];\r\n\r\n if (node instanceof HTMLElement && typeof method === 'function') {\r\n node.onclick = (evt: Event) => {\r\n const args = click.argTokens.map(token => {\r\n if (token.type === 'number' || token.type === 'string') {\r\n return token.value;\r\n }\r\n if (token.type === 'identifier') {\r\n if (token.value === 'event') {\r\n return evt;\r\n }\r\n\r\n const parts = token.value.split('.');\r\n return parts.reduce((obj, key) => obj?.[key], data);\r\n }\r\n });\r\n method.apply(this.component, args);\r\n };\r\n }\r\n }\r\n\r\n return this.root;\r\n }\r\n\r\n private getNodeAtPath(root: Node, path: number[]): Node {\r\n return path.reduce((node, index) => node.childNodes[index], root);\r\n }\r\n}\r\n\r\nexport function createBluePrint(html: string): Blueprint {\r\n var bp = new Blueprint(html);\r\n return bp;\r\n}\r\n\r\nexport class Blueprint {\r\n private readonly template: HTMLTemplateElement;\r\n private readonly bindings: RawBinding[];\r\n private readonly clickBindings: ClickBinding[];\r\n\r\n constructor(htmlOrTemplate: string | HTMLTemplateElement) {\r\n if (typeof htmlOrTemplate === 'string') {\r\n const trimmed = htmlOrTemplate.trim();\r\n if (trimmed.startsWith('<template')) {\r\n const wrapper = document.createElement('div');\r\n wrapper.innerHTML = trimmed;\r\n const found = wrapper.querySelector('template');\r\n if (!found) throw new Error('Could not find <template> in input string');\r\n this.template = found;\r\n } else {\r\n this.template = document.createElement('template');\r\n this.template.innerHTML = trimmed;\r\n }\r\n } else {\r\n this.template = htmlOrTemplate;\r\n }\r\n\r\n const rootElement = this.getRootElement();\r\n this.bindings = this.collectBindings(rootElement);\r\n this.clickBindings = this.collectClickBindings(rootElement);\r\n }\r\n\r\n createInstance(component?: Record<string, any>): BoundNode {\r\n const rootClone = this.getRootElement().cloneNode(true) as HTMLElement;\r\n\r\n const boundBindings: BoundBinding[] = this.bindings.map(binding => {\r\n const node = this.getNodeAtPath(rootClone, binding.path);\r\n if (binding.type === 'text') {\r\n return {\r\n type: 'text',\r\n node,\r\n func: (data, node) => binding.func(data, component, node)\r\n };\r\n } else {\r\n return {\r\n type: 'attribute',\r\n element: node as HTMLElement,\r\n name: binding.name,\r\n func: (data, node) => binding.func(data, component, node)\r\n };\r\n }\r\n });\r\n\r\n return new BoundNode(rootClone, boundBindings, this.clickBindings, component);\r\n }\r\n\r\n private getRootElement(): HTMLElement {\r\n const el = Array.from(this.template.content.childNodes).find(\r\n node => node.nodeType === Node.ELEMENT_NODE\r\n );\r\n if (!(el instanceof HTMLElement)) {\r\n throw new Error('Template must contain a single root element');\r\n }\r\n return el;\r\n }\r\n\r\n private collectBindings(root: HTMLElement): RawBinding[] {\r\n const bindings: RawBinding[] = [];\r\n\r\n const walk = (node: Node, path: number[] = []) => {\r\n if (node.nodeType === Node.TEXT_NODE && node.textContent) {\r\n if (node.textContent.match(/\\{\\{\\s*(.*?)\\s*\\}\\}/g)) {\r\n const func = compileMustard(node.textContent);\r\n bindings.push({\r\n type: 'text',\r\n path: [...path],\r\n func: (data, component, targetNode) => {\r\n targetNode.textContent = func(data, component);\r\n }\r\n });\r\n }\r\n }\r\n\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n\r\n if (element.tagName === 'TEMPLATE') return;\r\n\r\n for (let i = 0; i < element.attributes.length; i++) {\r\n const attr = element.attributes[i];\r\n if (attr.value.match(/\\{\\{\\s*(.*?)\\s*\\}\\}/g)) {\r\n const func = compileMustard(attr.value);\r\n bindings.push({\r\n type: 'attribute',\r\n path: [...path],\r\n name: attr.name,\r\n func: (data, component, el) => {\r\n el.setAttribute(attr.name, func(data, component));\r\n }\r\n });\r\n }\r\n }\r\n\r\n Array.from(node.childNodes).forEach((child, index) => {\r\n walk(child, [...path, index]);\r\n });\r\n }\r\n };\r\n\r\n walk(root);\r\n return bindings;\r\n }\r\n\r\n private collectClickBindings(root: Node): ClickBinding[] {\r\n const bindings: ClickBinding[] = [];\r\n\r\n const walk = (node: Node, path: number[] = []) => {\r\n if (node.nodeType === Node.ELEMENT_NODE) {\r\n const element = node as HTMLElement;\r\n const clickAttr = element.getAttribute('click');\r\n if (clickAttr?.trim()) {\r\n const trimmed = clickAttr.trim();\r\n\r\n const match = trimmed.match(/^([a-zA-Z_$][\\w$]*)\\s*\\((.*)\\)$/);\r\n if (match) {\r\n const methodName = match[1];\r\n const argTokens = tokenizeArgs(trimmed);\r\n bindings.push({ path: [...path], methodName, argTokens });\r\n } else {\r\n // No parentheses \u2014 treat as method with no args\r\n bindings.push({ path: [...path], methodName: trimmed, argTokens: [] });\r\n }\r\n }\r\n\r\n Array.from(node.childNodes).forEach((child, index) => {\r\n walk(child, [...path, index]);\r\n });\r\n }\r\n };\r\n\r\n walk(root);\r\n return bindings;\r\n }\r\n\r\n private getNodeAtPath(root: Node, path: number[]): Node {\r\n return path.reduce((node, index) => node.childNodes[index], root);\r\n }\r\n}\r\n", "export class TableRenderer {\r\n private table: HTMLTableElement;\r\n private template: HTMLTemplateElement;\r\n private component: HTMLElement;\r\n private dataMap = new Map<string, Record<string, any>>();\r\n private rowMap = new Map<string, HTMLTableRowElement>();\r\n\r\n public IdColumn: string;\r\n\r\n constructor(\r\n table: HTMLTableElement,\r\n template: HTMLTemplateElement,\r\n idColumn: string,\r\n component: HTMLElement\r\n ) {\r\n this.table = table;\r\n this.template = template;\r\n this.IdColumn = idColumn;\r\n this.component = component;\r\n }\r\n\r\n public render(data: Record<string, any>[]) {\r\n this.clearRows();\r\n for (const item of data) {\r\n this.renderRow(item);\r\n }\r\n }\r\n\r\n private clearRows(): void {\r\n this.table.tBodies[0].innerHTML = '';\r\n this.dataMap.clear();\r\n this.rowMap.clear();\r\n }\r\n\r\n private renderRow(data: Record<string, any>): void {\r\n const id = data[this.IdColumn];\r\n if (id === undefined || id === null) {\r\n throw new Error(`Missing IdColumn '${this.IdColumn}' in data`);\r\n }\r\n\r\n const row = this.template.content.firstElementChild?.cloneNode(true) as HTMLTableRowElement;\r\n if (!row) throw new Error(\"Template must have a <tr> as its first child\");\r\n\r\n this.populateRow(row, data);\r\n this.attachEventHandlers(row, data);\r\n\r\n this.table.tBodies[0].appendChild(row);\r\n this.dataMap.set(id, data);\r\n this.rowMap.set(id, row);\r\n }\r\n\r\n private populateRow(row: HTMLTableRowElement, data: Record<string, any>): void {\r\n const cells = row.querySelectorAll('[data-field]');\r\n cells.forEach((cell) => {\r\n const field = (cell as HTMLElement).dataset.field;\r\n if (field && field in data) {\r\n cell.textContent = String(data[field]);\r\n }\r\n });\r\n }\r\n\r\n private attachEventHandlers(row: HTMLElement, data: Record<string, any>): void {\r\n const interactiveElements = row.querySelectorAll('[onclick]');\r\n interactiveElements.forEach((el) => {\r\n const element = el as HTMLElement;\r\n const handlerAttr = element.getAttribute('onclick');\r\n if (!handlerAttr) return;\r\n\r\n const match = handlerAttr.match(/^(\\w+)(\\(([^)]*)\\))?$/);\r\n if (!match) return;\r\n\r\n const [, methodName, , argStr] = match;\r\n const args = argStr ? argStr.split(',').map(s => s.trim().replace(/^['\"]|['\"]$/g, '')) : [];\r\n\r\n if (typeof (this.component as any)[methodName] === 'function') {\r\n element.removeAttribute('onclick');\r\n element.addEventListener('click', (event) => {\r\n (this.component as any)[methodName](...args, data, event);\r\n });\r\n }\r\n });\r\n }\r\n\r\n public update(data: Record<string, any>) {\r\n const id = data[this.IdColumn];\r\n if (id === undefined || id === null) {\r\n throw new Error(`Missing IdColumn '${this.IdColumn}' in update data`);\r\n }\r\n\r\n const row = this.rowMap.get(id);\r\n if (!row) {\r\n this.renderRow(data);\r\n } else {\r\n this.populateRow(row, data);\r\n this.attachEventHandlers(row, data);\r\n this.dataMap.set(id, data);\r\n }\r\n }\r\n}\r\n\r\nexport class SortChangeEvent extends CustomEvent<SortColumn[]> {\r\n constructor(sortColumns: SortColumn[]) {\r\n super('sortchange', {\r\n detail: sortColumns,\r\n bubbles: true,\r\n composed: true,\r\n });\r\n }\r\n}\r\n\r\n\r\ntype SortDirection = 'asc' | 'desc';\r\nexport type SortColumn = { column: string; direction: SortDirection };\r\n\r\nexport class TableSorter {\r\n private table: HTMLTableElement;\r\n private sortColumns: SortColumn[] = [];\r\n private component: HTMLElement;\r\n\r\n constructor(table: HTMLTableElement, component: HTMLElement) {\r\n this.table = table;\r\n this.component = component;\r\n this.setupListeners();\r\n }\r\n\r\n private setupListeners() {\r\n const headers = this.table.tHead?.querySelectorAll('th[name]');\r\n headers?.forEach((th) => {\r\n th.addEventListener('click', () => {\r\n const column = th.getAttribute('name')!;\r\n this.toggle(column);\r\n this.updateSortIndicators();\r\n this.emit();\r\n });\r\n });\r\n }\r\n\r\n private toggle(column: string) {\r\n const index = this.sortColumns.findIndex(c => c.column === column);\r\n\r\n if (index === -1) {\r\n this.sortColumns.push({ column, direction: 'asc' });\r\n } else if (this.sortColumns[index].direction === 'asc') {\r\n this.sortColumns[index].direction = 'desc';\r\n } else {\r\n this.sortColumns.splice(index, 1);\r\n }\r\n }\r\n\r\n private emit() {\r\n const event = new SortChangeEvent(this.sortColumns);\r\n this.component.dispatchEvent(event);\r\n }\r\n\r\n private updateSortIndicators() {\r\n const headers = this.table.tHead?.querySelectorAll('th[name]');\r\n headers?.forEach((th: HTMLElement) => {\r\n // Remove existing indicators\r\n const existingIndicator = th.querySelector('.sort-indicator') as HTMLElement;\r\n if (existingIndicator) {\r\n th.removeChild(existingIndicator);\r\n }\r\n\r\n // Get column name and find if it's sorted\r\n const column = th.getAttribute('name')!;\r\n const sortInfo = this.sortColumns.find(c => c.column === column);\r\n \r\n if (sortInfo) {\r\n // Create indicator element\r\n const indicator = document.createElement('span');\r\n indicator.className = 'sort-indicator';\r\n indicator.textContent = sortInfo.direction === 'asc' ? '\u2191' : '\u2193';\r\n \r\n // Style for right alignment\r\n indicator.style.float = 'right';\r\n indicator.style.marginLeft = '5px';\r\n \r\n // Append to header\r\n th.appendChild(indicator);\r\n }\r\n \r\n // Ensure header is positioned relatively for absolute positioning if needed\r\n if (!th.style.position) {\r\n th.style.position = 'relative';\r\n }\r\n });\r\n }\r\n\r\n public getSortColumns(): SortColumn[] {\r\n return [...this.sortColumns];\r\n }\r\n\r\n public clear() {\r\n this.sortColumns = [];\r\n this.updateSortIndicators();\r\n this.emit();\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLTableElementEventMap extends HTMLElementEventMap {\r\n 'sortchange': SortChangeEvent;\r\n }\r\n\r\n interface HTMLTableElement {\r\n addEventListener<K extends keyof HTMLTableElementEventMap>(\r\n type: K,\r\n listener: (this: HTMLTableElement, ev: HTMLTableElementEventMap[K]) => any,\r\n options?: boolean | AddEventListenerOptions\r\n ): void;\r\n }\r\n}", "type WebComponentConstructor = new (...args: any[]) => HTMLElement;\r\n\r\nexport enum GuardResult {\r\n /**\r\n * Handle route without checking more guards.\r\n */\r\n Allow,\r\n\r\n /**\r\n * Throw a RouteGuardError.\r\n */\r\n Deny,\r\n\r\n /**\r\n * Resume and check other guards.\r\n */\r\n Continue,\r\n\r\n /**\r\n * Do not invoke the rooute nor other guards.\r\n */\r\n Stop\r\n}\r\n\r\nexport interface RouteGuard {\r\n check(route: RouteMatchResult): GuardResult;\r\n}\r\n\r\nexport interface Route {\r\n name?: string;\r\n target?: string;\r\n path: string;\r\n\r\n /**\r\n * HTML file name (without extension).\r\n *\r\n * Define for instance if you have a route that requires a more limited layout. The library\r\n * will automatically load that HTML file and rewrite URL history so that the correct url is displayed.\r\n */\r\n layout?: string;\r\n\r\n /**\r\n * Name of the tag for your web component.\r\n */\r\n componentTagName?: string;\r\n\r\n /**\r\n * Guards used to check if this route can be visited.\r\n */\r\n guards?: RouteGuard[];\r\n\r\n component?: WebComponentConstructor;\r\n}\r\n\r\nexport type RouteParamType = string | number;\r\nexport type RouteData = Record<string, RouteParamType>;\r\n\r\n/**\r\n * Implement to receive typed route parameters via a `routeData` property.\r\n * RouteTarget assigns `routeData` after element creation but before DOM insertion.\r\n * Optional since it's not available at construction time.\r\n *\r\n * For convention-based usage without undefined checks, skip the interface\r\n * and declare `routeData` directly on your component.\r\n *\r\n * @example\r\n * class UserProfile extends HTMLElement implements Routable<{ userName: string }> {\r\n * routeData?: { userName: string };\r\n * }\r\n */\r\nexport interface Routable<T extends RouteData = RouteData> {\r\n routeData?: T;\r\n}\r\n\r\n/**\r\n * Implement to run async initialization before the component is added to the DOM.\r\n * RouteTarget calls `loadRoute()` and awaits it before inserting the element.\r\n *\r\n * @example\r\n * class OrderDetail extends HTMLElement implements LoadRoute<{ orderId: number }> {\r\n * async loadRoute(data: { orderId: number }) {\r\n * this.order = await fetchOrder(data.orderId);\r\n * }\r\n * }\r\n */\r\nexport interface LoadRoute<T extends RouteData = RouteData> {\r\n loadRoute(data: T): void | Promise<void>;\r\n}\r\n\r\n/**\r\n * Result from route matching operations.\r\n * Contains all information needed for navigation and rendering.\r\n */\r\nexport type RouteMatchResult = {\r\n /**\r\n * Matched route configuration\r\n */\r\n route: Route;\r\n\r\n /**\r\n * URL segments used for history state\r\n */\r\n urlSegments: string[];\r\n\r\n /**\r\n * Extracted and type-converted parameters\r\n */\r\n params: RouteData;\r\n};\r\n\r\n/**\r\n * Supported types of route segments\r\n */\r\nexport type RouteSegmentType = 'string' | 'number' | 'path' | 'regex';\r\n\r\n/**\r\n * Strongly typed route segment value\r\n */\r\nexport interface RouteValue {\r\n /**\r\n * Type of parameter for validation\r\n */\r\n type: RouteSegmentType;\r\n\r\n /**\r\n * Actual parameter value\r\n */\r\n value: any;\r\n}\r\n\r\nexport class RouteError extends Error {}\r\nexport class RouteGuardError extends RouteError {\r\n isGuard;\r\n}\r\n\r\nexport interface NavigateOptions {\r\n /**\r\n * Optional parameters when using route name\r\n */\r\n params?: Record<string, string | number>;\r\n\r\n /**\r\n * override for route's default target\r\n */\r\n target?: string;\r\n\r\n /**\r\n * When you want to override routes from the globally registered ones.\r\n */\r\n routes?: Route[];\r\n}\r\n", "import type { Route, RouteData } from './types';\r\n\r\n/**\r\n * Event sent to routing targets when a new route should be displayed.\r\n */\r\nexport class NavigateRouteEvent extends Event {\r\n static NAME: string = 'rlx.navigateRoute';\r\n constructor(\r\n /**\r\n * Matched route.\r\n */\r\n public route: Route,\r\n\r\n /**\r\n * The generated url sements which can be used to push the url into the browser history.\r\n */\r\n public urlSegments: string[],\r\n\r\n /**\r\n * Data supplied to the route.\r\n */\r\n public routeData?: RouteData,\r\n\r\n /**\r\n * The target can differ from the default target that is defined in the route.\r\n *\r\n * undefined means that the default (unnamed) target should be used.\r\n */\r\n public routeTarget?: string,\r\n\r\n eventInit?: EventInit\r\n ) {\r\n super(NavigateRouteEvent.NAME, eventInit);\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementEventMap {\r\n 'rlx.navigateRoute': NavigateRouteEvent;\r\n }\r\n interface DocumentEventMap {\r\n 'rlx.navigateRoute': NavigateRouteEvent;\r\n }\r\n}\r\n", "import { reportError } from '../errors';\r\nimport { NavigateRouteEvent } from './NavigateRouteEvent';\r\n\r\ntype RouteTargetHandler = (evt: NavigateRouteEvent) => void;\r\nconst targetHandlers = new Map<string | undefined, RouteTargetHandler>();\r\nconst pendingEvents = new Map<string | undefined, NavigateRouteEvent>();\r\n\r\n/**\r\n * Registers a route target handler.\r\n * When a navigation event targets this name, the handler is called directly.\r\n * If a pending event exists for this target, it is replayed immediately.\r\n *\r\n * @param name - Target name, or `undefined` for the default (unnamed) target\r\n * @param handler - Callback that receives the `NavigateRouteEvent`\r\n *\r\n * @example\r\n * registerRouteTarget('sidebar', (evt) => renderComponent(evt));\r\n */\r\nexport function registerRouteTarget(\r\n name: string | undefined,\r\n handler: RouteTargetHandler,\r\n) {\r\n initRouteTargetListener();\r\n if (targetHandlers.has(name)) {\r\n const error = reportError('Duplicate route target', {\r\n target: name ?? 'default',\r\n });\r\n if (error) throw error;\r\n return;\r\n }\r\n targetHandlers.set(name, handler);\r\n\r\n const pending = pendingEvents.get(name);\r\n if (pending) {\r\n pendingEvents.delete(name);\r\n handler(pending);\r\n }\r\n}\r\n\r\n/**\r\n * Unregisters a previously registered route target handler.\r\n *\r\n * @param name - Target name that was passed to `registerRouteTarget`\r\n */\r\nexport function unregisterRouteTarget(name: string | undefined) {\r\n targetHandlers.delete(name);\r\n}\r\n\r\nexport function clearPendingNavigations() {\r\n pendingEvents.clear();\r\n targetHandlers.clear();\r\n}\r\n\r\nfunction dispatchToTarget(evt: NavigateRouteEvent) {\r\n const handler = targetHandlers.get(evt.routeTarget);\r\n if (handler) {\r\n handler(evt);\r\n } else {\r\n pendingEvents.set(evt.routeTarget, evt);\r\n }\r\n}\r\n\r\nlet listenerAttached = false;\r\n\r\nexport function initRouteTargetListener() {\r\n if (listenerAttached) return;\r\n listenerAttached = true;\r\n document.addEventListener(NavigateRouteEvent.NAME, (evt) => {\r\n dispatchToTarget(evt as NavigateRouteEvent);\r\n });\r\n}\r\n", "import type { Route, RouteData, RouteParamType, RouteMatchResult } from './types';\r\n\r\n/**\r\n * Route segment matcher interface.\r\n * Each segment type (string, number, path) implements this\r\n * for parameter extraction and validation.\r\n */\r\ninterface RouteSegment {\r\n /**\r\n * Parameter name when segment is dynamic (:name or ;id)\r\n */\r\n paramName?: string;\r\n\r\n /**\r\n * Validates if URL segment matches pattern\r\n * @param value Segment from URL to validate\r\n */\r\n isMatch(value: string): boolean;\r\n\r\n /**\r\n * Converts URL segment to typed parameter\r\n * @param pathValue Raw value from URL\r\n */\r\n getValue(pathValue: string): RouteParamType;\r\n}\r\n\r\n/**\r\n * Number parameter segment matcher.\r\n * Used for ;id style parameters that must be numbers.\r\n */\r\nclass NumberRouteSegment implements RouteSegment {\r\n constructor(public paramName: string) {}\r\n isMatch(value: string): boolean {\r\n if (/^\\d+$/.test(value)) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n getValue(pathValue: string): RouteParamType {\r\n if (/^\\d+$/.test(pathValue) === false) {\r\n throw new Error(\r\n `Path is not a number, parameter name '${this.paramName}', value: '${pathValue}'.`\r\n );\r\n }\r\n return parseInt(pathValue);\r\n }\r\n}\r\n\r\n/**\r\n * String parameter segment matcher.\r\n * Used for :name style parameters.\r\n */\r\nclass StringRouteSegment implements RouteSegment {\r\n constructor(public paramName: string) {}\r\n isMatch(value: string): boolean {\r\n return true;\r\n }\r\n\r\n /**\r\n *\r\n * @param pathValue the route data (for route by name) or segment extracted from the url (for url routing).\r\n * @returns\r\n */\r\n getValue(pathValue: string): RouteParamType {\r\n return pathValue;\r\n }\r\n}\r\n\r\n/**\r\n * Static path segment matcher.\r\n * Used for fixed URL parts like 'users' in /users/:id\r\n */\r\nclass PathRouteSegment implements RouteSegment {\r\n constructor(public value: string) {}\r\n isMatch(value: string): boolean {\r\n return value == this.value;\r\n }\r\n\r\n getValue(_pathValue: string): RouteParamType {\r\n return this.value;\r\n }\r\n}\r\n\r\n/**\r\n * Internal route implementation that handles segment matching\r\n * and parameter extraction.\r\n */\r\nclass RouteImp {\r\n constructor(public route: Route, private segments: RouteSegment[]) {}\r\n\r\n /**\r\n * Attempts to match URL segments against route pattern\r\n * @param segments URL parts to match\r\n * @returns Match result with parameters if successful\r\n */\r\n match(segments: string[]): RouteMatchResult | null {\r\n if (segments.length != this.segments.length) {\r\n return null;\r\n }\r\n\r\n const generatedSegments: string[] = [];\r\n var params: RouteData = {};\r\n for (let index = 0; index < segments.length; index++) {\r\n const urlSegment = segments[index];\r\n const ourSegment = this.segments[index];\r\n\r\n if (!ourSegment.isMatch(urlSegment)) {\r\n return null;\r\n }\r\n\r\n if (ourSegment.paramName) {\r\n const value = ourSegment.getValue(urlSegment);\r\n params[ourSegment.paramName] = value;\r\n generatedSegments.push(value.toString());\r\n } else {\r\n generatedSegments.push(urlSegment);\r\n }\r\n }\r\n\r\n return { route: this.route, params, urlSegments: generatedSegments };\r\n }\r\n\r\n /**\r\n * Routing by name and route data, so generate the url segments.\r\n * @param routeData Data to use in the URL.\r\n * @returns Match result with parameters if successful\r\n */\r\n buildUrl(routeData: RouteData): RouteMatchResult | null {\r\n const urlSegments: string[] = [];\r\n for (let index = 0; index < this.segments.length; index++) {\r\n const ourSegment = this.segments[index];\r\n if (ourSegment.paramName) {\r\n var value = routeData[ourSegment.paramName];\r\n if (!value) {\r\n throw new Error(\r\n `Route \"${\r\n this.route.name\r\n }\" did not get value for parameter \"${\r\n ourSegment.paramName\r\n } from the provided routeData: \"${JSON.stringify(\r\n routeData\r\n )}\".`\r\n );\r\n }\r\n\r\n urlSegments.push(value.toString());\r\n } else {\r\n urlSegments.push(ourSegment.getValue('').toString());\r\n }\r\n }\r\n\r\n return { route: this.route, params: routeData, urlSegments };\r\n }\r\n\r\n /**\r\n * Converts string parameters to proper types\r\n * @param routeParams Raw string parameters to convert\r\n */\r\n parseParameters(routeParams: Record<string, string>): RouteData {\r\n const d: Record<string, any> = {};\r\n\r\n this.segments.forEach((segment) => {\r\n if (!segment.paramName) {\r\n return;\r\n }\r\n\r\n if (!segment.isMatch(providedValue)) {\r\n throw new Error(\r\n `Failed to convert parameter ${segment.paramName}, or missing value: ${providedValue}, route: ${this.route.name}.`\r\n );\r\n }\r\n\r\n var providedValue = routeParams[segment.paramName];\r\n if (!providedValue) {\r\n throw new Error(\r\n `Parameter ${segment.paramName} was not provided, route: ${this.route.name}.`\r\n );\r\n }\r\n\r\n var convertedValue = segment.getValue(providedValue);\r\n d[segment.paramName] = convertedValue;\r\n });\r\n\r\n return d;\r\n }\r\n}\r\n\r\n/**\r\n * Match route by either name or URL pattern\r\n * @param routes Available routes\r\n * @param routeNameOrUrl Route name or URL to match\r\n * @param routeData Optional parameters for named routes\r\n */\r\nexport function matchRoute(\r\n routes: Route[],\r\n routeNameOrUrl: string,\r\n routeData?: Record<string, string | any>\r\n): RouteMatchResult | null {\r\n if (routeNameOrUrl === '' || routeNameOrUrl.indexOf('/') >= 0) {\r\n return findRouteByUrl(routes, routeNameOrUrl || '/');\r\n } else {\r\n return findRouteByName(routes, routeNameOrUrl, routeData!);\r\n }\r\n}\r\n\r\n/**\r\n * Find route by name and apply parameters\r\n * @param routes Available routes\r\n * @param name Route name to find\r\n * @param routeData Parameters to apply\r\n */\r\nexport function findRouteByName(\r\n routes: Route[],\r\n name: string,\r\n routeData?: Record<string, string | any>\r\n): RouteMatchResult | null {\r\n var route = routes.find((x) => x.name === name);\r\n if (!route) {\r\n return null;\r\n }\r\n\r\n var imp = generateRouteImp(route);\r\n var result = imp.buildUrl(routeData);\r\n return result;\r\n}\r\n\r\n/**\r\n * Find route matching URL pattern\r\n * @param routes Available routes\r\n * @param path URL to match\r\n */\r\nexport function findRouteByUrl(\r\n routes: Route[],\r\n path: string\r\n): RouteMatchResult | null {\r\n const urlSegments = path.replace(/^\\/|\\/$/g, '').split('/');\r\n const routeImps = generateRouteImps(routes);\r\n\r\n for (let index = 0; index < routeImps.length; index++) {\r\n const element = routeImps[index];\r\n const m = element.match(urlSegments);\r\n if (m) {\r\n return m;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Generate implementations for all routes\r\n */\r\nfunction generateRouteImps(routes: Route[]) {\r\n const routeImps: RouteImp[] = [];\r\n routes.forEach((route) => {\r\n var imp = generateRouteImp(route);\r\n routeImps.push(imp);\r\n });\r\n\r\n return routeImps;\r\n}\r\n\r\n/**\r\n * Generate implementation for single route\r\n * Parses URL pattern into segment matchers\r\n */\r\nfunction generateRouteImp(route: Route): RouteImp {\r\n var impSegments = [];\r\n const segments = route.path.replace(/^\\/|\\/$/g, '').split('/');\r\n segments.forEach((segment) => {\r\n if (segment.substring(0, 1) == ':') {\r\n impSegments.push(new StringRouteSegment(segment.substring(1)));\r\n } else if (segment.substring(0, 1) === ';') {\r\n impSegments.push(new NumberRouteSegment(segment.substring(1)));\r\n } else if (segment.substring(0, 1) === '{') {\r\n } else {\r\n impSegments.push(new PathRouteSegment(segment));\r\n }\r\n });\r\n\r\n var imp = new RouteImp(route, impSegments);\r\n return imp;\r\n}\r\n", "import { navigate, printRoutes } from './navigation';\r\nimport { RelaxError, reportError } from '../errors';\r\n\r\nexport class RouteLink extends HTMLElement {\r\n static get observedAttributes() {\r\n return ['name', 'target', 'params'];\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.addEventListener('click', e => this.handleClick(e));\r\n }\r\n\r\n private handleClick(e: MouseEvent) {\r\n e.preventDefault();\r\n \r\n const name = this.getAttribute('name');\r\n if (!name) return;\r\n\r\n console.log('Calling printRoutes from RouteLink in relaxjs/components');\r\n printRoutes();\r\n \r\n const params: Record<string, string> = {};\r\n for (const attr of Array.from(this.attributes)) {\r\n if (attr.name.startsWith('param-')) {\r\n const paramName = attr.name.substring(6);\r\n params[paramName] = attr.value;\r\n }\r\n }\r\n\r\n const paramsAttr = this.getAttribute('params');\r\n let additionalParams: Record<string, string | number> | undefined;\r\n if (paramsAttr) {\r\n try {\r\n const parsed = JSON.parse(paramsAttr);\r\n additionalParams = parsed as Record<string, string | number>;\r\n } catch (error) {\r\n const err = reportError('Failed to parse route params', {\r\n element: 'r-link',\r\n params: paramsAttr,\r\n cause: error,\r\n });\r\n if (err) throw err;\r\n }\r\n }\r\n\r\n const target = this.getAttribute('target');\r\n if (additionalParams){\r\n Object.assign(params, additionalParams);\r\n }\r\n\r\n try {\r\n navigate(name, { params, target: target || undefined });\r\n } catch (error) {\r\n if (error instanceof RelaxError) throw error;\r\n const reported = reportError('Navigation failed', {\r\n element: 'r-link',\r\n route: name,\r\n params,\r\n target,\r\n cause: error,\r\n });\r\n if (reported) throw reported;\r\n }\r\n }\r\n\r\n connectedCallback() {\r\n if (!this.hasAttribute('tabindex')) {\r\n this.setAttribute('tabindex', '0');\r\n }\r\n \r\n this.style.cursor = 'pointer';\r\n this.role = 'link';\r\n }\r\n\r\n disconnectedCallback() {\r\n this.removeEventListener('click', this.handleClick);\r\n }\r\n}", "import { registerRouteTarget, unregisterRouteTarget } from './routeTargetRegistry';\r\nimport type { NavigateRouteEvent } from './NavigateRouteEvent';\r\nimport type { RouteData, LoadRoute } from './types';\r\nimport { RelaxError, reportError } from '../errors';\r\n\r\n/**\r\n * WebComponent that listens on the `NavigateRouteEvent` event to be able to switch route.\r\n *\r\n * Use the \"name\" attribute to make this non-default target.\r\n * Use the \"dialog\" attribute to render routes inside a native `<dialog>` element\r\n * with built-in focus trapping, backdrop, and Escape-to-close.\r\n *\r\n * @example\r\n * <r-route-target></r-route-target>\r\n * <r-route-target name=\"modal\" dialog></r-route-target>\r\n */\r\nexport class RouteTarget extends HTMLElement {\r\n name?: string = undefined;\r\n private dialog?: HTMLDialogElement;\r\n\r\n connectedCallback() {\r\n this.name = this.getAttribute('name') ?? undefined;\r\n\r\n if (this.hasAttribute('dialog')) {\r\n this.dialog = document.createElement('dialog');\r\n this.dialog.addEventListener('close', () => {\r\n this.dialog!.replaceChildren();\r\n });\r\n this.appendChild(this.dialog);\r\n }\r\n\r\n registerRouteTarget(this.name, (evt) => this.onNavigate(evt));\r\n console.log('registered');\r\n }\r\n\r\n disconnectedCallback() {\r\n unregisterRouteTarget(this.name);\r\n }\r\n\r\n private onNavigate(evt: NavigateRouteEvent) {\r\n console.log('got nav', evt);\r\n this.loadComponent(evt).catch((error) => {\r\n if (!(error instanceof RelaxError)) {\r\n error = reportError('Route navigation failed', {\r\n route: evt.route.name,\r\n routeTarget: evt.routeTarget,\r\n cause: error,\r\n });\r\n }\r\n if (error) {\r\n console.error(error);\r\n }\r\n });\r\n }\r\n\r\n private async loadComponent(evt: NavigateRouteEvent) {\r\n const tagName = evt.route.componentTagName\r\n ?? customElements.getName(evt.route.component);\r\n\r\n if (!tagName) {\r\n const error = reportError('Failed to find component for route', {\r\n route: evt.route.name,\r\n componentTagName: evt.route.componentTagName,\r\n component: evt.route.component?.name,\r\n routeData: evt.routeData,\r\n });\r\n if (error) throw error;\r\n return;\r\n }\r\n\r\n await customElements.whenDefined(tagName);\r\n const element = document.createElement(tagName);\r\n\r\n await this.applyRouteData(element, evt.routeData);\r\n\r\n if (this.dialog) {\r\n this.dialog.replaceChildren(element);\r\n if (!this.dialog.open) {\r\n this.dialog.showModal();\r\n }\r\n } else if (document.startViewTransition) {\r\n document.startViewTransition(() => this.replaceChildren(element));\r\n } else {\r\n this.replaceChildren(element);\r\n }\r\n }\r\n\r\n /** Closes the dialog (only applies to dialog targets). */\r\n close() {\r\n this.dialog?.close();\r\n }\r\n\r\n private async applyRouteData(element: Element, data?: RouteData) {\r\n if ('loadRoute' in element) {\r\n const routeData = data\r\n ?? { error: 'loadRoute function without mapped route data in the routes' };\r\n await (element as unknown as LoadRoute).loadRoute(routeData);\r\n }\r\n\r\n if (data) {\r\n (element as any).routeData = data;\r\n }\r\n }\r\n}\r\n", "/**\r\n * Single Page Application routing system with multiple target support.\r\n * Designed for scenarios where you need:\r\n * - Multiple navigation targets (main content, modals, sidebars)\r\n * - Strongly typed route parameters\r\n * - History management with back/forward support\r\n *\r\n * @example\r\n * // Configure routes\r\n * const routes = [\r\n * { name: 'user', path: '/users/:id' }, // String parameter\r\n * { name: 'order', path: '/orders/;orderId' }, // Number parameter\r\n * { name: 'modal', path: '/detail/:id', target: 'modal' } // Custom target\r\n * ];\r\n */\r\n\r\nimport { reportError } from '../errors';\r\nimport {\r\n GuardResult,\r\n RouteError,\r\n RouteGuardError,\r\n type Route,\r\n type RouteData,\r\n type RouteParamType,\r\n type RouteMatchResult,\r\n type NavigateOptions,\r\n} from './types';\r\nimport { NavigateRouteEvent } from './NavigateRouteEvent';\r\nimport { matchRoute } from './routeMatching';\r\nimport { initRouteTargetListener } from './routeTargetRegistry';\r\nimport { RouteLink } from './RouteLink';\r\nimport { RouteTarget } from './RoutingTarget';\r\n\r\n/**\r\n * Used to keep track of current main HTML file,\r\n * used when different layouts are supported.\r\n *\r\n * The default page is ALWAYS loaded initially,\r\n * which means that we need to switch layout page\r\n * if someone else is configured for the route.\r\n */\r\nvar currentLayout = getLayout() ?? 'default';\r\nfunction getLayout() {\r\n const path = window.location.pathname;\r\n if (path == '/index.html') {\r\n return 'default';\r\n }\r\n\r\n return path.endsWith('.html') ? path.slice(1, -5) : null;\r\n}\r\n\r\nexport const internalRoutes: Route[] = [];\r\n\r\nexport const MyData = {\r\n routes: []\r\n};\r\n\r\n/**\r\n * Debug helper to print all registered routes to console.\r\n */\r\nexport function printRoutes() {\r\n console.log(internalRoutes);\r\n}\r\n\r\n/**\r\n * Registers application routes with the router.\r\n * Call this at application startup before routing begins.\r\n *\r\n * @param appRoutes - Array of route configurations\r\n * @throws Error if referenced components are not registered\r\n *\r\n * @example\r\n * const routes: Route[] = [\r\n * { name: 'home', path: '/', componentTagName: 'app-home' },\r\n * { name: 'user', path: '/users/:id', componentTagName: 'user-profile' },\r\n * { name: 'login', path: '/auth/', componentTagName: 'login-form', layout: 'noauth' }\r\n * ];\r\n * defineRoutes(routes);\r\n */\r\nexport function defineRoutes(appRoutes: Route[]) {\r\n console.log('defining routes1', appRoutes);\r\n initRouteTargetListener();\r\n if (!customElements.get('r-route-target')) {\r\n customElements.define('r-route-target', RouteTarget);\r\n }\r\n if (!customElements.get('r-link')) {\r\n customElements.define('r-link', RouteLink);\r\n }\r\n console.log('defining routes', appRoutes);\r\n internalRoutes.length = 0;\r\n internalRoutes.push(...appRoutes);\r\n\r\n var errs = [];\r\n appRoutes.forEach((route) => {\r\n if (\r\n route.componentTagName &&\r\n !customElements.get(route.componentTagName)\r\n ) {\r\n errs.push(\r\n `Component with tagName '${route.componentTagName}' is not defined in customElements.`\r\n );\r\n }\r\n if (route.component && !customElements.getName(route.component)) {\r\n errs.push(\r\n `Component '${route.component.name}' is not defined in customElements. Used in route '${JSON.stringify(route)}'.`\r\n );\r\n }\r\n if (route.layout === '') {\r\n console.log('should not use empty string layout.', route);\r\n route.layout = undefined;\r\n }\r\n });\r\n\r\n if (errs.length > 0) {\r\n throw new Error(errs.join('\\n'));\r\n }\r\n}\r\n\r\n/**\r\n * Initializes routing and navigates to the current URL.\r\n * Call this after DOM is ready and routes are defined.\r\n *\r\n * @example\r\n * // In your main application component\r\n * connectedCallback() {\r\n * defineRoutes(routes);\r\n * startRouting();\r\n * }\r\n */\r\nexport function startRouting() {\r\n let newPage = false;\r\n if (currentLayout == '') {\r\n const path = window.location.pathname;\r\n const match = path.match(/\\/([^\\/]+)\\.html$/);\r\n if (match && match[1] !== '') {\r\n console.log('setting current layut', match[1]);\r\n currentLayout = match[1];\r\n newPage = true;\r\n } else {\r\n console.log('Setting default layout name');\r\n currentLayout = 'default';\r\n }\r\n }\r\n\r\n if (tryLoadRouteFromLayoutNavigation()) {\r\n return;\r\n }\r\n\r\n const currentUrl = window.location.pathname.replace(/^\\/|\\/$/g, '') || '/';\r\n const routeResult = findRoute(currentUrl, {});\r\n\r\n const searchParams = new URLSearchParams(window.location.search);\r\n if (searchParams.size > 0) {\r\n routeResult.params ??= {};\r\n searchParams.forEach((value, key) => {\r\n routeResult.params[key] = value;\r\n });\r\n }\r\n\r\n if (navigateToLayout(routeResult)) {\r\n return;\r\n }\r\n\r\n history.replaceState(\r\n routeResult.urlSegments,\r\n '',\r\n '/' + routeResult.urlSegments.join('/')\r\n );\r\n\r\n const e = new NavigateRouteEvent(\r\n routeResult.route,\r\n routeResult.urlSegments,\r\n routeResult.params,\r\n routeResult.route.target\r\n );\r\n document.dispatchEvent(e);\r\n}\r\n\r\n/**\r\n * Navigates to a route by name or URL.\r\n * Updates browser history and dispatches navigation events.\r\n *\r\n * @param routeNameOrUrl - Route name or URL path to navigate to\r\n * @param options - Navigation options including params and target\r\n *\r\n * @example\r\n * // Navigate by route name\r\n * navigate('user', { params: { id: '123' } });\r\n *\r\n * // Navigate by URL\r\n * navigate('/users/123');\r\n *\r\n * // Navigate to specific target\r\n * navigate('detail', { params: { id: '42' }, target: 'modal' });\r\n */\r\nexport function navigate(routeNameOrUrl: string, options?: NavigateOptions) {\r\n console.log('navigating to ', routeNameOrUrl, options);\r\n const routeResult = findRoute(routeNameOrUrl, options);\r\n if (navigateToLayout(routeResult)) {\r\n return;\r\n }\r\n\r\n const target = options?.target ?? routeResult.route.target;\r\n const ourUrl = routeResult.urlSegments.join('/');\r\n const currentUrl = window.location.pathname.replace(/^\\/|\\/$/g, '');\r\n if (currentUrl != ourUrl) {\r\n history.pushState(\r\n routeResult.urlSegments,\r\n '',\r\n '/' + routeResult.urlSegments.join('/')\r\n );\r\n }\r\n const e = new NavigateRouteEvent(\r\n routeResult.route,\r\n routeResult.urlSegments,\r\n routeResult.params,\r\n target\r\n );\r\n document.dispatchEvent(e);\r\n}\r\n\r\nfunction findRoute(routeNameOrUrl: string, options?: NavigateOptions) {\r\n const theRoutes = options?.routes ?? internalRoutes;\r\n const params = options?.params;\r\n\r\n const routeResult = matchRoute(theRoutes, routeNameOrUrl, params);\r\n if (!routeResult) {\r\n const errorMsg = generateErrorMessage(\r\n routeNameOrUrl,\r\n params,\r\n theRoutes\r\n );\r\n console.error(errorMsg);\r\n throw new RouteError(errorMsg);\r\n }\r\n\r\n if (!checkRouteGuards(routeResult)) {\r\n throw new RouteGuardError('Route guards stopped navigation for route ' + routeNameOrUrl);\r\n }\r\n\r\n return routeResult;\r\n}\r\n\r\nfunction navigateToLayout(routeResult: RouteMatchResult): boolean {\r\n if (!routeResult) {\r\n console.error('Route result is null, cannot navigate to layout.');\r\n }\r\n\r\n const wantedLayout = (routeResult.route.layout ?? 'default').replace(\r\n /\\.html?$/,\r\n ''\r\n );\r\n if (wantedLayout === currentLayout) {\r\n return false;\r\n }\r\n\r\n console.log(\r\n 'Current layout: ' + currentLayout,\r\n 'Wanted layout: ' + wantedLayout\r\n );\r\n\r\n // The hash means that we attempted to redirect to the same layout once,\r\n // so if it's there and another redirect is requsted, something is wrong.\r\n //\r\n // Because the push history should remove it if everything worked out.\r\n if (window.location.hash) {\r\n throw Error(\r\n 'A redirect failed, does the requsted layout exist? \"' +\r\n wantedLayout +\r\n '\"?'\r\n );\r\n }\r\n\r\n console.log(\r\n `requires layout switch from ${currentLayout} to ${wantedLayout}`\r\n );\r\n const navigationState = {\r\n routeName: routeResult.route.name,\r\n params: routeResult.params || {}\r\n };\r\n\r\n sessionStorage.setItem('layoutNavigation', JSON.stringify(navigationState));\r\n const layoutUrl =\r\n wantedLayout.indexOf('.htm') > -1\r\n ? `/${wantedLayout}#layout`\r\n : `/${wantedLayout}.html#layout`;\r\n console.log('redirecting to ', layoutUrl);\r\n window.location.href = layoutUrl;\r\n return true;\r\n}\r\n/**\r\n * Checks session storage for route information and initiates proper navigation\r\n * Should be called when page loads to handle layout transitions\r\n *\r\n * @returns Whether navigation was initiated from session storage\r\n *\r\n * @example\r\n * // Call on page load\r\n * document.addEventListener('DOMContentLoaded', () => {\r\n * if (handleLayoutNavigation()) {\r\n * console.log('Navigation handled from session storage');\r\n * }\r\n * });\r\n */\r\nfunction tryLoadRouteFromLayoutNavigation(): boolean {\r\n try {\r\n const navigationStateJson = sessionStorage.getItem('layoutNavigation');\r\n if (!navigationStateJson) {\r\n return false;\r\n }\r\n\r\n const navigationState = JSON.parse(navigationStateJson);\r\n sessionStorage.removeItem('layoutNavigation');\r\n console.log('session store navigation ', navigationState);\r\n navigate(navigationState.routeName, {\r\n params: navigationState.params\r\n });\r\n\r\n return true;\r\n } catch (error) {\r\n sessionStorage.removeItem('layoutNavigation');\r\n reportError('Failed to navigate from session storage', {\r\n cause: error,\r\n });\r\n return false;\r\n }\r\n}\r\n\r\nfunction generateErrorMessage(\r\n routeNameOrUrl: string,\r\n routeParams: Record<string, RouteParamType>,\r\n allRoutes: Route[]\r\n): string {\r\n var routeData = '';\r\n if (routeParams) {\r\n routeData += Object.entries(routeParams)\r\n .map(([key, value]) => `${key}=${value}`)\r\n .join(', ');\r\n } else {\r\n routeData = '.';\r\n }\r\n\r\n var routesStr = allRoutes.map(\r\n (x) =>\r\n ` * Name: '${x.name}', path: '${x.path}', target: ${\r\n x.target ?? 'default'\r\n }\\n`\r\n );\r\n return `No route matched '${routeNameOrUrl}${routeData}'. Available routes:\\n${routesStr}`;\r\n}\r\n\r\nfunction checkRouteGuards(routeResult: RouteMatchResult): boolean {\r\n if (\r\n !routeResult ||\r\n !routeResult.route.guards ||\r\n routeResult.route.guards.length == 0\r\n ) {\r\n return true;\r\n }\r\n\r\n for (let index = 0; index < routeResult.route.guards.length; index++) {\r\n const element = routeResult.route.guards[index];\r\n var result = element.check(routeResult);\r\n if (result == GuardResult.Allow) {\r\n return true;\r\n }\r\n\r\n if (result == GuardResult.Stop) {\r\n return false;\r\n }\r\n\r\n if (result == GuardResult.Deny) {\r\n throw new RouteGuardError(\r\n `Guard ${element.constructor.name} said 'Deny' for ${routeResult.route.name}`\r\n );\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n", "import { reportError } from './errors';\r\n\r\n/**\r\n * Generic constructor type used for dependency registration and injection.\r\n * Represents any class constructor that can be used with the DI container.\r\n *\r\n * @template T - The type of object the constructor creates\r\n *\r\n * @example\r\n * // Use with service registration\r\n * class UserService {}\r\n * const ctor: Constructor<UserService> = UserService;\r\n * serviceCollection.registerByType(ctor, { inject: [] });\r\n */\r\nexport type Constructor<T extends object = object> = new (...args: any[]) => T;\r\n\r\n/**\r\n * Controls how service instances are shared across the container hierarchy.\r\n * Used when registering services to define their lifetime behavior.\r\n *\r\n * - `global`: Single instance shared everywhere (singleton pattern)\r\n * - `closest`: New instance per container scope (scoped lifetime)\r\n *\r\n * @example\r\n * // Singleton service - same instance everywhere\r\n * serviceCollection.register(LoggerService, { scope: 'global', inject: [] });\r\n *\r\n * // Scoped service - new instance per scope\r\n * serviceCollection.register(RequestContext, { scope: 'closest', inject: [] });\r\n */\r\nexport type ServiceScope = 'global' | 'closest';\r\n\r\n/**\r\n * Configuration options for registering a service in the DI container.\r\n * Controls identification, lifetime, and dependency resolution.\r\n *\r\n * @example\r\n * // Register with constructor injection\r\n * const options: RegistrationOptions = {\r\n * scope: 'global',\r\n * inject: [DatabaseConnection, ConfigService]\r\n * };\r\n * serviceCollection.register(UserRepository, options);\r\n *\r\n * @example\r\n * // Register with property injection\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * properties: { logger: Logger, config: 'appConfig' }\r\n * };\r\n *\r\n * @example\r\n * // Register with a pre-created instance\r\n * const options: RegistrationOptions = {\r\n * inject: [],\r\n * instance: existingService\r\n * };\r\n */\r\nexport interface RegistrationOptions {\r\n /** Service lifetime - 'global' for singleton, 'closest' for scoped */\r\n scope?: ServiceScope;\r\n /** Optional string key for resolving by name instead of type */\r\n key?: string;\r\n /** Pre-existing instance to use instead of creating new one */\r\n instance?: unknown;\r\n /** Types or keys for constructor parameters, in order */\r\n inject: (string | Constructor)[];\r\n /** Map of property names to their injection types/keys */\r\n properties?: Record<string, string | Constructor>;\r\n}\r\n\r\n/**\r\n * Field decorator that collects property injection configuration.\r\n * Updates or creates the properties mapping in registration options.\r\n * \r\n * @example\r\n * @ContainerService({\r\n * inject: [Database],\r\n * properties: {\r\n * logger: Logger, // Inject by type\r\n * audit: 'auditLogger' // Inject by key\r\n * }\r\n * })\r\n * class UserService {\r\n * @Inject(Logger)\r\n * private logger!: Logger;\r\n * \r\n * @Inject('auditLogger')\r\n * private audit!: Logger;\r\n * \r\n * constructor(db: Database) {}\r\n * }\r\n */\r\nexport function Inject<T extends object>(typeOrKey: Constructor<T> | string) {\r\n return (_: undefined, context: ClassFieldDecoratorContext) => {\r\n var instance = container.resolve(typeOrKey);\r\n return function(this: any) {\r\n return instance;\r\n }\r\n };\r\n}\r\n\r\n// Temporary collector of property injections - cleared after registration\r\n//const propertyCollector = new WeakMap<object, Record<string, string>>();\r\n\r\n/**\r\n * Class decorator that automatically registers a service in the global DI container.\r\n * Use this to declaratively register services without manual registration calls.\r\n *\r\n * Services are registered at module load time, so ensure this file is imported\r\n * before attempting to resolve the decorated service.\r\n *\r\n * @param options - Registration configuration including scope and dependencies\r\n *\r\n * @example\r\n * // Simple service with constructor injection\r\n * @ContainerService({ inject: [DatabaseConnection] })\r\n * class UserRepository {\r\n * constructor(private db: DatabaseConnection) {}\r\n * }\r\n *\r\n * @example\r\n * // Service with custom key for named resolution\r\n * @ContainerService({ key: 'primaryCache', scope: 'global', inject: [] })\r\n * class CacheService {}\r\n *\r\n * // Later resolve by key\r\n * const cache = container.resolve('primaryCache');\r\n */\r\nexport function ContainerService<T extends object>(\r\n options?: RegistrationOptions\r\n) {\r\n return (target: Constructor<T>) => {\r\n const opts = options ?? {inject: []};\r\n\r\n if (opts.key) {\r\n serviceCollection.register(target, opts);\r\n } else {\r\n serviceCollection.registerByType(target, opts);\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Internal class representing a registered service's metadata.\r\n * Holds all information needed to create and configure service instances.\r\n *\r\n * @internal This is an implementation detail and should not be used directly.\r\n */\r\nclass Registration {\r\n /**\r\n * Creates a new registration record.\r\n *\r\n * @param classConstructor - The class constructor function\r\n * @param scope - Instance sharing behavior\r\n * @param inject - Constructor parameter dependencies\r\n * @param properties - Property injection mappings\r\n * @param key - Optional string identifier\r\n * @param instance - Optional pre-created instance\r\n */\r\n constructor(\r\n public classConstructor: Constructor,\r\n public scope: ServiceScope,\r\n public inject: (string | Constructor)[],\r\n public properties: Record<string, string | Constructor> = {},\r\n public key?: string,\r\n public instance?: unknown\r\n ) {}\r\n}\r\n\r\n/**\r\n * Registry that stores service registration metadata.\r\n * Use this to register services before they can be resolved by a ServiceContainer.\r\n *\r\n * Typically you'll use the global `serviceCollection` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Register a service by type\r\n * serviceCollection.registerByType(LoggerService, { inject: [] });\r\n *\r\n * // Register with a string key\r\n * serviceCollection.register(CacheService, { key: 'cache', inject: [] });\r\n *\r\n * // Check if service is registered\r\n * const reg = serviceCollection.tryGet(LoggerService);\r\n * if (reg) {\r\n * console.log('Logger is registered');\r\n * }\r\n */\r\nexport class ServiceCollection {\r\n private servicesByKey = new Map<string, Registration>();\r\n private servicesByClassName = new Map<string, Registration>();\r\n\r\n /**\r\n * Registers a service with full configuration options.\r\n * The service will be resolvable by both its class name and optional key.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Registration configuration\r\n */\r\n register<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(\r\n constructor,\r\n options.scope ?? 'global',\r\n options.inject,\r\n options.properties ?? {},\r\n options.key,\r\n options.instance\r\n );\r\n\r\n if (options.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n /**\r\n * Registers a service by its class type.\r\n * The service will be resolvable by its class constructor.\r\n *\r\n * @param constructor - The service class constructor\r\n * @param options - Optional registration configuration\r\n */\r\n registerByType<T extends object>(\r\n constructor: Constructor<T>,\r\n options?: RegistrationOptions\r\n ): void {\r\n this.checkNameCollision(constructor);\r\n if (options) this.validateRegistration(constructor, options);\r\n\r\n const reg = new Registration(constructor, options?.scope, options?.inject ?? [], options?.properties, options?.key, options?.instance);\r\n if (options?.key) {\r\n this.servicesByKey.set(options.key, reg);\r\n }\r\n this.servicesByClassName.set(constructor.name, reg);\r\n }\r\n\r\n private checkNameCollision<T extends object>(constructor: Constructor<T>): void {\r\n const existing = this.servicesByClassName.get(constructor.name);\r\n if (existing && existing.classConstructor !== constructor) {\r\n const error = reportError('Service name collision: different class registered with same name', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n private validateRegistration<T extends object>(constructor: Constructor<T>, options: RegistrationOptions): void {\r\n this.checkNameCollision(constructor);\r\n\r\n if (options.key) {\r\n const existingByKey = this.servicesByKey.get(options.key);\r\n if (existingByKey && existingByKey.classConstructor !== constructor) {\r\n const error = reportError('Service key already registered to a different class', {\r\n key: options.key,\r\n existingClass: existingByKey.classConstructor.name,\r\n newClass: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n if (options.instance && options.inject.length > 0) {\r\n const error = reportError('Service has both instance and inject (inject will be ignored)', {\r\n service: constructor.name,\r\n });\r\n if (error) throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Attempts to retrieve a service registration.\r\n * Returns undefined if the service is not registered.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration or undefined\r\n */\r\n tryGet<T extends object>(key: string | Constructor<T>): Registration | undefined {\r\n if (typeof key === 'string') {\r\n return this.servicesByKey.get(key);\r\n }\r\n return this.servicesByClassName.get(key.name);\r\n }\r\n\r\n /**\r\n * Retrieves a service registration or throws if not found.\r\n *\r\n * @param key - Either a string key or class constructor\r\n * @returns The registration\r\n * @throws Error if the service is not registered\r\n */\r\n get<T extends object>(key: string | Constructor<T>): Registration {\r\n const reg = this.tryGet(key);\r\n if (!reg) {\r\n const service = typeof key === 'string' ? key : key.name;\r\n const error = reportError(`Failed to resolve service '${service}'`, {\r\n service,\r\n registeredTypes: Array.from(this.servicesByClassName.keys()),\r\n registeredKeys: Array.from(this.servicesByKey.keys()),\r\n });\r\n if (error) throw error;\r\n }\r\n return reg!;\r\n }\r\n}\r\n\r\n/**\r\n * Internal storage for tracking injected fields during service resolution.\r\n * @internal\r\n */\r\nconst injectedFields = new WeakMap<object, Map<string, string>>();\r\n\r\n/**\r\n * IoC container that resolves and manages service instances.\r\n * Creates instances based on registrations in a ServiceCollection,\r\n * handling constructor injection, property injection, and lifetime management.\r\n *\r\n * Typically you'll use the global `container` instance rather than creating your own.\r\n *\r\n * @example\r\n * // Resolve a service by class\r\n * const logger = container.resolve(LoggerService);\r\n *\r\n * // Resolve by string key\r\n * const cache = container.resolve<CacheService>('primaryCache');\r\n *\r\n * @example\r\n * // Full setup workflow\r\n * serviceCollection.register(UserService, {\r\n * inject: [DatabaseConnection],\r\n * scope: 'global'\r\n * });\r\n *\r\n * const userService = container.resolve(UserService);\r\n */\r\nexport class ServiceContainer {\r\n private instances = new Map<string, any>();\r\n\r\n /**\r\n * Creates a new container backed by the given service collection.\r\n *\r\n * @param serviceCollection - The registry containing service registrations\r\n */\r\n constructor(private serviceCollection: ServiceCollection) {}\r\n\r\n /**\r\n * Resolves a service instance by class type or string key.\r\n * Creates the instance if not already cached (for global scope).\r\n * Handles constructor and property injection automatically.\r\n *\r\n * @param keyOrType - Either a string key or class constructor\r\n * @returns The resolved service instance\r\n * @throws Error if the service is not registered\r\n *\r\n * @example\r\n * const service = container.resolve(MyService);\r\n */\r\n resolve<T extends object>(keyOrType: string | Constructor<T>): T {\r\n const key = typeof keyOrType === 'string' ? keyOrType : keyOrType.name;\r\n\r\n if (this.instances.has(key)) {\r\n return this.instances.get(key);\r\n }\r\n\r\n const registration = this.serviceCollection.get(keyOrType);\r\n if (!registration) {\r\n const error = reportError(`Failed to resolve service '${key}'`, { service: key });\r\n if (error) throw error;\r\n return undefined as unknown as T;\r\n }\r\n\r\n if (registration.instance) {\r\n const inst = registration.instance as T;\r\n this.injectFields(inst, registration);\r\n this.instances.set(key, inst);\r\n return inst;\r\n }\r\n\r\n const instance = this.createInstance<T>(registration);\r\n if (registration.scope === 'global') {\r\n this.instances.set(key, instance);\r\n }\r\n this.injectFields(instance, registration);\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Creates a new instance of a service, resolving all constructor dependencies.\r\n */\r\n private createInstance<T extends object>(registration: Registration): T {\r\n const constructor = registration.classConstructor as Constructor<T>;\r\n\r\n const dependencies = registration.inject.map(dep => this.resolve(dep));\r\n return new constructor(...dependencies);\r\n }\r\n\r\n /**\r\n * Injects dependencies into instance properties based on registration config.\r\n */\r\n private injectFields<T extends object>(instance: T, registration: Registration): void {\r\n for (const [fieldName, keyOrType] of Object.entries(registration.properties)) {\r\n (instance as any)[fieldName] = this.resolve(keyOrType);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Global service collection instance for registering services.\r\n * Use this to register services that can later be resolved by the container.\r\n *\r\n * @example\r\n * import { serviceCollection } from 'relaxjs';\r\n *\r\n * serviceCollection.register(MyService, { inject: [Dependency] });\r\n */\r\nexport const serviceCollection = new ServiceCollection();\r\n\r\n/**\r\n * Global service container instance for resolving dependencies.\r\n * Use this to obtain service instances with all dependencies injected.\r\n *\r\n * @example\r\n * import { container } from 'relaxjs';\r\n *\r\n * const service = container.resolve(MyService);\r\n */\r\nexport const container = new ServiceContainer(serviceCollection);", "/**\r\n * Finds the closest parent element of a specific Web Component type.\r\n * Traverses up the DOM tree looking for an ancestor matching the constructor.\r\n *\r\n * Useful for child components that need to communicate with or access\r\n * their parent container component, common in composite component patterns.\r\n *\r\n * @template T - The type of HTMLElement to find\r\n * @param node - The starting node to search from\r\n * @param constructor - The class constructor of the desired element type\r\n * @returns The matching parent element or null if not found\r\n *\r\n * @example\r\n * // Inside a child component, find the parent container\r\n * class ListItem extends HTMLElement {\r\n * connectedCallback() {\r\n * const list = getParentComponent(this, ListContainer);\r\n * if (list) {\r\n * list.registerItem(this);\r\n * }\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Access parent component's methods\r\n * class TabPanel extends HTMLElement {\r\n * activate() {\r\n * const tabs = getParentComponent(this, TabContainer);\r\n * tabs?.selectPanel(this);\r\n * }\r\n * }\r\n *\r\n * @example\r\n * // Handle case where parent might not exist\r\n * const form = getParentComponent(input, FormContainer);\r\n * if (!form) {\r\n * console.warn('Input must be inside a FormContainer');\r\n * return;\r\n * }\r\n */\r\nexport function getParentComponent<T extends HTMLElement>(\r\n node: Node,\r\n constructor: { new (...args: any[]): T }\r\n): T | null {\r\n let current = node.parentElement;\r\n\r\n while (current) {\r\n if (current instanceof constructor) {\r\n return current;\r\n }\r\n current = current.parentElement;\r\n }\r\n\r\n return null;\r\n} ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * @module http\r\n * Type-safe HTTP module built on fetch() with automatic JWT handling.\r\n *\r\n * @example\r\n * import { configure, get, post } from './http';\r\n *\r\n * configure({ baseUrl: '/api' });\r\n * const response = await get('/users');\r\n * const users = response.as<User[]>();\r\n */\r\n\r\n/**\r\n * Configuration options for the http module.\r\n */\r\nexport interface HttpOptions {\r\n /**\r\n * Root URL to remote endpoint. Used so that each method only has to specify path in requests.\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Default content type to use if none is specified in the request method.\r\n */\r\n contentType?: string;\r\n\r\n /**\r\n * Checks for a JWT token in localStorage to automatically include it in requests.\r\n *\r\n * Undefined = use \"jwt\", null = disable.\r\n */\r\n bearerTokenName?: string | null;\r\n\r\n /**\r\n * Default request timeout in milliseconds.\r\n * Uses `AbortSignal.timeout()` to automatically abort requests that take too long.\r\n * Can be overridden per-request by passing a `signal` in `RequestInit`.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api', timeout: 10000 }); // 10 second timeout\r\n */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Response for request methods.\r\n */\r\nexport interface HttpResponse {\r\n /**\r\n * Http status code.\r\n */\r\n statusCode: number;\r\n\r\n /**\r\n * Reason to why the status code was used.\r\n */\r\n statusReason: string;\r\n\r\n /**\r\n * True if this is a 2xx response.\r\n */\r\n success: boolean;\r\n\r\n /**\r\n * Content type of response body.\r\n */\r\n contentType: string | null;\r\n\r\n /**\r\n * Body returned.\r\n *\r\n * Body has been read and deserialized from json (if the request content type was 'application/json' which is the default).\r\n */\r\n body: unknown;\r\n\r\n /**\r\n * Charset used in body.\r\n */\r\n charset: string | null;\r\n\r\n /**\r\n * Cast body to a type.\r\n */\r\n as<T>(): T;\r\n}\r\n\r\n/**\r\n * Error thrown when a request fails.\r\n */\r\nexport class HttpError extends Error {\r\n message: string;\r\n response: HttpResponse;\r\n\r\n constructor(response: HttpResponse) {\r\n super(response.statusReason);\r\n this.message = response.statusReason;\r\n this.response = response;\r\n }\r\n}\r\n\r\n/**\r\n * HTTP request options.\r\n */\r\nexport interface RequestOptions {\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n mode?: 'cors' | 'no-cors' | '*cors' | 'same-origin';\r\n cache:\r\n | 'default'\r\n | 'no-store'\r\n | 'reload'\r\n | 'no-cache'\r\n | 'force-cache'\r\n | 'only-if-cached';\r\n credentials: 'omit' | 'same-origin' | 'include';\r\n headers: Map<string, string>;\r\n redirect: 'follow' | 'manual' | '*follow' | 'error';\r\n referrerPolicy:\r\n | 'no-referrer'\r\n | '*no-referrer-when-downgrade'\r\n | 'origin'\r\n | 'origin-when-cross-origin'\r\n | 'same-origin'\r\n | 'strict-origin'\r\n | 'strict-origin-when-cross-origin'\r\n | 'unsafe-url';\r\n\r\n /**\r\n * Will be serialized if the content type is json (and the body is an object).\r\n */\r\n body: unknown;\r\n}\r\n\r\ndeclare type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\r\n\r\nlet config: HttpOptions = {\r\n bearerTokenName: 'jwt'\r\n};\r\n\r\nlet fetchImpl: FetchFn = fetch;\r\n\r\n/**\r\n * Replace the fetch implementation for testing purposes.\r\n *\r\n * @param fn - Custom fetch function, or undefined to restore the default.\r\n *\r\n * @example\r\n * setFetch(async (url, options) => {\r\n * return new Response(JSON.stringify({ id: 1 }), { status: 200 });\r\n * });\r\n */\r\nexport function setFetch(fn?: FetchFn): void {\r\n fetchImpl = fn ?? fetch;\r\n}\r\n\r\n/**\r\n * Configure the http module.\r\n *\r\n * @example\r\n * configure({ baseUrl: '/api/v1', bearerTokenName: 'auth_token' });\r\n */\r\nexport function configure(options: HttpOptions): void {\r\n config = {\r\n ...config,\r\n ...options\r\n };\r\n if (options.bearerTokenName === undefined) {\r\n config.bearerTokenName = 'jwt';\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request.\r\n *\r\n * @param url - URL to make the request against.\r\n * @param options - Request options.\r\n * @returns Response from server.\r\n *\r\n * @example\r\n * const response = await request('/users', { method: 'GET' });\r\n */\r\nexport async function request(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (config.bearerTokenName) {\r\n const token = localStorage.getItem(config.bearerTokenName);\r\n if (token && options) {\r\n const headers = options?.headers\r\n ? new Headers(options.headers)\r\n : new Headers();\r\n\r\n if (!headers.get('Authorization')) {\r\n headers.set('Authorization', 'Bearer ' + token);\r\n }\r\n\r\n options.headers = headers;\r\n }\r\n }\r\n\r\n if (config.timeout && !options?.signal) {\r\n options ??= {};\r\n options.signal = AbortSignal.timeout(config.timeout);\r\n }\r\n\r\n if (config.baseUrl) {\r\n if (url[0] !== '/' && config.baseUrl[config.baseUrl.length - 1] !== '/') {\r\n url = `${config.baseUrl}/${url}`;\r\n } else {\r\n url = config.baseUrl + url;\r\n }\r\n }\r\n\r\n const response = await fetchImpl(url, options);\r\n\r\n if (!response.ok) {\r\n return {\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n success: false,\r\n contentType: response.headers.get('content-type'),\r\n body: await response.text(),\r\n charset: response.headers.get('charset'),\r\n\r\n as() {\r\n throw new Error('No response received');\r\n }\r\n };\r\n }\r\n\r\n let body: unknown | null = null;\r\n if (response.status !== 204) {\r\n body = await response.json();\r\n }\r\n\r\n return {\r\n success: true,\r\n statusCode: response.status,\r\n statusReason: response.statusText,\r\n contentType: response.headers.get('content-type'),\r\n body: body,\r\n charset: response.headers.get('charset'),\r\n as<T>() {\r\n return <T>body;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * GET a resource.\r\n *\r\n * @param url - URL to get resource from.\r\n * @param queryString - Optional query string parameters.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await get('/users', { page: '1', limit: '10' });\r\n * const users = response.as<User[]>();\r\n */\r\nexport async function get(\r\n url: string,\r\n queryString?: Record<string, string>,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'GET',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'GET';\r\n }\r\n\r\n if (queryString) {\r\n let prefix = '&';\r\n if (url.indexOf('?') === -1) {\r\n prefix = '?';\r\n }\r\n\r\n for (const key in queryString) {\r\n const value = queryString[key];\r\n url += `${prefix}${key}=${value}`;\r\n prefix = '&';\r\n }\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * POST a resource.\r\n *\r\n * @param url - URL to post to.\r\n * @param data - Data to post.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await post('/users', JSON.stringify({ name: 'John' }));\r\n */\r\nexport async function post(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'POST',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'POST';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * PUT a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param data - Data to put.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await put('/users/1', JSON.stringify({ name: 'Jane' }));\r\n */\r\nexport async function put(\r\n url: string,\r\n data: BodyInit,\r\n options?: RequestInit\r\n): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'PUT',\r\n body: data,\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'PUT';\r\n options.body = data;\r\n }\r\n\r\n return request(url, options);\r\n}\r\n\r\n/**\r\n * DELETE a resource.\r\n *\r\n * @param url - URL to resource.\r\n * @param options - Request options.\r\n * @returns HTTP response.\r\n *\r\n * @example\r\n * const response = await del('/users/1');\r\n */\r\nexport async function del(url: string, options?: RequestInit): Promise<HttpResponse> {\r\n if (!options) {\r\n options = {\r\n method: 'DELETE',\r\n headers: {\r\n 'content-type': config.contentType ?? 'application/json'\r\n }\r\n };\r\n } else {\r\n options.method = 'DELETE';\r\n }\r\n\r\n return request(url, options);\r\n}\r\n", "/**\r\n * @module ServerSentEvents\r\n * SSE client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * eventTypes: ['user-updated', 'order-created']\r\n * });\r\n * sse.connect();\r\n *\r\n * document.addEventListener('user-updated', (e: SSEDataEvent) => {\r\n * console.log('User updated:', e.data);\r\n * });\r\n */\r\n\r\n/**\r\n * Event dispatched when an SSE message is received.\r\n * The event name matches the SSE event type.\r\n */\r\nexport class SSEDataEvent extends Event {\r\n constructor(\r\n eventName: string,\r\n public data: unknown,\r\n eventInit?: EventInit\r\n ) {\r\n super(eventName, { bubbles: true, ...eventInit });\r\n }\r\n}\r\n\r\n/**\r\n * Factory function for creating custom event instances.\r\n *\r\n * @example\r\n * const factory: SSEEventFactory = (eventName, data) => {\r\n * switch (eventName) {\r\n * case 'user-updated':\r\n * return new UserUpdatedEvent(data as User);\r\n * default:\r\n * return new SSEDataEvent(eventName, data);\r\n * }\r\n * };\r\n */\r\nexport type SSEEventFactory = (eventName: string, data: unknown) => Event;\r\n\r\n/**\r\n * Configuration options for SSEClient.\r\n */\r\nexport interface SSEOptions {\r\n /**\r\n * Target element or CSS selector for event dispatching.\r\n * Defaults to document.\r\n */\r\n target?: string | Element;\r\n\r\n /**\r\n * Whether to send credentials with the request (default: false).\r\n */\r\n withCredentials?: boolean;\r\n\r\n /**\r\n * Specific SSE event types to listen for.\r\n * If not specified, listens to the default 'message' event.\r\n *\r\n * @example\r\n * eventTypes: ['user-updated', 'order-created']\r\n */\r\n eventTypes?: string[];\r\n\r\n /**\r\n * Factory function for creating custom event instances.\r\n * If not provided, SSEDataEvent is used.\r\n *\r\n * @example\r\n * eventFactory: (name, data) => new MyCustomEvent(name, data)\r\n */\r\n eventFactory?: SSEEventFactory;\r\n\r\n /**\r\n * Callback when connection is established.\r\n */\r\n onConnect?: (client: SSEClient) => void;\r\n\r\n /**\r\n * Callback when an error occurs.\r\n * Note: EventSource automatically reconnects on errors.\r\n */\r\n onError?: (client: SSEClient, error: Event) => void;\r\n}\r\n\r\n/**\r\n * Server-Sent Events client that dispatches received events as DOM events.\r\n * Uses the browser's built-in EventSource with automatic reconnection.\r\n *\r\n * @example\r\n * const sse = new SSEClient('/api/events', {\r\n * target: '#notifications',\r\n * eventTypes: ['notification', 'alert']\r\n * });\r\n *\r\n * sse.connect();\r\n *\r\n * document.querySelector('#notifications')\r\n * .addEventListener('notification', (e: SSEDataEvent) => {\r\n * showNotification(e.data);\r\n * });\r\n *\r\n * sse.disconnect();\r\n */\r\nexport class SSEClient {\r\n private eventSource?: EventSource;\r\n private target: Element | Document;\r\n\r\n /**\r\n * Whether the client is currently connected.\r\n */\r\n get connected(): boolean {\r\n return this.eventSource?.readyState === EventSource.OPEN;\r\n }\r\n\r\n constructor(\r\n private url: string,\r\n private options?: SSEOptions\r\n ) {\r\n this.target = this.resolveTarget(options?.target);\r\n }\r\n\r\n /**\r\n * Establish connection to the SSE endpoint.\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return;\r\n }\r\n\r\n const eventSource = new EventSource(this.url, {\r\n withCredentials: this.options?.withCredentials ?? false\r\n });\r\n\r\n this.eventSource = eventSource;\r\n\r\n eventSource.onopen = () => {\r\n this.options?.onConnect?.(this);\r\n };\r\n\r\n eventSource.onerror = (error) => {\r\n this.options?.onError?.(this, error);\r\n };\r\n\r\n if (this.options?.eventTypes && this.options.eventTypes.length > 0) {\r\n for (const eventType of this.options.eventTypes) {\r\n eventSource.addEventListener(eventType, (e: MessageEvent) => {\r\n this.dispatchEvent(eventType, e.data);\r\n });\r\n }\r\n } else {\r\n eventSource.onmessage = (e: MessageEvent) => {\r\n this.dispatchEvent('message', e.data);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Close the connection.\r\n */\r\n disconnect(): void {\r\n this.eventSource?.close();\r\n this.eventSource = undefined;\r\n }\r\n\r\n private resolveTarget(target?: string | Element): Element | Document {\r\n if (!target) {\r\n return document;\r\n }\r\n if (typeof target === 'string') {\r\n const element = document.querySelector(target);\r\n if (!element) {\r\n throw new Error(`SSEClient: Target element not found: ${target}`);\r\n }\r\n return element;\r\n }\r\n return target;\r\n }\r\n\r\n private dispatchEvent(eventName: string, rawData: string): void {\r\n let data: unknown;\r\n\r\n if (rawData.length > 0 && (rawData[0] === '{' || rawData[0] === '[' || rawData[0] === '\"')) {\r\n try {\r\n data = JSON.parse(rawData);\r\n } catch {\r\n data = rawData;\r\n }\r\n } else {\r\n data = rawData;\r\n }\r\n\r\n const event = this.options?.eventFactory\r\n ? this.options.eventFactory(eventName, data)\r\n : new SSEDataEvent(eventName, data);\r\n\r\n this.target.dispatchEvent(event);\r\n }\r\n}\r\n", "/**\r\n * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n "],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed", "Node", "value", "removeCallback", "LinkedList", "newNode", "PageSelectedEvent", "page", "Pager", "container", "totalCount", "pageSize", "pageCount", "createButton", "label", "disabled", "btn", "i", "getFieldName", "element", "id", "form", "label", "FormValidator", "options", "event", "formElements", "isFormValid", "errorMessages", "fieldName", "messages", "errorList", "message", "listItem", "errorSummary", "firstInvalidElement", "i", "child", "pluralRulesCache", "getPluralRule", "locale", "escapeRegex", "s", "defaultFormatICU", "message", "values", "_", "key", "type", "categoriesPart", "value", "exact", "category", "match", "escaped", "formatICU", "fallbackLocale", "currentLocale", "translations", "missingHandler", "t", "fullKey", "values", "namespace", "key", "message", "translations", "missingHandler", "currentLocale", "formatICU", "getCurrentLocale", "mapFormToClass", "form", "instance", "options", "formElements", "element", "booleanAttr", "propertyName", "value", "readElementValue", "SKIP", "formFieldNames", "prop", "getDataConverter", "dataType", "createConverterFromDataType", "createConverterFromInputType", "BooleanConverter", "str", "readData", "data", "formData", "seen", "_", "name", "values", "converter", "v", "i", "el", "lower", "NumberConverter", "nr", "getLocaleDateOrder", "locale", "p", "DateConverter", "date", "numericParts", "getCurrentLocale", "order", "mapped", "type", "inputType", "year", "month", "week", "hours", "minutes", "seconds", "attr", "o", "validators", "RegisterValidator", "validationName", "validInputTypes", "target", "getValidator", "name", "_RequiredValidation_decorators", "_init", "_RequiredValidation", "rule", "value", "context", "t", "__decoratorStart", "__decorateElement", "__runInitializers", "RequiredValidation", "_RangeValidation_decorators", "_RangeValidation", "min", "max", "rangeMatch", "num", "actual", "RangeValidation", "_DigitsValidation_decorators", "_DigitsValidation", "DigitsValidation", "setFormData", "form", "data", "element", "name", "arrayName", "arrayValue", "getValueByComplexPath", "el", "type", "boolAttr", "val", "option", "opt", "allWithName", "idx", "value", "setElementValue", "obj", "path", "segments", "currentSegment", "inBrackets", "i", "char", "result", "segment", "index", "setElementValue", "element", "value", "el", "type", "pad", "n", "boolAttr", "options", "vals", "opt", "name", "attr", "uppercasePipe", "value", "trimPipe", "lowercasePipe", "capitalizePipe", "str", "shortenPipe", "length", "maxLength", "currencyPipe", "currency", "locale", "getCurrentLocale", "datePipe", "format", "date", "daysAgoPipe", "inputDate", "today", "diffTime", "diffDays", "t", "piecesPipe", "count", "joinPipe", "separator", "firstPipe", "lastPipe", "keysPipe", "defaultPipe", "defaultValue", "ternaryPipe", "trueValue", "falseValue", "createPipeRegistry", "pipes", "name", "pipe", "defaultPipes", "applyPipes", "registry", "currentValue", "pipeName", "args", "p", "error", "pipes", "defaultPipes", "html", "templateStrings", "substitutions", "template", "resolvedTemplate", "resolveTemplate", "bindings", "walker", "node", "element", "processElement", "myNode", "text", "result", "parseTemplate", "startMarker", "endMarker", "insertedNodes", "instance", "value", "n", "temp", "nodes", "parent", "context", "x", "str", "i", "attrBindings", "attr", "attrValue", "regex", "match", "index", "func", "boundFunction", "attributeCallback", "attrBinding", "parseArguments", "argsStr", "arg", "parts", "part", "lastIndex", "textBindings", "_instance", "sub", "mustacheName", "matchingPipes", "pipe", "args", "val", "_", "binding", "parseExpression", "expr", "pipesSplit", "mainExpr", "pipes", "fnMatch", "fnName", "argsStr", "fnArgs", "a", "resolvePath", "ctx", "path", "segments", "current", "key", "handleError", "config", "message", "context", "shouldThrow", "formattedMessage", "createGetter", "debugInfo", "err", "errorMessage", "evaluateExpression", "parsed", "fns", "value", "registry", "defaultPipes", "fn", "resolvedArgs", "arg", "resolved", "applyPipes", "expressionCache", "textNodePatcher", "node", "_get", "raw", "part", "exprs", "result", "literal", "attributeInterpolationPatcher", "element", "setters", "attributes", "attr", "match", "name", "createConditionalPatcher", "get", "attrName", "shouldRender", "templateNode", "placeholder", "parent", "currentElement", "currentRenderer", "cachedElement", "cachedRenderer", "shouldBeVisible", "clone", "compileDOM", "ifPatcher", "unlessPatcher", "loopPatcher", "loopDef", "alias", "source", "tpl", "slots", "items", "reuseCount", "i", "frag", "newSlots", "instance", "childRenderer", "insertAfter", "structuralPatchers", "contentPatchers", "root", "processNode", "patch", "setter", "child", "lastCtx", "lastFns", "compileTemplate", "templateStr", "content", "render", "parsePath", "notation", "options", "delimiter", "escapeChar", "segments", "current", "inBrackets", "bracketContent", "char", "currentInDelimLength", "nextChar", "nextInDelimLength", "createAccessorFromPath", "path", "record", "segment", "index", "createAccessor", "tokenize", "input", "tokens", "i", "char", "pipeTarget", "quote", "value", "hasDecimal", "isFunctionCall", "bracketCount", "wsCount", "parenCount", "lastToken", "isDotAfterConstant", "tokenizeArgs", "start", "end", "argsStr", "quoteType", "numStr", "ident", "tokenizeMustache", "template", "currentIndex", "openTagIndex", "createStringToken", "mustache", "endIndex", "balanced", "extractMustache", "createMustacheToken", "startIndex", "open", "close", "depth", "compileMustard", "template", "options", "segments", "tokenizeMustache", "token", "_data", "_component", "compileExpression", "data", "component", "fn", "tokens", "tokenize", "chain", "buildExpressionChain", "renderFromChain", "sourceText", "pipeRegistry", "defaultPipes", "createAccessor", "resolveFunction", "pipeName", "args", "p", "pipe", "value", "initial", "result", "acc", "expression", "pos", "resolvedArgs", "tokenizeArgs", "arg", "name", "fnAccessor", "evaluatedArgs", "argFn", "BoundNode", "root", "bindings", "clickBindings", "component", "data", "binding", "click", "node", "method", "evt", "args", "token", "obj", "key", "path", "index", "createBluePrint", "html", "bp", "Blueprint", "htmlOrTemplate", "trimmed", "wrapper", "found", "rootElement", "rootClone", "boundBindings", "el", "walk", "func", "compileMustard", "targetNode", "element", "i", "attr", "child", "clickAttr", "match", "methodName", "argTokens", "tokenizeArgs", "TableRenderer", "table", "template", "idColumn", "component", "data", "item", "id", "row", "cell", "field", "el", "element", "handlerAttr", "match", "methodName", "argStr", "args", "s", "event", "SortChangeEvent", "sortColumns", "TableSorter", "th", "column", "index", "c", "existingIndicator", "sortInfo", "indicator", "GuardResult", "RouteError", "RouteGuardError", "NavigateRouteEvent", "_NavigateRouteEvent", "route", "urlSegments", "routeData", "routeTarget", "eventInit", "targetHandlers", "pendingEvents", "registerRouteTarget", "name", "handler", "initRouteTargetListener", "error", "reportError", "pending", "unregisterRouteTarget", "clearPendingNavigations", "dispatchToTarget", "evt", "listenerAttached", "NavigateRouteEvent", "NumberRouteSegment", "paramName", "value", "pathValue", "StringRouteSegment", "PathRouteSegment", "_pathValue", "RouteImp", "route", "segments", "generatedSegments", "params", "index", "urlSegment", "ourSegment", "routeData", "urlSegments", "routeParams", "d", "segment", "providedValue", "convertedValue", "matchRoute", "routes", "routeNameOrUrl", "findRouteByUrl", "findRouteByName", "name", "x", "imp", "generateRouteImp", "result", "path", "routeImps", "generateRouteImps", "m", "impSegments", "RouteLink", "e", "name", "printRoutes", "params", "attr", "paramName", "paramsAttr", "additionalParams", "error", "err", "reportError", "target", "navigate", "RelaxError", "reported", "RouteTarget", "registerRouteTarget", "evt", "unregisterRouteTarget", "error", "RelaxError", "reportError", "tagName", "element", "data", "routeData", "currentLayout", "getLayout", "path", "internalRoutes", "printRoutes", "internalRoutes", "defineRoutes", "appRoutes", "initRouteTargetListener", "RouteTarget", "RouteLink", "errs", "route", "startRouting", "newPage", "currentLayout", "match", "tryLoadRouteFromLayoutNavigation", "currentUrl", "routeResult", "findRoute", "searchParams", "value", "key", "navigateToLayout", "e", "NavigateRouteEvent", "navigate", "routeNameOrUrl", "options", "target", "ourUrl", "theRoutes", "params", "matchRoute", "errorMsg", "generateErrorMessage", "RouteError", "checkRouteGuards", "RouteGuardError", "wantedLayout", "navigationState", "layoutUrl", "navigationStateJson", "error", "reportError", "routeParams", "allRoutes", "routeData", "routesStr", "x", "index", "element", "result", "Inject", "typeOrKey", "_", "context", "instance", "container", "ContainerService", "options", "target", "opts", "serviceCollection", "Registration", "classConstructor", "scope", "inject", "properties", "key", "ServiceCollection", "constructor", "reg", "existing", "error", "reportError", "existingByKey", "service", "ServiceContainer", "serviceCollection", "keyOrType", "key", "registration", "error", "reportError", "inst", "instance", "constructor", "dependencies", "dep", "fieldName", "ServiceCollection", "container", "getParentComponent", "node", "constructor", "current", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "HttpError", "response", "config", "fetchImpl", "setFetch", "fn", "configure", "options", "request", "url", "token", "headers", "body", "get", "queryString", "prefix", "key", "value", "post", "data", "put", "del", "SSEDataEvent", "eventName", "data", "eventInit", "SSEClient", "url", "options", "eventSource", "error", "eventType", "e", "target", "element", "rawData", "event", "resolveValue", "path", "context", "value", "key"]
|
|
7
7
|
}
|