rune-lab 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +12 -0
- package/README.md +3 -3
- package/deno.json +50 -0
- package/justfile +5 -0
- package/package.json +2 -79
- package/scripts/build_pkg.ts +51 -0
- package/scripts/ci.just +26 -0
- package/scripts/deploy.just +21 -0
- package/scripts/dev.just +4 -0
- package/scripts/inject.just +72 -0
- package/src/RuneProvider.svelte +105 -0
- package/src/i18n/message-resolver.test.ts +103 -0
- package/src/i18n/message-resolver.ts +89 -0
- package/src/i18n/project.inlang/settings.json +26 -0
- package/src/i18n/translations/ar.json +89 -0
- package/src/i18n/translations/de.json +89 -0
- package/src/i18n/translations/en.json +89 -0
- package/src/i18n/translations/es.json +89 -0
- package/src/i18n/translations/fr.json +89 -0
- package/src/i18n/translations/hi.json +89 -0
- package/src/i18n/translations/it.json +89 -0
- package/src/i18n/translations/ja.json +89 -0
- package/src/i18n/translations/ko.json +89 -0
- package/src/i18n/translations/pt.json +89 -0
- package/src/i18n/translations/ru.json +89 -0
- package/src/i18n/translations/vi.json +89 -0
- package/src/i18n/translations/zh.json +89 -0
- package/src/kernel/deno.json +5 -0
- package/src/kernel/src/actions/portal.ts +41 -0
- package/src/kernel/src/actions/shortcut-listener.ts +50 -0
- package/src/kernel/src/context/app.svelte.ts +98 -0
- package/src/kernel/src/context/context.ts +31 -0
- package/src/kernel/src/context/stores.svelte.ts +96 -0
- package/src/kernel/src/context/types.ts +110 -0
- package/src/kernel/src/context/useRuneLab.ts +38 -0
- package/src/kernel/src/mod.ts +13 -0
- package/src/kernel/src/persistence/createConfigStore.svelte.ts +120 -0
- package/src/kernel/src/persistence/drivers.test.ts +95 -0
- package/src/kernel/src/persistence/drivers.ts +77 -0
- package/src/kernel/src/persistence/provider.test.ts +58 -0
- package/{dist/state/persistence/provider.js → src/kernel/src/persistence/provider.ts} +29 -14
- package/src/kernel/src/persistence/types.ts +19 -0
- package/src/kernel/src/persistence/usePersistence.ts +9 -0
- package/src/kernel/src/registry/mod.ts +221 -0
- package/src/kernel/src/registry/registry.test.ts +162 -0
- package/src/kernel/src/tokens/props.ts +94 -0
- package/src/mod.ts +10 -0
- package/src/runes/layout/deno.json +5 -0
- package/src/runes/layout/src/APP_CONFIGURATIONS.ts +56 -0
- package/{dist/ui/features/config → src/runes/layout/src}/AppSettingSelector.svelte +1 -1
- package/{dist/ui/layout → src/runes/layout/src}/ConnectedNavigationPanel.svelte +1 -1
- package/{dist/ui/layout → src/runes/layout/src}/ConnectedWorkspaceStrip.svelte +1 -1
- package/src/runes/layout/src/Icon.svelte +7 -0
- package/{dist/ui/features/config → src/runes/layout/src}/LanguageSelector.svelte +7 -5
- package/{dist/ui/layout → src/runes/layout/src}/NavigationPanel.svelte +1 -4
- package/{dist/ui/features/config → src/runes/layout/src}/ResourceSelector.svelte +3 -5
- package/{dist/ui/features/config → src/runes/layout/src}/ThemeSelector.svelte +2 -2
- package/{dist/ui/layout → src/runes/layout/src}/WorkspaceLayout.svelte +6 -4
- package/{dist/ui/layout → src/runes/layout/src}/WorkspaceStrip.svelte +1 -1
- package/src/runes/layout/src/connection-factory.ts +95 -0
- package/src/runes/layout/src/language.svelte.ts +44 -0
- package/src/runes/layout/src/mod.ts +71 -0
- package/src/runes/layout/src/store.svelte.ts +142 -0
- package/src/runes/layout/src/theme.svelte.ts +73 -0
- package/src/runes/layout/src/types.ts +11 -0
- package/src/runes/palettes/deno.json +8 -0
- package/{dist/ui/features/command-palette → src/runes/palettes/src/commands}/CommandPalette.svelte +4 -4
- package/src/runes/palettes/src/commands/mod.ts +2 -0
- package/src/runes/palettes/src/commands/store.svelte.ts +80 -0
- package/src/runes/palettes/src/mod.ts +51 -0
- package/{dist/ui/components → src/runes/palettes/src/notifications}/Toaster.svelte +1 -2
- package/src/runes/palettes/src/notifications/bridge.ts +56 -0
- package/src/runes/palettes/src/notifications/mod.ts +4 -0
- package/src/runes/palettes/src/notifications/store.svelte.ts +58 -0
- package/{dist/ui/features → src/runes/palettes/src}/shortcuts/ShortcutPalette.svelte +4 -4
- package/src/runes/palettes/src/shortcuts/mod.ts +4 -0
- package/src/runes/palettes/src/shortcuts/store.svelte.ts +85 -0
- package/src/runes/palettes/src/shortcuts/types.ts +4 -0
- package/src/runes/palettes/src/shortcuts/useShortcuts.ts +85 -0
- package/src/runes/plugins/money/deno.json +8 -0
- package/{dist/ui/features/config → src/runes/plugins/money/src}/CurrencySelector.svelte +2 -2
- package/{dist/ui/components/money → src/runes/plugins/money/src}/MoneyDisplay.svelte +2 -2
- package/{dist/ui/components/money → src/runes/plugins/money/src}/MoneyInput.svelte +4 -8
- package/src/runes/plugins/money/src/currency.svelte.ts +95 -0
- package/src/runes/plugins/money/src/currency.test.ts +40 -0
- package/src/runes/plugins/money/src/exchange-rate.svelte.ts +176 -0
- package/src/runes/plugins/money/src/exchange-rate.test.ts +95 -0
- package/src/runes/plugins/money/src/mod.ts +79 -0
- package/src/runes/plugins/money/src/money-primitive.test.ts +217 -0
- package/src/runes/plugins/money/src/money-primitive.ts +220 -0
- package/src/runes/plugins/money/src/money.test.ts +183 -0
- package/src/runes/plugins/money/src/money.ts +382 -0
- package/src/runes/plugins/money/src/strategies.test.ts +143 -0
- package/{dist/core/exchange-rate/strategies.js → src/runes/plugins/money/src/strategies.ts} +45 -22
- package/src/runes/plugins/money/src/types.ts +27 -0
- package/src/runes/plugins/money/src/useMoney.ts +261 -0
- package/src/runes/plugins/money/src/useMoneyFilter.ts +132 -0
- package/tsconfig.json +41 -0
- package/vite.config.ts +44 -0
- package/dist/core/design-tokens/props.d.ts +0 -52
- package/dist/core/design-tokens/props.d.ts.map +0 -1
- package/dist/core/design-tokens/props.js +0 -34
- package/dist/core/exchange-rate/strategies.d.ts +0 -52
- package/dist/core/exchange-rate/strategies.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -9
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -8
- package/dist/core/internal/message-resolver.d.ts +0 -42
- package/dist/core/internal/message-resolver.d.ts.map +0 -1
- package/dist/core/internal/message-resolver.js +0 -47
- package/dist/core/layout/types.d.ts +0 -60
- package/dist/core/layout/types.d.ts.map +0 -1
- package/dist/core/layout/types.js +0 -4
- package/dist/core/money/index.d.ts +0 -2
- package/dist/core/money/index.d.ts.map +0 -1
- package/dist/core/money/index.js +0 -2
- package/dist/core/money/money-primitive.d.ts +0 -101
- package/dist/core/money/money-primitive.d.ts.map +0 -1
- package/dist/core/money/money-primitive.js +0 -161
- package/dist/core/money/money.d.ts +0 -129
- package/dist/core/money/money.d.ts.map +0 -1
- package/dist/core/money/money.js +0 -250
- package/dist/core/persistence/types.d.ts +0 -18
- package/dist/core/persistence/types.d.ts.map +0 -1
- package/dist/core/persistence/types.js +0 -2
- package/dist/core/shortcuts/types.d.ts +0 -60
- package/dist/core/shortcuts/types.d.ts.map +0 -1
- package/dist/core/shortcuts/types.js +0 -4
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -7
- package/dist/state/api.svelte.d.ts +0 -26
- package/dist/state/api.svelte.js +0 -65
- package/dist/state/app.svelte.d.ts +0 -48
- package/dist/state/app.svelte.js +0 -82
- package/dist/state/auth/index.d.ts +0 -2
- package/dist/state/auth/index.js +0 -2
- package/dist/state/auth/session.svelte.d.ts +0 -40
- package/dist/state/auth/session.svelte.js +0 -59
- package/dist/state/auth/types.d.ts +0 -30
- package/dist/state/auth/types.js +0 -3
- package/dist/state/cart.svelte.d.ts +0 -64
- package/dist/state/cart.svelte.js +0 -122
- package/dist/state/commands.svelte.d.ts +0 -46
- package/dist/state/commands.svelte.js +0 -62
- package/dist/state/composables/useMoney.d.ts +0 -31
- package/dist/state/composables/useMoney.js +0 -126
- package/dist/state/composables/useMoneyFilter.d.ts +0 -20
- package/dist/state/composables/useMoneyFilter.js +0 -81
- package/dist/state/composables/usePersistence.d.ts +0 -2
- package/dist/state/composables/usePersistence.js +0 -5
- package/dist/state/composables/useRuneLab.d.ts +0 -19
- package/dist/state/composables/useRuneLab.js +0 -30
- package/dist/state/composables/useShortcuts.d.ts +0 -33
- package/dist/state/composables/useShortcuts.js +0 -75
- package/dist/state/context.d.ts +0 -15
- package/dist/state/context.js +0 -16
- package/dist/state/createConfigStore.svelte.d.ts +0 -28
- package/dist/state/createConfigStore.svelte.js +0 -72
- package/dist/state/currency.svelte.d.ts +0 -32
- package/dist/state/currency.svelte.js +0 -96
- package/dist/state/currency.test.d.ts +0 -1
- package/dist/state/currency.test.js +0 -35
- package/dist/state/exchange-rate.svelte.d.ts +0 -43
- package/dist/state/exchange-rate.svelte.js +0 -145
- package/dist/state/exchange-rate.test.d.ts +0 -1
- package/dist/state/exchange-rate.test.js +0 -75
- package/dist/state/index.d.ts +0 -26
- package/dist/state/index.js +0 -32
- package/dist/state/language.svelte.d.ts +0 -57
- package/dist/state/language.svelte.js +0 -43
- package/dist/state/layout.svelte.d.ts +0 -49
- package/dist/state/layout.svelte.js +0 -108
- package/dist/state/persistence/drivers.d.ts +0 -12
- package/dist/state/persistence/drivers.js +0 -75
- package/dist/state/persistence/drivers.test.d.ts +0 -1
- package/dist/state/persistence/drivers.test.js +0 -79
- package/dist/state/persistence/provider.d.ts +0 -23
- package/dist/state/persistence/provider.test.d.ts +0 -1
- package/dist/state/persistence/provider.test.js +0 -51
- package/dist/state/registry/index.d.ts +0 -44
- package/dist/state/registry/index.js +0 -58
- package/dist/state/registry/registry.test.d.ts +0 -1
- package/dist/state/registry/registry.test.js +0 -112
- package/dist/state/registry/types.d.ts +0 -20
- package/dist/state/registry/types.js +0 -3
- package/dist/state/shortcuts.svelte.d.ts +0 -121
- package/dist/state/shortcuts.svelte.js +0 -222
- package/dist/state/theme.svelte.d.ts +0 -15
- package/dist/state/theme.svelte.js +0 -92
- package/dist/state/toast-bridge.d.ts +0 -29
- package/dist/state/toast-bridge.js +0 -43
- package/dist/state/toast.svelte.d.ts +0 -27
- package/dist/state/toast.svelte.js +0 -43
- package/dist/ui/actions/portal.d.ts +0 -7
- package/dist/ui/actions/portal.js +0 -32
- package/dist/ui/components/ApiMonitor.svelte +0 -162
- package/dist/ui/components/ApiMonitor.svelte.d.ts +0 -3
- package/dist/ui/components/Icon.svelte +0 -108
- package/dist/ui/components/Icon.svelte.d.ts +0 -14
- package/dist/ui/components/Kyntharil.svelte +0 -48
- package/dist/ui/components/Kyntharil.svelte.d.ts +0 -6
- package/dist/ui/components/RuneProvider.svelte +0 -218
- package/dist/ui/components/RuneProvider.svelte.d.ts +0 -49
- package/dist/ui/components/Toaster.svelte.d.ts +0 -18
- package/dist/ui/components/money/MoneyDisplay.svelte.d.ts +0 -33
- package/dist/ui/components/money/MoneyDisplay.svelte.test.d.ts +0 -1
- package/dist/ui/components/money/MoneyDisplay.svelte.test.js +0 -117
- package/dist/ui/components/money/MoneyInput.svelte.d.ts +0 -34
- package/dist/ui/components/money/index.d.ts +0 -2
- package/dist/ui/components/money/index.js +0 -3
- package/dist/ui/components/user/UserAvatar.svelte +0 -66
- package/dist/ui/components/user/UserAvatar.svelte.d.ts +0 -13
- package/dist/ui/components/user/UserProfile.svelte +0 -79
- package/dist/ui/components/user/UserProfile.svelte.d.ts +0 -17
- package/dist/ui/components/user/index.d.ts +0 -2
- package/dist/ui/components/user/index.js +0 -3
- package/dist/ui/features/command-palette/CommandPalette.svelte.d.ts +0 -6
- package/dist/ui/features/config/APP_CONFIGURATIONS.d.ts +0 -29
- package/dist/ui/features/config/APP_CONFIGURATIONS.js +0 -38
- package/dist/ui/features/config/AppSettingSelector.svelte.d.ts +0 -13
- package/dist/ui/features/config/CurrencySelector.svelte.d.ts +0 -8
- package/dist/ui/features/config/LanguageSelector.svelte.d.ts +0 -8
- package/dist/ui/features/config/ResourceSelector.svelte.d.ts +0 -25
- package/dist/ui/features/config/ThemeSelector.svelte.d.ts +0 -8
- package/dist/ui/features/notifications/NotificationBell.svelte.d.ts +0 -11
- package/dist/ui/features/notifications/index.d.ts +0 -1
- package/dist/ui/features/notifications/index.js +0 -2
- package/dist/ui/features/shortcuts/ShortcutBinder.svelte +0 -17
- package/dist/ui/features/shortcuts/ShortcutBinder.svelte.d.ts +0 -7
- package/dist/ui/features/shortcuts/ShortcutPalette.svelte.d.ts +0 -6
- package/dist/ui/index.d.ts +0 -30
- package/dist/ui/index.js +0 -46
- package/dist/ui/layout/ConnectedNavigationPanel.svelte.d.ts +0 -10
- package/dist/ui/layout/ConnectedWorkspaceStrip.svelte.d.ts +0 -9
- package/dist/ui/layout/ContentArea.svelte.d.ts +0 -8
- package/dist/ui/layout/DetailPanel.svelte.d.ts +0 -7
- package/dist/ui/layout/NavigationPanel.svelte.d.ts +0 -14
- package/dist/ui/layout/WorkspaceLayout.svelte.d.ts +0 -32
- package/dist/ui/layout/WorkspaceStrip.svelte.d.ts +0 -11
- package/dist/ui/layout/connection-factory.d.ts +0 -50
- package/dist/ui/layout/connection-factory.js +0 -58
- package/dist/ui/layout/index.d.ts +0 -7
- package/dist/ui/layout/index.js +0 -7
- package/dist/ui/paraglide/README.md +0 -147
- package/dist/ui/paraglide/messages/_index.d.ts +0 -87
- package/dist/ui/paraglide/messages/_index.js +0 -88
- package/dist/ui/paraglide/messages/abyss.d.ts +0 -16
- package/dist/ui/paraglide/messages/abyss.js +0 -84
- package/dist/ui/paraglide/messages/acid.d.ts +0 -16
- package/dist/ui/paraglide/messages/acid.js +0 -84
- package/dist/ui/paraglide/messages/active_toasts.d.ts +0 -16
- package/dist/ui/paraglide/messages/active_toasts.js +0 -84
- package/dist/ui/paraglide/messages/aed3.d.ts +0 -17
- package/dist/ui/paraglide/messages/aed3.js +0 -85
- package/dist/ui/paraglide/messages/all_currencies.d.ts +0 -16
- package/dist/ui/paraglide/messages/all_currencies.js +0 -84
- package/dist/ui/paraglide/messages/all_languages.d.ts +0 -16
- package/dist/ui/paraglide/messages/all_languages.js +0 -84
- package/dist/ui/paraglide/messages/all_themes.d.ts +0 -16
- package/dist/ui/paraglide/messages/all_themes.js +0 -84
- package/dist/ui/paraglide/messages/api_status.d.ts +0 -16
- package/dist/ui/paraglide/messages/api_status.js +0 -84
- package/dist/ui/paraglide/messages/app_info.d.ts +0 -16
- package/dist/ui/paraglide/messages/app_info.js +0 -84
- package/dist/ui/paraglide/messages/appearance.d.ts +0 -16
- package/dist/ui/paraglide/messages/appearance.js +0 -84
- package/dist/ui/paraglide/messages/aqua.d.ts +0 -16
- package/dist/ui/paraglide/messages/aqua.js +0 -84
- package/dist/ui/paraglide/messages/ar.d.ts +0 -16
- package/dist/ui/paraglide/messages/ar.js +0 -84
- package/dist/ui/paraglide/messages/autumn.d.ts +0 -16
- package/dist/ui/paraglide/messages/autumn.js +0 -84
- package/dist/ui/paraglide/messages/black.d.ts +0 -16
- package/dist/ui/paraglide/messages/black.js +0 -84
- package/dist/ui/paraglide/messages/brl3.d.ts +0 -17
- package/dist/ui/paraglide/messages/brl3.js +0 -85
- package/dist/ui/paraglide/messages/bumblebee.d.ts +0 -16
- package/dist/ui/paraglide/messages/bumblebee.js +0 -84
- package/dist/ui/paraglide/messages/business.d.ts +0 -16
- package/dist/ui/paraglide/messages/business.js +0 -84
- package/dist/ui/paraglide/messages/cad3.d.ts +0 -17
- package/dist/ui/paraglide/messages/cad3.js +0 -85
- package/dist/ui/paraglide/messages/caramellatte.d.ts +0 -16
- package/dist/ui/paraglide/messages/caramellatte.js +0 -84
- package/dist/ui/paraglide/messages/cmyk.d.ts +0 -16
- package/dist/ui/paraglide/messages/cmyk.js +0 -84
- package/dist/ui/paraglide/messages/cny3.d.ts +0 -17
- package/dist/ui/paraglide/messages/cny3.js +0 -85
- package/dist/ui/paraglide/messages/coffee.d.ts +0 -16
- package/dist/ui/paraglide/messages/coffee.js +0 -84
- package/dist/ui/paraglide/messages/commands_label.d.ts +0 -16
- package/dist/ui/paraglide/messages/commands_label.js +0 -84
- package/dist/ui/paraglide/messages/corporate.d.ts +0 -16
- package/dist/ui/paraglide/messages/corporate.js +0 -84
- package/dist/ui/paraglide/messages/cupcake.d.ts +0 -16
- package/dist/ui/paraglide/messages/cupcake.js +0 -84
- package/dist/ui/paraglide/messages/currency.d.ts +0 -16
- package/dist/ui/paraglide/messages/currency.js +0 -84
- package/dist/ui/paraglide/messages/current_currency.d.ts +0 -16
- package/dist/ui/paraglide/messages/current_currency.js +0 -84
- package/dist/ui/paraglide/messages/current_language.d.ts +0 -16
- package/dist/ui/paraglide/messages/current_language.js +0 -84
- package/dist/ui/paraglide/messages/current_theme.d.ts +0 -16
- package/dist/ui/paraglide/messages/current_theme.js +0 -84
- package/dist/ui/paraglide/messages/currently_in_queue.d.ts +0 -16
- package/dist/ui/paraglide/messages/currently_in_queue.js +0 -84
- package/dist/ui/paraglide/messages/cyberpunk.d.ts +0 -16
- package/dist/ui/paraglide/messages/cyberpunk.js +0 -84
- package/dist/ui/paraglide/messages/dark.d.ts +0 -16
- package/dist/ui/paraglide/messages/dark.js +0 -84
- package/dist/ui/paraglide/messages/de.d.ts +0 -16
- package/dist/ui/paraglide/messages/de.js +0 -84
- package/dist/ui/paraglide/messages/dim.d.ts +0 -16
- package/dist/ui/paraglide/messages/dim.js +0 -84
- package/dist/ui/paraglide/messages/dracula.d.ts +0 -16
- package/dist/ui/paraglide/messages/dracula.js +0 -84
- package/dist/ui/paraglide/messages/emerald.d.ts +0 -16
- package/dist/ui/paraglide/messages/emerald.js +0 -84
- package/dist/ui/paraglide/messages/en.d.ts +0 -16
- package/dist/ui/paraglide/messages/en.js +0 -84
- package/dist/ui/paraglide/messages/es.d.ts +0 -16
- package/dist/ui/paraglide/messages/es.js +0 -84
- package/dist/ui/paraglide/messages/eur3.d.ts +0 -17
- package/dist/ui/paraglide/messages/eur3.js +0 -85
- package/dist/ui/paraglide/messages/extended_controls.d.ts +0 -16
- package/dist/ui/paraglide/messages/extended_controls.js +0 -84
- package/dist/ui/paraglide/messages/fantasy.d.ts +0 -16
- package/dist/ui/paraglide/messages/fantasy.js +0 -84
- package/dist/ui/paraglide/messages/forest.d.ts +0 -16
- package/dist/ui/paraglide/messages/forest.js +0 -84
- package/dist/ui/paraglide/messages/fr.d.ts +0 -16
- package/dist/ui/paraglide/messages/fr.js +0 -84
- package/dist/ui/paraglide/messages/garden.d.ts +0 -16
- package/dist/ui/paraglide/messages/garden.js +0 -84
- package/dist/ui/paraglide/messages/gbp3.d.ts +0 -17
- package/dist/ui/paraglide/messages/gbp3.js +0 -85
- package/dist/ui/paraglide/messages/halloween.d.ts +0 -16
- package/dist/ui/paraglide/messages/halloween.js +0 -84
- package/dist/ui/paraglide/messages/hello_world.d.ts +0 -18
- package/dist/ui/paraglide/messages/hello_world.js +0 -84
- package/dist/ui/paraglide/messages/hi.d.ts +0 -16
- package/dist/ui/paraglide/messages/hi.js +0 -84
- package/dist/ui/paraglide/messages/inr3.d.ts +0 -17
- package/dist/ui/paraglide/messages/inr3.js +0 -85
- package/dist/ui/paraglide/messages/it.d.ts +0 -16
- package/dist/ui/paraglide/messages/it.js +0 -84
- package/dist/ui/paraglide/messages/ja.d.ts +0 -16
- package/dist/ui/paraglide/messages/ja.js +0 -84
- package/dist/ui/paraglide/messages/jpy3.d.ts +0 -17
- package/dist/ui/paraglide/messages/jpy3.js +0 -85
- package/dist/ui/paraglide/messages/ko.d.ts +0 -16
- package/dist/ui/paraglide/messages/ko.js +0 -84
- package/dist/ui/paraglide/messages/krw3.d.ts +0 -17
- package/dist/ui/paraglide/messages/krw3.js +0 -85
- package/dist/ui/paraglide/messages/languages.d.ts +0 -16
- package/dist/ui/paraglide/messages/languages.js +0 -84
- package/dist/ui/paraglide/messages/lemonade.d.ts +0 -16
- package/dist/ui/paraglide/messages/lemonade.js +0 -84
- package/dist/ui/paraglide/messages/light.d.ts +0 -16
- package/dist/ui/paraglide/messages/light.js +0 -84
- package/dist/ui/paraglide/messages/live_store_dashboard.d.ts +0 -16
- package/dist/ui/paraglide/messages/live_store_dashboard.js +0 -84
- package/dist/ui/paraglide/messages/localization.d.ts +0 -16
- package/dist/ui/paraglide/messages/localization.js +0 -84
- package/dist/ui/paraglide/messages/lofi.d.ts +0 -16
- package/dist/ui/paraglide/messages/lofi.js +0 -84
- package/dist/ui/paraglide/messages/luxury.d.ts +0 -16
- package/dist/ui/paraglide/messages/luxury.js +0 -84
- package/dist/ui/paraglide/messages/mxn3.d.ts +0 -17
- package/dist/ui/paraglide/messages/mxn3.js +0 -85
- package/dist/ui/paraglide/messages/name_label.d.ts +0 -16
- package/dist/ui/paraglide/messages/name_label.js +0 -84
- package/dist/ui/paraglide/messages/night.d.ts +0 -16
- package/dist/ui/paraglide/messages/night.js +0 -84
- package/dist/ui/paraglide/messages/nord.d.ts +0 -16
- package/dist/ui/paraglide/messages/nord.js +0 -84
- package/dist/ui/paraglide/messages/pastel.d.ts +0 -16
- package/dist/ui/paraglide/messages/pastel.js +0 -84
- package/dist/ui/paraglide/messages/pt.d.ts +0 -16
- package/dist/ui/paraglide/messages/pt.js +0 -84
- package/dist/ui/paraglide/messages/real_time_monitor_desc.d.ts +0 -16
- package/dist/ui/paraglide/messages/real_time_monitor_desc.js +0 -84
- package/dist/ui/paraglide/messages/registered_in_registry.d.ts +0 -16
- package/dist/ui/paraglide/messages/registered_in_registry.js +0 -84
- package/dist/ui/paraglide/messages/retro.d.ts +0 -16
- package/dist/ui/paraglide/messages/retro.js +0 -84
- package/dist/ui/paraglide/messages/ru.d.ts +0 -16
- package/dist/ui/paraglide/messages/ru.js +0 -84
- package/dist/ui/paraglide/messages/silk.d.ts +0 -16
- package/dist/ui/paraglide/messages/silk.js +0 -84
- package/dist/ui/paraglide/messages/state_label.d.ts +0 -16
- package/dist/ui/paraglide/messages/state_label.js +0 -84
- package/dist/ui/paraglide/messages/sunset.d.ts +0 -16
- package/dist/ui/paraglide/messages/sunset.js +0 -84
- package/dist/ui/paraglide/messages/synthwave.d.ts +0 -16
- package/dist/ui/paraglide/messages/synthwave.js +0 -84
- package/dist/ui/paraglide/messages/system.d.ts +0 -16
- package/dist/ui/paraglide/messages/system.js +0 -84
- package/dist/ui/paraglide/messages/theme.d.ts +0 -16
- package/dist/ui/paraglide/messages/theme.js +0 -84
- package/dist/ui/paraglide/messages/themes.d.ts +0 -16
- package/dist/ui/paraglide/messages/themes.js +0 -84
- package/dist/ui/paraglide/messages/url_label.d.ts +0 -16
- package/dist/ui/paraglide/messages/url_label.js +0 -84
- package/dist/ui/paraglide/messages/usd3.d.ts +0 -17
- package/dist/ui/paraglide/messages/usd3.js +0 -85
- package/dist/ui/paraglide/messages/valentine.d.ts +0 -16
- package/dist/ui/paraglide/messages/valentine.js +0 -84
- package/dist/ui/paraglide/messages/version_label.d.ts +0 -16
- package/dist/ui/paraglide/messages/version_label.js +0 -84
- package/dist/ui/paraglide/messages/vi.d.ts +0 -16
- package/dist/ui/paraglide/messages/vi.js +0 -84
- package/dist/ui/paraglide/messages/winter.d.ts +0 -16
- package/dist/ui/paraglide/messages/winter.js +0 -84
- package/dist/ui/paraglide/messages/wireframe.d.ts +0 -16
- package/dist/ui/paraglide/messages/wireframe.js +0 -84
- package/dist/ui/paraglide/messages/zh.d.ts +0 -16
- package/dist/ui/paraglide/messages/zh.js +0 -84
- package/dist/ui/paraglide/messages.d.ts +0 -2
- package/dist/ui/paraglide/messages.js +0 -4
- package/dist/ui/paraglide/registry.d.ts +0 -21
- package/dist/ui/paraglide/registry.js +0 -31
- package/dist/ui/paraglide/runtime.d.ts +0 -730
- package/dist/ui/paraglide/runtime.js +0 -1812
- package/dist/ui/paraglide/server.d.ts +0 -92
- package/dist/ui/paraglide/server.js +0 -239
- package/dist/ui/primitives/DatePicker.svelte +0 -257
- package/dist/ui/primitives/DatePicker.svelte.d.ts +0 -17
- package/dist/ui/primitives/index.d.ts +0 -1
- package/dist/ui/primitives/index.js +0 -3
- /package/{dist/ui/layout → src/runes/layout/src}/ContentArea.svelte +0 -0
- /package/{dist/ui/layout → src/runes/layout/src}/DetailPanel.svelte +0 -0
- /package/{dist/ui/features → src/runes/palettes/src}/notifications/NotificationBell.svelte +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// sdk/state/src/exchange-rate.svelte.ts
|
|
2
|
+
|
|
3
|
+
import { getContext } from "svelte";
|
|
4
|
+
import {
|
|
5
|
+
convertMoney,
|
|
6
|
+
createMoney,
|
|
7
|
+
CURRENCY_MAP,
|
|
8
|
+
directConversion,
|
|
9
|
+
inverseConversion,
|
|
10
|
+
type RateMap,
|
|
11
|
+
resolveRate,
|
|
12
|
+
type ScaledRate,
|
|
13
|
+
scaledRate,
|
|
14
|
+
toMoneySnapshot,
|
|
15
|
+
triangularConversion,
|
|
16
|
+
} from "@rune-lab/money";
|
|
17
|
+
import { RUNE_LAB_CONTEXT } from "@rune-lab/kernel";
|
|
18
|
+
|
|
19
|
+
export class ExchangeRateStore {
|
|
20
|
+
#rates = $state<RateMap>({});
|
|
21
|
+
#baseCurrency = $state<string>("USD");
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The current exchange rates relative to the base currency.
|
|
25
|
+
*/
|
|
26
|
+
get rates(): RateMap {
|
|
27
|
+
return this.#rates;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The base currency all rates are relative to.
|
|
32
|
+
*/
|
|
33
|
+
get baseCurrency(): string {
|
|
34
|
+
return this.#baseCurrency;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns true if exchange rates have been loaded.
|
|
39
|
+
*/
|
|
40
|
+
get hasRates(): boolean {
|
|
41
|
+
return Object.keys(this.#rates).length > 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Set exchange rates from a human-readable float map.
|
|
46
|
+
* @param base - The base currency code (e.g., "USD")
|
|
47
|
+
* @param rawRates - A map of currency codes to float rates (e.g., { MXN: 17.23 })
|
|
48
|
+
*/
|
|
49
|
+
setRates(base: string, rawRates: Record<string, number>) {
|
|
50
|
+
const nextRates: RateMap = {};
|
|
51
|
+
for (const [code, rate] of Object.entries(rawRates)) {
|
|
52
|
+
nextRates[code] = scaledRate(rate, 4);
|
|
53
|
+
}
|
|
54
|
+
this.#baseCurrency = base;
|
|
55
|
+
this.#rates = nextRates;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Directly set pre-scaled rates.
|
|
60
|
+
*/
|
|
61
|
+
setScaledRates(base: string, rates: RateMap) {
|
|
62
|
+
this.#baseCurrency = base;
|
|
63
|
+
this.#rates = rates;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Resolves the exchange rate between two currencies.
|
|
68
|
+
* Returns a ScaledRate representing how many units of toCode are in 1 unit of fromCode.
|
|
69
|
+
*/
|
|
70
|
+
getRate(fromCode: string, toCode: string): ScaledRate | number | undefined {
|
|
71
|
+
if (fromCode === toCode) return 1;
|
|
72
|
+
|
|
73
|
+
const fromCurrency = CURRENCY_MAP[fromCode];
|
|
74
|
+
const toCurrency = CURRENCY_MAP[toCode];
|
|
75
|
+
if (!fromCurrency || !toCurrency) return undefined;
|
|
76
|
+
|
|
77
|
+
if (!this.hasRates) return undefined;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
// 1 unit of fromCode (major unit)
|
|
81
|
+
const oneUnit = Math.pow(
|
|
82
|
+
Array.isArray(fromCurrency.base)
|
|
83
|
+
? fromCurrency.base[0]
|
|
84
|
+
: fromCurrency.base,
|
|
85
|
+
fromCurrency.exponent,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const currentRates = this.#rates;
|
|
89
|
+
const currentBase = this.#baseCurrency;
|
|
90
|
+
|
|
91
|
+
const sourceMoney = createMoney(oneUnit, fromCode);
|
|
92
|
+
|
|
93
|
+
let targetMoney;
|
|
94
|
+
if (fromCode === currentBase) {
|
|
95
|
+
// Direct: base → target
|
|
96
|
+
targetMoney = convertMoney(sourceMoney, toCode, currentRates);
|
|
97
|
+
} else if (toCode === currentBase) {
|
|
98
|
+
// Inverse: target → base
|
|
99
|
+
const rateToBase = currentRates[fromCode];
|
|
100
|
+
if (!rateToBase) return undefined;
|
|
101
|
+
const r = resolveRate(rateToBase);
|
|
102
|
+
targetMoney = convertMoney(sourceMoney, toCode, {
|
|
103
|
+
[toCode]: scaledRate(1 / r, 6),
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
// Triangular: source → base → target
|
|
107
|
+
const rateToBase = currentRates[fromCode];
|
|
108
|
+
const rateToTarget = currentRates[toCode];
|
|
109
|
+
if (!rateToBase || !rateToTarget) return undefined;
|
|
110
|
+
|
|
111
|
+
const r1 = resolveRate(rateToBase);
|
|
112
|
+
const r2 = resolveRate(rateToTarget);
|
|
113
|
+
|
|
114
|
+
targetMoney = convertMoney(sourceMoney, toCode, {
|
|
115
|
+
[toCode]: scaledRate(r2 / r1, 6),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const snapshot = toMoneySnapshot(targetMoney);
|
|
120
|
+
return {
|
|
121
|
+
amount: snapshot.amount,
|
|
122
|
+
scale: snapshot.scale,
|
|
123
|
+
};
|
|
124
|
+
} catch (_err) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Internal conversion logic that handles triangulation through base currency.
|
|
131
|
+
* Delegates all math to ConversionStrategies (directConversion, inverseConversion, triangularConversion).
|
|
132
|
+
*/
|
|
133
|
+
convertAmount(amount: number, fromCode: string, toCode: string): number {
|
|
134
|
+
if (fromCode === toCode) return amount;
|
|
135
|
+
if (!this.hasRates) return amount;
|
|
136
|
+
|
|
137
|
+
// Direct: Base → Target
|
|
138
|
+
if (fromCode === this.#baseCurrency) {
|
|
139
|
+
const rateToTarget = this.#rates[toCode];
|
|
140
|
+
if (!rateToTarget) return amount;
|
|
141
|
+
return directConversion(amount, resolveRate(rateToTarget));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Inverse: Target → Base
|
|
145
|
+
if (toCode === this.#baseCurrency) {
|
|
146
|
+
const rateFromSource = this.#rates[fromCode];
|
|
147
|
+
if (!rateFromSource) return amount;
|
|
148
|
+
return inverseConversion(amount, resolveRate(rateFromSource));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Triangulation: From → Base → To
|
|
152
|
+
const rateFromSource = this.#rates[fromCode];
|
|
153
|
+
const rateToTarget = this.#rates[toCode];
|
|
154
|
+
if (!rateFromSource || !rateToTarget) return amount;
|
|
155
|
+
|
|
156
|
+
return triangularConversion(
|
|
157
|
+
amount,
|
|
158
|
+
resolveRate(rateFromSource),
|
|
159
|
+
resolveRate(rateToTarget),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Factory to create the ExchangeRateStore.
|
|
166
|
+
*/
|
|
167
|
+
export function createExchangeRateStore(): ExchangeRateStore {
|
|
168
|
+
return new ExchangeRateStore();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Consumer to retrieve the ExchangeRateStore from context.
|
|
173
|
+
*/
|
|
174
|
+
export function getExchangeRateStore(): ExchangeRateStore {
|
|
175
|
+
return getContext<ExchangeRateStore>(RUNE_LAB_CONTEXT.exchangeRate);
|
|
176
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vite-plus/test";
|
|
2
|
+
import { ExchangeRateStore } from "./exchange-rate.svelte.ts";
|
|
3
|
+
import { currencyStore, setExchangeRateStore } from "./currency.svelte.ts";
|
|
4
|
+
import { inMemoryDriver, RUNE_LAB_CONTEXT } from "@rune-lab/kernel";
|
|
5
|
+
import { languageStore } from "../../../layout/src/language.svelte.ts";
|
|
6
|
+
|
|
7
|
+
// Mock useMoney since it uses getContext and other stores
|
|
8
|
+
vi.mock("./useMoney.ts", () => ({
|
|
9
|
+
useMoney: () => ({
|
|
10
|
+
format: (amount: number, code?: string, _unit?: unknown) =>
|
|
11
|
+
`${amount} ${code ?? "USD"}`,
|
|
12
|
+
}),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe("ExchangeRateStore", () => {
|
|
16
|
+
it("should initialize with default base", () => {
|
|
17
|
+
const store = new ExchangeRateStore();
|
|
18
|
+
expect(store.baseCurrency).toBe("USD");
|
|
19
|
+
expect(store.hasRates).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should set and retrieve rates", () => {
|
|
23
|
+
const store = new ExchangeRateStore();
|
|
24
|
+
store.setRates("USD", { MXN: 17.23, EUR: 0.91 });
|
|
25
|
+
|
|
26
|
+
expect(store.hasRates).toBe(true);
|
|
27
|
+
expect(store.baseCurrency).toBe("USD");
|
|
28
|
+
|
|
29
|
+
const rateToMxn = store.getRate("USD", "MXN");
|
|
30
|
+
expect(rateToMxn).toEqual({ amount: 17230000, scale: 6 });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should handle inverse rates", () => {
|
|
34
|
+
const store = new ExchangeRateStore();
|
|
35
|
+
store.setRates("USD", { MXN: 20 });
|
|
36
|
+
|
|
37
|
+
const rateToBase = store.getRate("MXN", "USD");
|
|
38
|
+
expect(rateToBase).toEqual({ amount: 5000000, scale: 8 });
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should handle triangulation (cross-rates)", () => {
|
|
42
|
+
const store = new ExchangeRateStore();
|
|
43
|
+
store.setRates("USD", { MXN: 20, EUR: 0.5 });
|
|
44
|
+
|
|
45
|
+
const rateMxnToEur = store.getRate("MXN", "EUR");
|
|
46
|
+
expect(rateMxnToEur).toEqual({ amount: 2500000, scale: 8 });
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe("CurrencyStore Integration", () => {
|
|
51
|
+
it("should convert amount when ExchangeRateStore is wired", () => {
|
|
52
|
+
const exchangeRateStore = new ExchangeRateStore();
|
|
53
|
+
exchangeRateStore.setRates("USD", { MXN: 20 });
|
|
54
|
+
|
|
55
|
+
setExchangeRateStore(exchangeRateStore);
|
|
56
|
+
|
|
57
|
+
expect(currencyStore.canConvert).toBe(true);
|
|
58
|
+
|
|
59
|
+
const converted = currencyStore.convertAmount(10000, "USD", "MXN");
|
|
60
|
+
expect(converted).toBe(200000);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should return original amount if no rates available", () => {
|
|
64
|
+
const exchangeRateStore = new ExchangeRateStore();
|
|
65
|
+
setExchangeRateStore(exchangeRateStore);
|
|
66
|
+
|
|
67
|
+
expect(currencyStore.canConvert).toBe(false);
|
|
68
|
+
|
|
69
|
+
const converted = currencyStore.convertAmount(10000, "USD", "MXN");
|
|
70
|
+
expect(converted).toBe(10000);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("useMoneyFilter", () => {
|
|
75
|
+
// Simple test for logic, skipping full component mount for brevity
|
|
76
|
+
it("matches() should work with conversion", () => {
|
|
77
|
+
const exchangeRateStore = new ExchangeRateStore();
|
|
78
|
+
exchangeRateStore.setRates("USD", { MXN: 20 });
|
|
79
|
+
|
|
80
|
+
setExchangeRateStore(exchangeRateStore);
|
|
81
|
+
|
|
82
|
+
// Manual mock of context for the composable
|
|
83
|
+
// In a real test we'd use render() from @testing-library/svelte
|
|
84
|
+
const mockContext = new Map();
|
|
85
|
+
mockContext.set(RUNE_LAB_CONTEXT.currency, currencyStore);
|
|
86
|
+
mockContext.set(RUNE_LAB_CONTEXT.exchangeRate, exchangeRateStore);
|
|
87
|
+
mockContext.set(RUNE_LAB_CONTEXT.language, languageStore);
|
|
88
|
+
|
|
89
|
+
// We can't easily call useMoneyFilter outside component without more setup
|
|
90
|
+
// but we can verify the matches logic in CurrencyStore
|
|
91
|
+
const amountInMxn = 1000000; // 10,000 MXN
|
|
92
|
+
const amountInUsd = currencyStore.convertAmount(amountInMxn, "MXN", "USD");
|
|
93
|
+
expect(amountInUsd).toBe(50000); // 500 USD
|
|
94
|
+
});
|
|
95
|
+
});
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { defineRune, RUNE_LAB_CONTEXT } from "@rune-lab/kernel";
|
|
2
|
+
import type { PersistenceDriver, RunePlugin } from "@rune-lab/kernel";
|
|
3
|
+
import {
|
|
4
|
+
type Currency,
|
|
5
|
+
currencyStore,
|
|
6
|
+
setExchangeRateStore,
|
|
7
|
+
} from "./currency.svelte.ts";
|
|
8
|
+
import { createExchangeRateStore } from "./exchange-rate.svelte.ts";
|
|
9
|
+
import type { ExchangeRateStore } from "./exchange-rate.svelte.ts";
|
|
10
|
+
|
|
11
|
+
export * from "./currency.svelte.ts";
|
|
12
|
+
export * from "./exchange-rate.svelte.ts";
|
|
13
|
+
export * from "./types.ts";
|
|
14
|
+
export * from "./money.ts";
|
|
15
|
+
export * from "./strategies.ts";
|
|
16
|
+
export * from "./money-primitive.ts";
|
|
17
|
+
export * from "./useMoney.ts";
|
|
18
|
+
export * from "./useMoneyFilter.ts";
|
|
19
|
+
|
|
20
|
+
interface MoneyConfig {
|
|
21
|
+
exchangeRates?: {
|
|
22
|
+
base: string;
|
|
23
|
+
rates: Record<string, number>;
|
|
24
|
+
};
|
|
25
|
+
currencies?: Currency[];
|
|
26
|
+
defaultCurrency?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Money Plugin — provides currency management and exchange rate conversion.
|
|
31
|
+
*/
|
|
32
|
+
export const MoneyPlugin: RunePlugin = defineRune({
|
|
33
|
+
id: "rune-lab.money",
|
|
34
|
+
stores: [
|
|
35
|
+
{
|
|
36
|
+
id: "exchangeRate",
|
|
37
|
+
contextKey: RUNE_LAB_CONTEXT.exchangeRate,
|
|
38
|
+
factory: (config: unknown) => {
|
|
39
|
+
const store = createExchangeRateStore();
|
|
40
|
+
const c = config as MoneyConfig;
|
|
41
|
+
if (c?.exchangeRates) {
|
|
42
|
+
store.setRates(c.exchangeRates.base, c.exchangeRates.rates);
|
|
43
|
+
}
|
|
44
|
+
return store;
|
|
45
|
+
},
|
|
46
|
+
noPersistence: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "currency",
|
|
50
|
+
contextKey: RUNE_LAB_CONTEXT.currency,
|
|
51
|
+
factory: (
|
|
52
|
+
config: unknown,
|
|
53
|
+
_driver: PersistenceDriver,
|
|
54
|
+
stores: Map<string, unknown>,
|
|
55
|
+
) => {
|
|
56
|
+
const c = config as MoneyConfig;
|
|
57
|
+
setExchangeRateStore(stores.get("exchangeRate") as ExchangeRateStore);
|
|
58
|
+
|
|
59
|
+
if (c?.currencies) {
|
|
60
|
+
for (const cur of c.currencies) {
|
|
61
|
+
currencyStore.addCurrency(cur);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
c?.defaultCurrency &&
|
|
67
|
+
!(currencyStore as unknown as { current: unknown }).current
|
|
68
|
+
) {
|
|
69
|
+
if (currencyStore.get(c.defaultCurrency as never)) {
|
|
70
|
+
currencyStore.set(c.defaultCurrency as never);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return currencyStore;
|
|
75
|
+
},
|
|
76
|
+
dependsOn: ["exchangeRate"],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
});
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { describe, expect, it } from "vite-plus/test";
|
|
2
|
+
import { MoneyPrimitive } from "./money-primitive.ts";
|
|
3
|
+
import { registerCurrency } from "./money.ts";
|
|
4
|
+
|
|
5
|
+
describe("MoneyPrimitive", () => {
|
|
6
|
+
describe("Construction", () => {
|
|
7
|
+
it("should create from minor units", () => {
|
|
8
|
+
const money = MoneyPrimitive.fromMinor(1299, "USD");
|
|
9
|
+
expect(money.amount).toBe(1299);
|
|
10
|
+
expect(money.currencyCode).toBe("USD");
|
|
11
|
+
expect(money.scale).toBe(2);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should create from major units", () => {
|
|
15
|
+
const money = MoneyPrimitive.fromMajor(12.99, "USD");
|
|
16
|
+
expect(money.amount).toBe(1299);
|
|
17
|
+
expect(money.currencyCode).toBe("USD");
|
|
18
|
+
expect(money.scale).toBe(2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should round fractional minor units", () => {
|
|
22
|
+
const money = MoneyPrimitive.fromMajor(12.999, "USD");
|
|
23
|
+
expect(money.amount).toBe(1300); // rounded
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should throw for unknown currency", () => {
|
|
27
|
+
expect(() => MoneyPrimitive.fromMinor(100, "UNKNOWN")).toThrow(
|
|
28
|
+
"Unknown currency code",
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("JPY (exponent 0)", () => {
|
|
34
|
+
it("should handle zero-exponent currencies", () => {
|
|
35
|
+
const yen = MoneyPrimitive.fromMinor(5000, "JPY");
|
|
36
|
+
expect(yen.minor).toBe(5000);
|
|
37
|
+
expect(yen.major).toBe(5000); // no decimal shift for JPY
|
|
38
|
+
expect(yen.scale).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("should create from major with no decimal shift", () => {
|
|
42
|
+
const yen = MoneyPrimitive.fromMajor(5000, "JPY");
|
|
43
|
+
expect(yen.amount).toBe(5000);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("BHD (exponent 3)", () => {
|
|
48
|
+
it("should handle 3-exponent currencies", () => {
|
|
49
|
+
const BHD = { code: "BHD", base: 10, exponent: 3 };
|
|
50
|
+
registerCurrency("BHD", BHD);
|
|
51
|
+
|
|
52
|
+
const dinar = MoneyPrimitive.fromMajor(1.234, "BHD");
|
|
53
|
+
expect(dinar.amount).toBe(1234);
|
|
54
|
+
expect(dinar.major).toBe(1.234);
|
|
55
|
+
expect(dinar.scale).toBe(3);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("Getters", () => {
|
|
60
|
+
it(".minor returns the raw amount", () => {
|
|
61
|
+
const money = MoneyPrimitive.fromMinor(1500, "USD");
|
|
62
|
+
expect(money.minor).toBe(1500);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it(".major returns the human-readable float", () => {
|
|
66
|
+
const money = MoneyPrimitive.fromMinor(1500, "USD");
|
|
67
|
+
expect(money.major).toBe(15.0);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it(".major handles MXN (exponent 2)", () => {
|
|
71
|
+
const money = MoneyPrimitive.fromMinor(25050, "MXN");
|
|
72
|
+
expect(money.major).toBe(250.5);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("Formatting", () => {
|
|
77
|
+
it("should format USD in en-US", () => {
|
|
78
|
+
const money = MoneyPrimitive.fromMinor(1299, "USD");
|
|
79
|
+
expect(money.format("en-US")).toMatch(/\$12\.99/);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should format MXN in es-MX", () => {
|
|
83
|
+
const money = MoneyPrimitive.fromMinor(25050, "MXN");
|
|
84
|
+
expect(money.format("es-MX")).toMatch(/\$250\.50/);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should format JPY with no decimals", () => {
|
|
88
|
+
const money = MoneyPrimitive.fromMinor(5000, "JPY");
|
|
89
|
+
const formatted = money.format("ja-JP");
|
|
90
|
+
expect(formatted).toMatch(/5,000/);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("Arithmetic (immutability)", () => {
|
|
95
|
+
it("add returns a new instance", () => {
|
|
96
|
+
const a = MoneyPrimitive.fromMinor(1000, "USD");
|
|
97
|
+
const b = MoneyPrimitive.fromMinor(500, "USD");
|
|
98
|
+
const result = a.add(b);
|
|
99
|
+
|
|
100
|
+
expect(result.amount).toBe(1500);
|
|
101
|
+
expect(result).not.toBe(a); // new instance
|
|
102
|
+
expect(a.amount).toBe(1000); // original unchanged
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("subtract returns a new instance", () => {
|
|
106
|
+
const a = MoneyPrimitive.fromMinor(1000, "USD");
|
|
107
|
+
const b = MoneyPrimitive.fromMinor(300, "USD");
|
|
108
|
+
const result = a.subtract(b);
|
|
109
|
+
|
|
110
|
+
expect(result.amount).toBe(700);
|
|
111
|
+
expect(a.amount).toBe(1000);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("multiply returns a new instance", () => {
|
|
115
|
+
const money = MoneyPrimitive.fromMinor(1000, "USD");
|
|
116
|
+
const result = money.multiply(2.5);
|
|
117
|
+
|
|
118
|
+
expect(result.amount).toBe(2500);
|
|
119
|
+
expect(money.amount).toBe(1000);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("multiply rounds correctly", () => {
|
|
123
|
+
const money = MoneyPrimitive.fromMinor(100, "USD");
|
|
124
|
+
const result = money.multiply(0.33);
|
|
125
|
+
|
|
126
|
+
expect(result.amount).toBe(33);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("throws on currency mismatch for add", () => {
|
|
130
|
+
const usd = MoneyPrimitive.fromMinor(100, "USD");
|
|
131
|
+
const eur = MoneyPrimitive.fromMinor(100, "EUR");
|
|
132
|
+
|
|
133
|
+
expect(() => usd.add(eur)).toThrow("Currency mismatch");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("throws on currency mismatch for subtract", () => {
|
|
137
|
+
const usd = MoneyPrimitive.fromMinor(100, "USD");
|
|
138
|
+
const eur = MoneyPrimitive.fromMinor(100, "EUR");
|
|
139
|
+
|
|
140
|
+
expect(() => usd.subtract(eur)).toThrow("Currency mismatch");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("Comparison", () => {
|
|
145
|
+
it("equals returns true for identical values", () => {
|
|
146
|
+
const a = MoneyPrimitive.fromMinor(1000, "USD");
|
|
147
|
+
const b = MoneyPrimitive.fromMinor(1000, "USD");
|
|
148
|
+
expect(a.equals(b)).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("equals returns false for different amounts", () => {
|
|
152
|
+
const a = MoneyPrimitive.fromMinor(1000, "USD");
|
|
153
|
+
const b = MoneyPrimitive.fromMinor(2000, "USD");
|
|
154
|
+
expect(a.equals(b)).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("equals returns false for different currencies", () => {
|
|
158
|
+
const a = MoneyPrimitive.fromMinor(1000, "USD");
|
|
159
|
+
const b = MoneyPrimitive.fromMinor(1000, "EUR");
|
|
160
|
+
expect(a.equals(b)).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("isZero returns true for zero amount", () => {
|
|
164
|
+
expect(MoneyPrimitive.fromMinor(0, "USD").isZero()).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("isZero returns false for non-zero", () => {
|
|
168
|
+
expect(MoneyPrimitive.fromMinor(1, "USD").isZero()).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("isNegative works correctly", () => {
|
|
172
|
+
expect(MoneyPrimitive.fromMinor(-100, "USD").isNegative()).toBe(true);
|
|
173
|
+
expect(MoneyPrimitive.fromMinor(0, "USD").isNegative()).toBe(false);
|
|
174
|
+
expect(MoneyPrimitive.fromMinor(100, "USD").isNegative()).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("Serialization (JSON round-trip)", () => {
|
|
179
|
+
it("should round-trip standard currency", () => {
|
|
180
|
+
const original = MoneyPrimitive.fromMinor(1299, "USD");
|
|
181
|
+
const json = original.toJSON();
|
|
182
|
+
|
|
183
|
+
expect(json).toEqual({
|
|
184
|
+
amount: 1299,
|
|
185
|
+
currencyCode: "USD",
|
|
186
|
+
scale: 2,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const restored = MoneyPrimitive.fromJSON(json);
|
|
190
|
+
expect(restored.equals(original)).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("should round-trip JPY", () => {
|
|
194
|
+
const original = MoneyPrimitive.fromMinor(5000, "JPY");
|
|
195
|
+
const json = original.toJSON();
|
|
196
|
+
const restored = MoneyPrimitive.fromJSON(json);
|
|
197
|
+
|
|
198
|
+
expect(restored.amount).toBe(5000);
|
|
199
|
+
expect(restored.scale).toBe(0);
|
|
200
|
+
expect(restored.equals(original)).toBe(true);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should round-trip through JSON.stringify/parse", () => {
|
|
204
|
+
const original = MoneyPrimitive.fromMajor(42.5, "EUR");
|
|
205
|
+
const serialized = JSON.stringify(original);
|
|
206
|
+
const parsed = JSON.parse(serialized);
|
|
207
|
+
const restored = MoneyPrimitive.fromJSON(parsed);
|
|
208
|
+
|
|
209
|
+
expect(restored.equals(original)).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("toString returns a debug-friendly string", () => {
|
|
213
|
+
const money = MoneyPrimitive.fromMinor(1299, "USD");
|
|
214
|
+
expect(money.toString()).toBe("MoneyPrimitive(1299 USD scale=2)");
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|