@relax.js/core 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +194 -188
  2. package/dist/DependencyInjection.d.ts +45 -27
  3. package/dist/collections/LinkedList.d.ts +9 -8
  4. package/dist/collections/index.js +1 -1
  5. package/dist/collections/index.js.map +3 -3
  6. package/dist/collections/index.mjs +1 -1
  7. package/dist/collections/index.mjs.map +3 -3
  8. package/dist/di/index.js +1 -1
  9. package/dist/di/index.js.map +3 -3
  10. package/dist/di/index.mjs +1 -1
  11. package/dist/di/index.mjs.map +3 -3
  12. package/dist/elements/index.js +1 -1
  13. package/dist/elements/index.js.map +1 -1
  14. package/dist/errors.d.ts +20 -0
  15. package/dist/forms/FormValidator.d.ts +3 -22
  16. package/dist/forms/ValidationRules.d.ts +4 -6
  17. package/dist/forms/index.js +1 -1
  18. package/dist/forms/index.js.map +4 -4
  19. package/dist/forms/index.mjs +1 -1
  20. package/dist/forms/index.mjs.map +4 -4
  21. package/dist/forms/setFormData.d.ts +39 -1
  22. package/dist/html/TableRenderer.d.ts +1 -0
  23. package/dist/html/index.js +1 -1
  24. package/dist/html/index.js.map +3 -3
  25. package/dist/html/index.mjs +1 -1
  26. package/dist/html/index.mjs.map +3 -3
  27. package/dist/html/template.d.ts +4 -0
  28. package/dist/http/ServerSentEvents.d.ts +1 -1
  29. package/dist/http/SimpleWebSocket.d.ts +1 -1
  30. package/dist/http/http.d.ts +1 -0
  31. package/dist/http/index.js +1 -1
  32. package/dist/http/index.js.map +3 -3
  33. package/dist/http/index.mjs +1 -1
  34. package/dist/http/index.mjs.map +3 -3
  35. package/dist/i18n/icu.d.ts +1 -1
  36. package/dist/i18n/index.js +1 -1
  37. package/dist/i18n/index.js.map +2 -2
  38. package/dist/i18n/index.mjs +1 -1
  39. package/dist/i18n/index.mjs.map +2 -2
  40. package/dist/index.js +3 -3
  41. package/dist/index.js.map +3 -3
  42. package/dist/index.mjs +3 -3
  43. package/dist/index.mjs.map +3 -3
  44. package/dist/routing/NavigateRouteEvent.d.ts +4 -4
  45. package/dist/routing/index.js +3 -3
  46. package/dist/routing/index.js.map +3 -3
  47. package/dist/routing/index.mjs +3 -3
  48. package/dist/routing/index.mjs.map +3 -3
  49. package/dist/routing/navigation.d.ts +1 -1
  50. package/dist/routing/routeTargetRegistry.d.ts +1 -0
  51. package/dist/routing/types.d.ts +2 -1
  52. package/dist/templates/NodeTemplate.d.ts +3 -1
  53. package/dist/utils/index.d.ts +1 -1
  54. package/dist/utils/index.js +1 -1
  55. package/dist/utils/index.js.map +3 -3
  56. package/dist/utils/index.mjs +1 -1
  57. package/dist/utils/index.mjs.map +3 -3
  58. package/docs/Architecture.md +333 -333
  59. package/docs/DependencyInjection.md +277 -237
  60. package/docs/Errors.md +87 -87
  61. package/docs/GettingStarted.md +238 -231
  62. package/docs/Pipes.md +5 -5
  63. package/docs/Translations.md +167 -312
  64. package/docs/WhyRelaxjs.md +336 -336
  65. package/docs/api.json +93193 -0
  66. package/docs/elements/dom.md +102 -102
  67. package/docs/forms/creating-form-components.md +924 -924
  68. package/docs/forms/form-api.md +94 -94
  69. package/docs/forms/forms.md +99 -99
  70. package/docs/forms/patterns.md +311 -311
  71. package/docs/forms/reading-writing.md +465 -365
  72. package/docs/forms/validation.md +351 -351
  73. package/docs/html/TableRenderer.md +291 -291
  74. package/docs/html/html.md +175 -175
  75. package/docs/html/index.md +54 -54
  76. package/docs/html/template.md +422 -422
  77. package/docs/http/HttpClient.md +459 -459
  78. package/docs/http/ServerSentEvents.md +184 -184
  79. package/docs/http/index.md +109 -109
  80. package/docs/i18n/i18n.md +49 -4
  81. package/docs/i18n/intl-standard.md +178 -178
  82. package/docs/routing/RouteLink.md +98 -98
  83. package/docs/routing/Routing.md +332 -332
  84. package/docs/routing/layouts.md +207 -207
  85. package/docs/setup/bootstrapping.md +154 -0
  86. package/docs/setup/build-and-deploy.md +183 -0
  87. package/docs/setup/project-structure.md +170 -0
  88. package/docs/setup/vite.md +175 -0
  89. package/docs/utilities.md +143 -143
  90. package/package.json +4 -2
@@ -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/utils/index.ts", "../../src/i18n/icu.ts", "../../src/i18n/i18n.ts", "../../src/pipes.ts", "../../src/tools.ts", "../../src/SequentialId.ts", "../../src/errors.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 * from '../pipes';\r\nexport * from '../tools';\r\nexport { generateSequentialId } from '../SequentialId';\r\nexport { onError, reportError, RelaxError } from '../errors';\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 * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n"],
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", "RelaxError", "applyPipes", "capitalizePipe", "createPipeRegistry", "currencyPipe", "datePipe", "daysAgoPipe", "defaultPipe", "defaultPipes", "firstPipe", "generateSequentialId", "joinPipe", "keysPipe", "lastPipe", "lowercasePipe", "onError", "piecesPipe", "reportError", "resolveValue", "shortenPipe", "ternaryPipe", "trimPipe", "uppercasePipe", "__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", "resolveValue", "path", "context", "value", "key", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed"]
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 * from '../pipes';\r\nexport * from '../tools';\r\nexport { generateSequentialId } from '../SequentialId';\r\nexport { onError, reportError, RelaxError, asyncHandler } from '../errors';\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 * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "index_exports", "__export", "RelaxError", "applyPipes", "asyncHandler", "capitalizePipe", "createPipeRegistry", "currencyPipe", "datePipe", "daysAgoPipe", "defaultPipe", "defaultPipes", "firstPipe", "generateSequentialId", "joinPipe", "keysPipe", "lastPipe", "lowercasePipe", "onError", "piecesPipe", "reportError", "resolveValue", "shortenPipe", "ternaryPipe", "trimPipe", "uppercasePipe", "__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", "resolveValue", "path", "context", "value", "key", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed", "asyncHandler", "args", "cause"]
7
7
  }
@@ -1,2 +1,2 @@
1
- var N=Object.create;var S=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var w=e=>t=>{var r=e[t];if(r)return r();throw new Error("Module not found in bundle: "+t)};var c=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var F=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!H.call(e,o)&&o!==r&&S(e,o,{get:()=>t[o],enumerable:!(n=_(t,o))||n.enumerable});return e};var u=(e,t,r)=>(r=e!=null?N(k(e)):{},F(t||!e||!e.__esModule?S(r,"default",{value:e,enumerable:!0}):r,e));var I=c((he,O)=>{O.exports={greeting:"Hello, {name}!",items:"{count, plural, one {# item} other {# items}}"}});var A=c((Ee,X)=>{X.exports={today:"today",yesterday:"yesterday",daysAgo:"{count, plural, one {# day ago} other {# days ago}}",pieces:"{count, plural, =0 {none} one {one} other {# pcs}}"}});var M=c((Se,v)=>{v.exports={required:"This field is required.",range:"Number must be between {min} and {max}, was {actual}.",digits:"Please enter only digits."}});var R=c((we,q)=>{q.exports={greeting:"Hej, {name}!",items:"{count, plural, one {# sak} other {# saker}}"}});var b=c((Te,z)=>{z.exports={today:"idag",yesterday:"ig\xE5r",daysAgo:"{count, plural, one {# dag sedan} other {# dagar sedan}}",pieces:"{count, plural, =0 {inga} one {en} other {# st}}"}});var D=c((Pe,V)=>{V.exports={required:"Detta f\xE4lt \xE4r obligatoriskt.",range:"Talet m\xE5ste vara mellan {min} och {max}, var {actual}.",digits:"Ange endast siffror."}});var m=new Map;function U(e){return m.has(e)||m.set(e,new Intl.PluralRules(e)),m.get(e)}function T(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function j(e,t,r="en"){return e.replace(/\{(\w+)(?:, (plural|select),((?:[^{}]*\{[^{}]*\})+))?\}/g,(n,o,i,a)=>{let s=t[o];if(i==="plural"){let p=new RegExp(`=${T(String(s))}\\s*\\{([^{}]*)\\}`).exec(a);if(p)return p[1].replace(`{${o}}`,String(s)).replace("#",String(s));let $=U(r).select(s),E=new RegExp(`${$}\\s*\\{([^{}]*)\\}`).exec(a)||new RegExp("other\\s*\\{([^{}]*)\\}").exec(a);return E?E[1].replace(`{${o}}`,String(s)).replace("#",String(s)):String(s)}if(i==="select"){let p=T(String(s)),f=new RegExp(`\\b${p}\\s*\\{([^{}]*)\\}`).exec(a)||new RegExp("\\bother\\s*\\{([^{}]*)\\}").exec(a);return f?f[1]:String(s)}return s!==void 0?String(s):`{${o}}`})}var P=j;var Me=w({"./locales/en/r-common.json":()=>Promise.resolve().then(()=>u(I())),"./locales/en/r-pipes.json":()=>Promise.resolve().then(()=>u(A())),"./locales/en/r-validation.json":()=>Promise.resolve().then(()=>u(M())),"./locales/sv/r-common.json":()=>Promise.resolve().then(()=>u(R())),"./locales/sv/r-pipes.json":()=>Promise.resolve().then(()=>u(b())),"./locales/sv/r-validation.json":()=>Promise.resolve().then(()=>u(D()))});var Z="en",y=Z;var G={},B=null;function l(e,t){let[r,n]=e.includes(":")?e.split(":"):["r-common",e],o=G[r]?.[n];if(!o)return B&&B(n,r,y),e;try{return P(o,t,y)}catch{return e}}function x(){return y}function J(e){return String(e).toUpperCase()}function Q(e){return String(e).trimEnd().trimStart()}function W(e){return String(e).toLowerCase()}function Y(e){let t=String(e);return t.charAt(0).toUpperCase()+t.slice(1)}function K(e,t){let r=String(e),n=parseInt(t,10);return r.length>n?r.substring(0,n-3)+"...":r}function ee(e,t="USD"){let r=x();return new Intl.NumberFormat(r,{style:"currency",currency:t}).format(e)}function te(e,t){let r=new Date(e),n=x();return t==="short"?r.toLocaleDateString(n):t==="long"?r.toLocaleDateString(n,{weekday:"long",year:"numeric",month:"long",day:"numeric"}):r.toISOString()}function re(e){if(!e)return"n/a";let t=new Date(e),r=new Date;t.setHours(0,0,0,0),r.setHours(0,0,0,0);let n=r.getTime()-t.getTime(),o=Math.round(n/(1e3*60*60*24));return o===0?l("r-pipes:today"):o===1?l("r-pipes:yesterday"):l("r-pipes:daysAgo",{count:o})}function ne(e){if(e==null)return"n/a";let t=Number(e);return l("r-pipes:pieces",{count:t})}function oe(e,t=","){return Array.isArray(e)?e.join(t):e}function se(e){return!Array.isArray(e)||e.length===0?"":e[0]}function ie(e){return!Array.isArray(e)||e.length===0?"":e[e.length-1]}function ae(e){return typeof e!="object"||e===null?[]:Object.keys(e)}function ce(e,t){return e||t}function ue(e,t,r){return e?t:r}function le(){let e=new Map;return e.set("uppercase",J),e.set("lowercase",W),e.set("capitalize",Y),e.set("trim",Q),e.set("shorten",K),e.set("currency",ee),e.set("date",te),e.set("daysAgo",re),e.set("pieces",ne),e.set("join",oe),e.set("first",se),e.set("last",ie),e.set("keys",ae),e.set("default",ce),e.set("ternary",ue),{lookup(t){return e.get(t)},get(t){var r=e.get(t);if(!r)throw Error("Pipe '"+t+"' not found.");return r},has(t){return e.has(t)}}}var pe=le();function Ce(e,t,r=pe){return t.reduce((n,o)=>{let[i,...a]=o.split(":").map(s=>s.trim());if(!r.has(i))return`[Pipe ${i} not found]`;try{return r.get(i)(n,...a)}catch(s){return`[Pipe ${i}, value: ${e}, error: ${s}]`}},e)}function Ne(e,t){let r=t;for(let n of e){if(r==null)return;r=r[n]}return r??void 0}var ge=Math.floor(new Date("2025-01-01T00:00:00Z").getTime()/1e3),C=0,g=0;function de(e){if(e<0||e>1048575)throw new Error("baseId must be between 0 and 1048575");let t=Math.floor(Date.now()/1e3);if(t===C){if(g++,g>255)throw new Error("Too many IDs generated in one second")}else C=t,g=0;let r=t-ge;if(r>1073741823)throw new Error("Timestamp exceeds allowed range (beyond 2045-01-01)");let n=BigInt(r),o=BigInt(g),i=BigInt(e);return(n<<BigInt(28)|o<<BigInt(20)|i).toString(36).toLowerCase()}var d=class extends Error{constructor(r,n){super(r);this.context=n}},h=null;function fe(e){h=e}function me(e,t){let r=new d(e,t);if(h){let n=!1;if(h(r,{suppress(){n=!0}}),n)return null}return r}export{d as RelaxError,Ce as applyPipes,Y as capitalizePipe,le as createPipeRegistry,ee as currencyPipe,te as datePipe,re as daysAgoPipe,ce as defaultPipe,pe as defaultPipes,se as firstPipe,de as generateSequentialId,oe as joinPipe,ae as keysPipe,ie as lastPipe,W as lowercasePipe,fe as onError,ne as piecesPipe,me as reportError,Ne as resolveValue,K as shortenPipe,ue as ternaryPipe,Q as trimPipe,J as uppercasePipe};
1
+ var N=Object.create;var E=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var H=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var S=e=>t=>{var r=e[t];if(r)return r();throw new Error("Module not found in bundle: "+t)};var c=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var U=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of L(t))!F.call(e,o)&&o!==r&&E(e,o,{get:()=>t[o],enumerable:!(n=_(t,o))||n.enumerable});return e};var l=(e,t,r)=>(r=e!=null?N(H(e)):{},U(t||!e||!e.__esModule?E(r,"default",{value:e,enumerable:!0}):r,e));var A=c((we,v)=>{v.exports={greeting:"Hello, {name}!",items:"{count, plural, one {# item} other {# items}}"}});var I=c((Ee,X)=>{X.exports={today:"today",yesterday:"yesterday",daysAgo:"{count, plural, one {# day ago} other {# days ago}}",pieces:"{count, plural, =0 {none} one {one} other {# pcs}}"}});var M=c((Se,q)=>{q.exports={required:"This field is required.",range:"Number must be between {min} and {max}, was {actual}.",digits:"Please enter only digits."}});var R=c((Te,z)=>{z.exports={greeting:"Hej, {name}!",items:"{count, plural, one {# sak} other {# saker}}"}});var b=c((Pe,V)=>{V.exports={today:"idag",yesterday:"ig\xE5r",daysAgo:"{count, plural, one {# dag sedan} other {# dagar sedan}}",pieces:"{count, plural, =0 {inga} one {en} other {# st}}"}});var D=c((Ae,Z)=>{Z.exports={required:"Detta f\xE4lt \xE4r obligatoriskt.",range:"Talet m\xE5ste vara mellan {min} och {max}, var {actual}.",digits:"Ange endast siffror."}});var m=new Map;function j(e){return m.has(e)||m.set(e,new Intl.PluralRules(e)),m.get(e)}function T(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function O(e,t,r="en"){return e.replace(/\{(\w+)(?:, (plural|select),((?:[^{}]*\{[^{}]*\})+))?\}/g,(n,o,i,a)=>{let s=t?.[o];if(i==="plural"){let p=new RegExp(`=${T(String(s))}\\s*\\{([^{}]*)\\}`).exec(a);if(p)return p[1].replace(`{${o}}`,String(s)).replace("#",String(s));let k=j(r).select(s),w=new RegExp(`${k}\\s*\\{([^{}]*)\\}`).exec(a)||new RegExp("other\\s*\\{([^{}]*)\\}").exec(a);return w?w[1].replace(`{${o}}`,String(s)).replace("#",String(s)):String(s)}if(i==="select"){let p=T(String(s)),f=new RegExp(`\\b${p}\\s*\\{([^{}]*)\\}`).exec(a)||new RegExp("\\bother\\s*\\{([^{}]*)\\}").exec(a);return f?f[1]:String(s)}return s!==void 0?String(s):`{${o}}`})}var P=O;var Re=S({"./locales/en/r-common.json":()=>Promise.resolve().then(()=>l(A())),"./locales/en/r-pipes.json":()=>Promise.resolve().then(()=>l(I())),"./locales/en/r-validation.json":()=>Promise.resolve().then(()=>l(M())),"./locales/sv/r-common.json":()=>Promise.resolve().then(()=>l(R())),"./locales/sv/r-pipes.json":()=>Promise.resolve().then(()=>l(b())),"./locales/sv/r-validation.json":()=>Promise.resolve().then(()=>l(D()))});var G="en",y=G;var J={},B=null;function u(e,t){let[r,n]=e.includes(":")?e.split(":"):["r-common",e],o=J[r]?.[n];if(!o)return B&&B(n,r,y),e;try{return P(o,t,y)}catch{return e}}function x(){return y}function Q(e){return String(e).toUpperCase()}function W(e){return String(e).trimEnd().trimStart()}function Y(e){return String(e).toLowerCase()}function K(e){let t=String(e);return t.charAt(0).toUpperCase()+t.slice(1)}function ee(e,t){let r=String(e),n=parseInt(t,10);return r.length>n?r.substring(0,n-3)+"...":r}function te(e,t="USD"){let r=x();return new Intl.NumberFormat(r,{style:"currency",currency:t}).format(e)}function re(e,t){let r=new Date(e),n=x();return t==="short"?r.toLocaleDateString(n):t==="long"?r.toLocaleDateString(n,{weekday:"long",year:"numeric",month:"long",day:"numeric"}):r.toISOString()}function ne(e){if(!e)return"n/a";let t=new Date(e),r=new Date;t.setHours(0,0,0,0),r.setHours(0,0,0,0);let n=r.getTime()-t.getTime(),o=Math.round(n/(1e3*60*60*24));return o===0?u("r-pipes:today"):o===1?u("r-pipes:yesterday"):u("r-pipes:daysAgo",{count:o})}function oe(e){if(e==null)return"n/a";let t=Number(e);return u("r-pipes:pieces",{count:t})}function se(e,t=","){return Array.isArray(e)?e.join(t):e}function ie(e){return!Array.isArray(e)||e.length===0?"":e[0]}function ae(e){return!Array.isArray(e)||e.length===0?"":e[e.length-1]}function ce(e){return typeof e!="object"||e===null?[]:Object.keys(e)}function le(e,t){return e||t}function ue(e,t,r){return e?t:r}function pe(){let e=new Map;return e.set("uppercase",Q),e.set("lowercase",Y),e.set("capitalize",K),e.set("trim",W),e.set("shorten",ee),e.set("currency",te),e.set("date",re),e.set("daysAgo",ne),e.set("pieces",oe),e.set("join",se),e.set("first",ie),e.set("last",ae),e.set("keys",ce),e.set("default",le),e.set("ternary",ue),{lookup(t){return e.get(t)??null},get(t){var r=e.get(t);if(!r)throw Error("Pipe '"+t+"' not found.");return r},has(t){return e.has(t)}}}var ge=pe();function $e(e,t,r=ge){return t.reduce((n,o)=>{let[i,...a]=o.split(":").map(s=>s.trim());if(!r.has(i))return`[Pipe ${i} not found]`;try{return r.get(i)(n,...a)}catch(s){return`[Pipe ${i}, value: ${e}, error: ${s}]`}},e)}function Ne(e,t){let r=t;for(let n of e){if(r==null)return;r=r[n]}return r??void 0}var de=Math.floor(new Date("2025-01-01T00:00:00Z").getTime()/1e3),C=0,g=0;function fe(e){if(e<0||e>1048575)throw new Error("baseId must be between 0 and 1048575");let t=Math.floor(Date.now()/1e3);if(t===C){if(g++,g>255)throw new Error("Too many IDs generated in one second")}else C=t,g=0;let r=t-de;if(r>1073741823)throw new Error("Timestamp exceeds allowed range (beyond 2045-01-01)");let n=BigInt(r),o=BigInt(g),i=BigInt(e);return(n<<BigInt(28)|o<<BigInt(20)|i).toString(36).toLowerCase()}var d=class extends Error{constructor(r,n){super(r);this.context=n}},h=null;function me(e){h=e}function $(e,t){let r=new d(e,t);if(h){let n=!1;if(h(r,{suppress(){n=!0}}),n)return null}return r}function ye(e){return function(...t){e.call(this,...t).catch(r=>{let n=$("Async callback failed",{cause:r});if(n)throw n})}}export{d as RelaxError,$e as applyPipes,ye as asyncHandler,K as capitalizePipe,pe as createPipeRegistry,te as currencyPipe,re as datePipe,ne as daysAgoPipe,le as defaultPipe,ge as defaultPipes,ie as firstPipe,fe as generateSequentialId,se as joinPipe,ce as keysPipe,ae as lastPipe,Y as lowercasePipe,me as onError,oe as piecesPipe,$ as reportError,Ne as resolveValue,ee as shortenPipe,ue as ternaryPipe,W as trimPipe,Q as uppercasePipe};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -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/i18n/icu.ts", "../../src/i18n/i18n.ts", "../../src/pipes.ts", "../../src/tools.ts", "../../src/SequentialId.ts", "../../src/errors.ts"],
4
- "sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "/**\r\n * @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 * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n"],
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", "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", "resolveValue", "path", "context", "value", "key", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed"]
4
+ "sourcesContent": ["{\r\n \"greeting\": \"Hello, {name}!\",\r\n \"items\": \"{count, plural, one {# item} other {# items}}\"\r\n}\r\n", "{\r\n \"today\": \"today\",\r\n \"yesterday\": \"yesterday\",\r\n \"daysAgo\": \"{count, plural, one {# day ago} other {# days ago}}\",\r\n \"pieces\": \"{count, plural, =0 {none} one {one} other {# pcs}}\"\r\n}\r\n", "{\r\n \"required\": \"This field is required.\",\r\n \"range\": \"Number must be between {min} and {max}, was {actual}.\",\r\n \"digits\": \"Please enter only digits.\"\r\n}\r\n", "{\r\n \"greeting\": \"Hej, {name}!\",\r\n \"items\": \"{count, plural, one {# sak} other {# saker}}\"\r\n}\r\n", "{\r\n \"today\": \"idag\",\r\n \"yesterday\": \"ig\u00E5r\",\r\n \"daysAgo\": \"{count, plural, one {# dag sedan} other {# dagar sedan}}\",\r\n \"pieces\": \"{count, plural, =0 {inga} one {en} other {# st}}\"\r\n}\r\n", "{\r\n \"required\": \"Detta f\u00E4lt \u00E4r obligatoriskt.\",\r\n \"range\": \"Talet m\u00E5ste vara mellan {min} och {max}, var {actual}.\",\r\n \"digits\": \"Ange endast siffror.\"\r\n}\r\n", "/**\r\n * @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 * Resolves a deeply nested value from an object using a path array.\r\n * Safely navigates through the object tree, returning undefined if any\r\n * segment in the path is null or undefined.\r\n *\r\n * Used internally by template engines to access data properties,\r\n * but also useful for general-purpose deep property access.\r\n *\r\n * @param path - Array of property names forming the path to the value\r\n * @param context - The object to resolve the value from\r\n * @returns The resolved value, or undefined if path cannot be resolved\r\n *\r\n * @example\r\n * // Access nested property\r\n * const user = { address: { city: 'Stockholm' } };\r\n * const city = resolveValue(['address', 'city'], user);\r\n * // Returns: 'Stockholm'\r\n *\r\n * @example\r\n * // Safe access with missing properties\r\n * const data = { user: null };\r\n * const name = resolveValue(['user', 'name'], data);\r\n * // Returns: undefined (doesn't throw)\r\n *\r\n * @example\r\n * // Use with template expression paths\r\n * const path = 'user.profile.avatar'.split('.');\r\n * const avatar = resolveValue(path, context);\r\n */\r\nexport function resolveValue(\r\n path: string[],\r\n context: Record<string, any>\r\n): any | undefined {\r\n let value = context;\r\n\r\n for (const key of path) {\r\n if (value === undefined || value === null) {\r\n return undefined;\r\n }\r\n\r\n value = value[key];\r\n }\r\n\r\n return value !== undefined && value !== null ? value : undefined;\r\n}\r\n ", "/**\r\n * @module SequentialId\r\n * Generates compact, time-ordered unique identifiers suitable for distributed systems.\r\n *\r\n * IDs are structured to be:\r\n * - Unique across multiple clients (via baseId)\r\n * - Time-sortable (timestamp is the most significant bits)\r\n * - Compact (Base36 encoding produces short strings)\r\n *\r\n * Bit allocation (58 bits total):\r\n * - 30 bits for timestamp (seconds since January 1, 2025)\r\n * - 8 bits for per-second counter (supports 256 IDs/second)\r\n * - 20 bits for client/endpoint identifier (supports ~1M unique sources)\r\n */\r\n\r\nconst TIMESTAMP_BITS = 30;\r\nconst COUNTER_BITS = 8;\r\nconst BASEID_BITS = 20;\r\n\r\nconst MAX_TIMESTAMP = (1 << TIMESTAMP_BITS) - 1;\r\nconst MAX_COUNTER = (1 << COUNTER_BITS) - 1;\r\nconst MAX_BASEID = (1 << BASEID_BITS) - 1;\r\n\r\nconst EPOCH = Math.floor(new Date('2025-01-01T00:00:00Z').getTime() / 1000);\r\n\r\nlet lastTimestamp = 0;\r\nlet counter = 0;\r\n\r\n/**\r\n * Generates a unique, time-ordered sequential ID.\r\n *\r\n * The ID combines a timestamp, per-second counter, and client identifier\r\n * into a compact Base36 string. IDs generated later will sort after earlier IDs,\r\n * making them suitable for ordered collections.\r\n *\r\n * @param baseId - Unique identifier for the client/endpoint (0 to 1,048,575).\r\n * Use different baseIds for different servers or processes to\r\n * avoid collisions.\r\n * @returns Base36 encoded string representing the unique ID\r\n * @throws Error if baseId is out of valid range\r\n * @throws Error if more than 256 IDs are generated in a single second\r\n * @throws Error if timestamp exceeds range (after year 2045)\r\n *\r\n * @example\r\n * // Generate ID for server instance 1\r\n * const id1 = generateSequentialId(1);\r\n * // Returns something like: 'k2j8m3n5p'\r\n *\r\n * @example\r\n * // Different servers use different baseIds\r\n * const SERVER_ID = parseInt(process.env.SERVER_ID || '0');\r\n * const orderId = generateSequentialId(SERVER_ID);\r\n *\r\n * @example\r\n * // IDs are time-sortable\r\n * const id1 = generateSequentialId(0);\r\n * await delay(1000);\r\n * const id2 = generateSequentialId(0);\r\n * console.log(id1 < id2); // true (lexicographic comparison works)\r\n */\r\nexport function generateSequentialId(baseId: number): string {\r\n if (baseId < 0 || baseId > MAX_BASEID) {\r\n throw new Error(`baseId must be between 0 and ${MAX_BASEID}`);\r\n }\r\n\r\n const now = Math.floor(Date.now() / 1000);\r\n if (now === lastTimestamp) {\r\n counter++;\r\n if (counter > MAX_COUNTER) {\r\n throw new Error('Too many IDs generated in one second');\r\n }\r\n } else {\r\n lastTimestamp = now;\r\n counter = 0;\r\n }\r\n\r\n const timestamp = now - EPOCH;\r\n if (timestamp > MAX_TIMESTAMP) {\r\n throw new Error('Timestamp exceeds allowed range (beyond 2045-01-01)');\r\n }\r\n\r\n const ts = BigInt(timestamp);\r\n const cnt = BigInt(counter);\r\n const uid = BigInt(baseId);\r\n\r\n // [ timestamp (30 bits) | counter (8 bits) | baseId (20 bits) ]\r\n const id =\r\n (ts << BigInt(COUNTER_BITS + BASEID_BITS)) |\r\n (cnt << BigInt(BASEID_BITS)) |\r\n uid;\r\n\r\n return id.toString(36).toLowerCase();\r\n}\r\n", "/**\r\n * Global error handling for Relaxjs.\r\n * Register a handler with `onError()` to intercept errors before they throw.\r\n * Call `ctx.suppress()` in the handler to prevent the error from being thrown.\r\n *\r\n * @example\r\n * import { onError } from 'relaxjs';\r\n *\r\n * onError((error, ctx) => {\r\n * logToService(error.message, error.context);\r\n * showToast(error.message);\r\n * ctx.suppress();\r\n * });\r\n */\r\n\r\n/**\r\n * Passed to error handlers to control error behavior.\r\n * Call `suppress()` to prevent the error from being thrown.\r\n */\r\nexport interface ErrorContext {\r\n suppress(): void;\r\n}\r\n\r\n/**\r\n * Error with structured context for debugging.\r\n * The `context` record contains details like route name, component tag, route data.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * console.log(error.context.route);\r\n * console.log(error.context.componentTagName);\r\n * });\r\n */\r\nexport class RelaxError extends Error {\r\n constructor(\r\n message: string,\r\n public context: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n }\r\n}\r\n\r\n/** @internal */\r\ntype ErrorHandler = (error: RelaxError, ctx: ErrorContext) => void;\r\n\r\nlet handler: ErrorHandler | null = null;\r\n\r\n/**\r\n * Registers a global error handler for Relaxjs errors.\r\n * The handler receives the error and an `ErrorContext`.\r\n * Call `ctx.suppress()` to prevent the error from being thrown.\r\n * Only one handler can be active at a time; subsequent calls replace the previous handler.\r\n *\r\n * @example\r\n * onError((error, ctx) => {\r\n * if (error.context.route === 'optional-panel') {\r\n * ctx.suppress();\r\n * return;\r\n * }\r\n * showErrorDialog(error.message);\r\n * });\r\n */\r\nexport function onError(fn: ErrorHandler) {\r\n handler = fn;\r\n}\r\n\r\n/**\r\n * Reports an error through the global handler.\r\n * Returns the `RelaxError` if it should be thrown, or `null` if the handler suppressed it.\r\n * The caller is responsible for throwing the returned error.\r\n *\r\n * @param message - Human-readable error description\r\n * @param context - Structured data for debugging (route, component, params, cause, etc.)\r\n * @returns The error to throw, or `null` if suppressed\r\n *\r\n * @example\r\n * const error = reportError('Failed to load route component', {\r\n * route: 'user',\r\n * componentTagName: 'user-profile',\r\n * routeData: { id: 123 },\r\n * });\r\n * if (error) throw error;\r\n */\r\nexport function reportError(message: string, context: Record<string, unknown>): RelaxError | null {\r\n const error = new RelaxError(message, context);\r\n if (handler) {\r\n let suppressed = false;\r\n const ctx: ErrorContext = {\r\n suppress() { suppressed = true; },\r\n };\r\n handler(error, ctx);\r\n if (suppressed) {\r\n return null;\r\n }\r\n }\r\n return error;\r\n}\r\n\r\n/**\r\n * Wraps an async function into a synchronous callback suitable for addEventListener.\r\n * Catches promise rejections and reports them through the global error handler.\r\n *\r\n * @param fn - Async function to wrap\r\n * @returns Synchronous function that can be passed to addEventListener\r\n *\r\n * @example\r\n * button.addEventListener('click', asyncHandler(async (e) => {\r\n * await saveData();\r\n * }));\r\n *\r\n * @example\r\n * form.addEventListener('submit', asyncHandler(async (e) => {\r\n * e.preventDefault();\r\n * await submitForm();\r\n * }));\r\n */\r\nexport function asyncHandler<TArgs extends unknown[]>(\r\n fn: (...args: TArgs) => Promise<void>,\r\n): (...args: TArgs) => void {\r\n return function (this: any, ...args: TArgs) {\r\n fn.call(this, ...args).catch((cause: unknown) => {\r\n const error = reportError('Async callback failed', { cause });\r\n if (error) throw error;\r\n });\r\n };\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": ["require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "require_r_common", "__commonJSMin", "exports", "module", "require_r_pipes", "__commonJSMin", "exports", "module", "require_r_validation", "__commonJSMin", "exports", "module", "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", "resolveValue", "path", "context", "value", "key", "EPOCH", "lastTimestamp", "counter", "generateSequentialId", "baseId", "now", "timestamp", "ts", "cnt", "uid", "RelaxError", "message", "context", "handler", "onError", "fn", "reportError", "error", "suppressed", "asyncHandler", "args", "cause"]
7
7
  }