@relax.js/core 1.0.4 → 1.0.6
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/DependencyInjection.d.ts +3 -3
- package/dist/collections/LinkedList.d.ts +9 -8
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +3 -3
- package/dist/collections/index.mjs +1 -1
- package/dist/collections/index.mjs.map +3 -3
- package/dist/di/index.js +1 -1
- package/dist/di/index.js.map +2 -2
- package/dist/di/index.mjs +1 -1
- package/dist/di/index.mjs.map +2 -2
- package/dist/elements/index.js +1 -1
- package/dist/elements/index.js.map +1 -1
- package/dist/forms/FormValidator.d.ts +2 -2
- package/dist/forms/ValidationRules.d.ts +2 -6
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +3 -3
- package/dist/forms/index.mjs +1 -1
- package/dist/forms/index.mjs.map +3 -3
- package/dist/forms/setFormData.d.ts +52 -1
- package/dist/html/index.js +1 -1
- package/dist/html/index.js.map +3 -3
- package/dist/html/index.mjs +1 -1
- package/dist/html/index.mjs.map +3 -3
- package/dist/http/ServerSentEvents.d.ts +1 -1
- package/dist/http/SimpleWebSocket.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/index.js.map +3 -3
- package/dist/http/index.mjs +1 -1
- package/dist/http/index.mjs.map +3 -3
- package/dist/i18n/icu.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/index.js.map +2 -2
- package/dist/i18n/index.mjs +1 -1
- package/dist/i18n/index.mjs.map +2 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +3 -3
- package/dist/routing/NavigateRouteEvent.d.ts +4 -4
- package/dist/routing/index.js +2 -2
- package/dist/routing/index.js.map +3 -3
- package/dist/routing/index.mjs +3 -3
- package/dist/routing/index.mjs.map +3 -3
- package/dist/routing/navigation.d.ts +1 -1
- package/dist/templates/NodeTemplate.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +3 -3
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +3 -3
- package/docs/GettingStarted.md +7 -0
- package/docs/api.json +34 -12
- package/docs/forms/reading-writing.md +137 -1
- package/docs/setup/bootstrapping.md +154 -0
- package/docs/setup/build-and-deploy.md +183 -0
- package/docs/setup/project-structure.md +170 -0
- package/docs/setup/vite.md +175 -0
- package/package.json +3 -2
- package/docs/api/.nojekyll +0 -1
- package/docs/api/assets/hierarchy.js +0 -1
- package/docs/api/assets/highlight.css +0 -120
- package/docs/api/assets/icons.js +0 -18
- package/docs/api/assets/icons.svg +0 -1
- package/docs/api/assets/main.js +0 -60
- package/docs/api/assets/navigation.js +0 -1
- package/docs/api/assets/search.js +0 -1
- package/docs/api/assets/style.css +0 -1633
- package/docs/api/classes/http.WebSocketClient.html +0 -26
- package/docs/api/classes/i18n.LocaleChangeEvent.html +0 -66
- package/docs/api/classes/index.Blueprint.html +0 -3
- package/docs/api/classes/index.BoundNode.html +0 -3
- package/docs/api/classes/index.DigitsValidation.html +0 -10
- package/docs/api/classes/index.FormValidator.html +0 -32
- package/docs/api/classes/index.HttpError.html +0 -13
- package/docs/api/classes/index.LinkedList.html +0 -26
- package/docs/api/classes/index.NavigateRouteEvent.html +0 -76
- package/docs/api/classes/index.Node.html +0 -15
- package/docs/api/classes/index.PageSelectedEvent.html +0 -61
- package/docs/api/classes/index.Pager.html +0 -4
- package/docs/api/classes/index.RangeValidation.html +0 -15
- package/docs/api/classes/index.RelaxError.html +0 -17
- package/docs/api/classes/index.RequiredValidation.html +0 -10
- package/docs/api/classes/index.RouteError.html +0 -11
- package/docs/api/classes/index.RouteGuardError.html +0 -12
- package/docs/api/classes/index.RouteLink.html +0 -779
- package/docs/api/classes/index.RouteTarget.html +0 -788
- package/docs/api/classes/index.SSEClient.html +0 -13
- package/docs/api/classes/index.SSEDataEvent.html +0 -63
- package/docs/api/classes/index.ServiceCollection.html +0 -28
- package/docs/api/classes/index.ServiceContainer.html +0 -24
- package/docs/api/classes/index.SortChangeEvent.html +0 -61
- package/docs/api/classes/index.TableRenderer.html +0 -5
- package/docs/api/classes/index.TableSorter.html +0 -4
- package/docs/api/enums/index.GuardResult.html +0 -9
- package/docs/api/functions/elements.formError.html +0 -6
- package/docs/api/functions/elements.selectOne.html +0 -6
- package/docs/api/functions/i18n.getCurrentLocale.html +0 -3
- package/docs/api/functions/i18n.loadNamespace.html +0 -7
- package/docs/api/functions/i18n.loadNamespaces.html +0 -6
- package/docs/api/functions/i18n.onMissingTranslation.html +0 -7
- package/docs/api/functions/i18n.setLocale.html +0 -7
- package/docs/api/functions/i18n.setMessageFormatter.html +0 -7
- package/docs/api/functions/i18n.t.html +0 -9
- package/docs/api/functions/index.BooleanConverter.html +0 -6
- package/docs/api/functions/index.ContainerService.html +0 -13
- package/docs/api/functions/index.DateConverter.html +0 -11
- package/docs/api/functions/index.Inject.html +0 -16
- package/docs/api/functions/index.NumberConverter.html +0 -5
- package/docs/api/functions/index.RegisterValidator.html +0 -7
- package/docs/api/functions/index.applyPipes.html +0 -17
- package/docs/api/functions/index.asyncHandler.html +0 -11
- package/docs/api/functions/index.capitalizePipe.html +0 -4
- package/docs/api/functions/index.clearPendingNavigations.html +0 -1
- package/docs/api/functions/index.compileTemplate.html +0 -26
- package/docs/api/functions/index.configure.html +0 -5
- package/docs/api/functions/index.createBluePrint.html +0 -1
- package/docs/api/functions/index.createConverterFromDataType.html +0 -4
- package/docs/api/functions/index.createConverterFromInputType.html +0 -5
- package/docs/api/functions/index.createPipeRegistry.html +0 -12
- package/docs/api/functions/index.currencyPipe.html +0 -9
- package/docs/api/functions/index.datePipe.html +0 -9
- package/docs/api/functions/index.daysAgoPipe.html +0 -8
- package/docs/api/functions/index.defaultPipe.html +0 -5
- package/docs/api/functions/index.defineRoutes.html +0 -8
- package/docs/api/functions/index.del.html +0 -8
- package/docs/api/functions/index.findRouteByName.html +0 -5
- package/docs/api/functions/index.findRouteByUrl.html +0 -4
- package/docs/api/functions/index.firstPipe.html +0 -4
- package/docs/api/functions/index.generateSequentialId.html +0 -21
- package/docs/api/functions/index.get.html +0 -9
- package/docs/api/functions/index.getDataConverter.html +0 -11
- package/docs/api/functions/index.getParentComponent.html +0 -18
- package/docs/api/functions/index.getValidator.html +0 -4
- package/docs/api/functions/index.html.html +0 -19
- package/docs/api/functions/index.joinPipe.html +0 -5
- package/docs/api/functions/index.keysPipe.html +0 -4
- package/docs/api/functions/index.lastPipe.html +0 -4
- package/docs/api/functions/index.lowercasePipe.html +0 -4
- package/docs/api/functions/index.mapFormToClass.html +0 -17
- package/docs/api/functions/index.matchRoute.html +0 -5
- package/docs/api/functions/index.navigate.html +0 -8
- package/docs/api/functions/index.onError.html +0 -8
- package/docs/api/functions/index.piecesPipe.html +0 -8
- package/docs/api/functions/index.post.html +0 -9
- package/docs/api/functions/index.printRoutes.html +0 -2
- package/docs/api/functions/index.put.html +0 -9
- package/docs/api/functions/index.readData.html +0 -17
- package/docs/api/functions/index.registerRouteTarget.html +0 -9
- package/docs/api/functions/index.reportError.html +0 -10
- package/docs/api/functions/index.request.html +0 -8
- package/docs/api/functions/index.resolveValue.html +0 -18
- package/docs/api/functions/index.setFetch.html +0 -6
- package/docs/api/functions/index.setFormData.html +0 -17
- package/docs/api/functions/index.shortenPipe.html +0 -5
- package/docs/api/functions/index.startRouting.html +0 -6
- package/docs/api/functions/index.ternaryPipe.html +0 -6
- package/docs/api/functions/index.trimPipe.html +0 -4
- package/docs/api/functions/index.unregisterRouteTarget.html +0 -3
- package/docs/api/functions/index.uppercasePipe.html +0 -4
- package/docs/api/hierarchy.html +0 -1
- package/docs/api/index.html +0 -323
- package/docs/api/interfaces/http.SimpleDataEvent.html +0 -3
- package/docs/api/interfaces/http.WebSocketAbstraction.html +0 -9
- package/docs/api/interfaces/http.WebSocketCodec.html +0 -4
- package/docs/api/interfaces/http.WebSocketOptions.html +0 -20
- package/docs/api/interfaces/index.CompiledTemplate.html +0 -10
- package/docs/api/interfaces/index.DataLoader.html +0 -19
- package/docs/api/interfaces/index.EngineConfig.html +0 -11
- package/docs/api/interfaces/index.ErrorContext.html +0 -4
- package/docs/api/interfaces/index.FormReaderOptions.html +0 -8
- package/docs/api/interfaces/index.HttpOptions.html +0 -16
- package/docs/api/interfaces/index.HttpResponse.html +0 -17
- package/docs/api/interfaces/index.LoadRoute.html +0 -7
- package/docs/api/interfaces/index.NavigateOptions.html +0 -7
- package/docs/api/interfaces/index.PipeRegistry.html +0 -12
- package/docs/api/interfaces/index.RegistrationOptions.html +0 -22
- package/docs/api/interfaces/index.RenderTemplate.html +0 -7
- package/docs/api/interfaces/index.RequestOptions.html +0 -11
- package/docs/api/interfaces/index.Routable.html +0 -10
- package/docs/api/interfaces/index.Route.html +0 -13
- package/docs/api/interfaces/index.RouteGuard.html +0 -2
- package/docs/api/interfaces/index.RouteValue.html +0 -6
- package/docs/api/interfaces/index.SSEOptions.html +0 -24
- package/docs/api/interfaces/index.ValidationContext.html +0 -8
- package/docs/api/interfaces/index.ValidatorOptions.html +0 -14
- package/docs/api/media/Architecture.md +0 -333
- package/docs/api/media/DependencyInjection.md +0 -277
- package/docs/api/media/GettingStarted.md +0 -231
- package/docs/api/media/HttpClient.md +0 -459
- package/docs/api/media/Pipes.md +0 -211
- package/docs/api/media/Routing.md +0 -332
- package/docs/api/media/WhyRelaxjs.md +0 -336
- package/docs/api/media/forms.md +0 -99
- package/docs/api/media/html.md +0 -175
- package/docs/api/media/i18n.md +0 -354
- package/docs/api/media/utilities.md +0 -143
- package/docs/api/media/validation.md +0 -351
- package/docs/api/modules/collections_Index.html +0 -1
- package/docs/api/modules/di.html +0 -1
- package/docs/api/modules/elements.html +0 -1
- package/docs/api/modules/forms.html +0 -1
- package/docs/api/modules/html.html +0 -1
- package/docs/api/modules/http.html +0 -1
- package/docs/api/modules/i18n.html +0 -1
- package/docs/api/modules/index.html +0 -1
- package/docs/api/modules/routing.html +0 -1
- package/docs/api/modules/utils.html +0 -1
- package/docs/api/modules.html +0 -1
- package/docs/api/types/http.WebSocketFactory.html +0 -2
- package/docs/api/types/i18n.MessageFormatter.html +0 -3
- package/docs/api/types/i18n.MissingTranslationHandler.html +0 -1
- package/docs/api/types/index.Constructor.html +0 -7
- package/docs/api/types/index.ConverterFunc.html +0 -2
- package/docs/api/types/index.DataType.html +0 -2
- package/docs/api/types/index.InputType.html +0 -2
- package/docs/api/types/index.PipeFunction.html +0 -6
- package/docs/api/types/index.RouteData.html +0 -1
- package/docs/api/types/index.RouteMatchResult.html +0 -9
- package/docs/api/types/index.RouteParamType.html +0 -1
- package/docs/api/types/index.RouteSegmentType.html +0 -2
- package/docs/api/types/index.SSEEventFactory.html +0 -5
- package/docs/api/types/index.ServiceScope.html +0 -10
- package/docs/api/types/index.SortColumn.html +0 -3
- package/docs/api/variables/i18n.formatICU.html +0 -3
- package/docs/api/variables/index.container.html +0 -6
- package/docs/api/variables/index.defaultPipes.html +0 -6
- package/docs/api/variables/index.internalRoutes.html +0 -1
- package/docs/api/variables/index.serviceCollection.html +0 -6
package/dist/html/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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/html/index.ts", "../../src/i18n/icu.ts", "../../src/i18n/i18n.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"],
|
|
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", "export { html, RenderTemplate } from './html';\r\nexport { compileTemplate, EngineConfig, CompiledTemplate } from './template';\r\nexport * from '../templates/NodeTemplate';\r\nexport { TableRenderer, TableSorter, SortChangeEvent } from './TableRenderer';\r\nexport type { SortColumn } from './TableRenderer';\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 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\n * @internal\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\n * @internal\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, creating setters for mustache in attributes/text\r\n * 3. Render, resolving mustache against the iteration context\r\n * 4. Insert into DOM. 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, no connectedCallback yet)\r\n const instance = tpl.cloneNode(true) as Element;\r\n\r\n // 2-3. Compile + render while detached; 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. 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. 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; 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: 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\n/** @internal */\r\ntype ClickBinding = {\r\n path: number[];\r\n methodName: string;\r\n argTokens: ArgToken[];\r\n};\r\n\r\n/** @internal */\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, 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\n/** @internal */\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}"],
|
|
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", "index_exports", "__export", "Blueprint", "BoundNode", "SortChangeEvent", "TableRenderer", "TableSorter", "compileTemplate", "createBluePrint", "html", "__toCommonJS", "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", "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", "i", "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", "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"]
|
|
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", "export { html, RenderTemplate } from './html';\r\nexport { compileTemplate, EngineConfig, CompiledTemplate } from './template';\r\nexport * from '../templates/NodeTemplate';\r\nexport { TableRenderer, TableSorter, SortChangeEvent } from './TableRenderer';\r\nexport type { SortColumn } from './TableRenderer';\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 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) ?? null;\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 as any)[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 as any)[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.get(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\n * @internal\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\n * @internal\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, creating setters for mustache in attributes/text\r\n * 3. Render, resolving mustache against the iteration context\r\n * 4. Insert into DOM. 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, no connectedCallback yet)\r\n const instance = tpl.cloneNode(true) as Element;\r\n\r\n // 2-3. Compile + render while detached; 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. 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. 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; 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: 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\n/** @internal */\r\ntype ClickBinding = {\r\n path: number[];\r\n methodName: string;\r\n argTokens: ArgToken[];\r\n};\r\n\r\n/** @internal */\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 const componentOrEmpty = component ?? {};\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, componentOrEmpty, 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, componentOrEmpty, 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, 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\n/** @internal */\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((el) => {\r\n const th = el as 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}"],
|
|
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", "index_exports", "__export", "Blueprint", "BoundNode", "SortChangeEvent", "TableRenderer", "TableSorter", "compileTemplate", "createBluePrint", "html", "__toCommonJS", "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", "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", "i", "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", "componentOrEmpty", "boundBindings", "el", "walk", "func", "compileMustard", "targetNode", "element", "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"]
|
|
7
7
|
}
|