@shopify/ui-extensions-server-kit 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -0
- package/README.md +74 -0
- package/dist/ExtensionServerClient/ExtensionServerClient.cjs.js +1 -0
- package/dist/ExtensionServerClient/ExtensionServerClient.d.ts +28 -0
- package/dist/ExtensionServerClient/ExtensionServerClient.es.js +133 -0
- package/dist/ExtensionServerClient/ExtensionServerClient.test.d.ts +1 -0
- package/dist/ExtensionServerClient/index.d.ts +2 -0
- package/dist/ExtensionServerClient/types.cjs.js +1 -0
- package/dist/ExtensionServerClient/types.d.ts +124 -0
- package/dist/ExtensionServerClient/types.es.js +4 -0
- package/dist/context/ExtensionServerProvider.cjs.js +1 -0
- package/dist/context/ExtensionServerProvider.d.ts +2 -0
- package/dist/context/ExtensionServerProvider.es.js +29 -0
- package/dist/context/ExtensionServerProvider.test.d.ts +1 -0
- package/dist/context/constants.cjs.js +1 -0
- package/dist/context/constants.d.ts +3 -0
- package/dist/context/constants.es.js +14 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/types.d.ts +11 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/useExtensionClient.cjs.js +1 -0
- package/dist/hooks/useExtensionClient.d.ts +1 -0
- package/dist/hooks/useExtensionClient.es.js +8 -0
- package/dist/hooks/useExtensionServerContext.cjs.js +1 -0
- package/dist/hooks/useExtensionServerContext.d.ts +1 -0
- package/dist/hooks/useExtensionServerContext.es.js +6 -0
- package/dist/hooks/useExtensionServerEvent.cjs.js +1 -0
- package/dist/hooks/useExtensionServerEvent.d.ts +1 -0
- package/dist/hooks/useExtensionServerEvent.es.js +9 -0
- package/dist/hooks/useExtensionServerState.cjs.js +1 -0
- package/dist/hooks/useExtensionServerState.d.ts +1 -0
- package/dist/hooks/useExtensionServerState.es.js +9 -0
- package/dist/hooks/useIsomorphicLayoutEffect.cjs.js +1 -0
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -0
- package/dist/hooks/useIsomorphicLayoutEffect.es.js +5 -0
- package/dist/i18n.cjs.js +1 -0
- package/dist/i18n.d.ts +93 -0
- package/dist/i18n.es.js +61 -0
- package/dist/i18n.test.d.ts +1 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.cjs2.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.es.js +54 -0
- package/dist/index.es2.js +8 -0
- package/dist/state/actions/actions.cjs.js +1 -0
- package/dist/state/actions/actions.d.ts +6 -0
- package/dist/state/actions/actions.es.js +37 -0
- package/dist/state/actions/index.d.ts +2 -0
- package/dist/state/actions/types.d.ts +21 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/reducers/constants.cjs.js +1 -0
- package/dist/state/reducers/constants.d.ts +2 -0
- package/dist/state/reducers/constants.es.js +7 -0
- package/dist/state/reducers/extensionServerReducer.cjs.js +1 -0
- package/dist/state/reducers/extensionServerReducer.d.ts +3 -0
- package/dist/state/reducers/extensionServerReducer.es.js +57 -0
- package/dist/state/reducers/extensionServerReducer.test.d.ts +1 -0
- package/dist/state/reducers/index.d.ts +3 -0
- package/dist/state/reducers/types.d.ts +6 -0
- package/dist/testing/MockExtensionServerProvider.cjs.js +1 -0
- package/dist/testing/MockExtensionServerProvider.d.ts +7 -0
- package/dist/testing/MockExtensionServerProvider.es.js +24 -0
- package/dist/testing/app.cjs.js +1 -0
- package/dist/testing/app.d.ts +2 -0
- package/dist/testing/app.es.js +16 -0
- package/dist/testing/extensions.cjs.js +1 -0
- package/dist/testing/extensions.d.ts +6 -0
- package/dist/testing/extensions.es.js +65 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/types.cjs.js +1 -0
- package/dist/types.d.ts +169 -0
- package/dist/types.es.js +4 -0
- package/dist/utilities/assetToString.cjs.js +1 -0
- package/dist/utilities/assetToString.d.ts +2 -0
- package/dist/utilities/assetToString.es.js +7 -0
- package/dist/utilities/assetToString.test.d.ts +1 -0
- package/dist/utilities/groupByKey.cjs.js +1 -0
- package/dist/utilities/groupByKey.d.ts +3 -0
- package/dist/utilities/groupByKey.es.js +6 -0
- package/dist/utilities/index.d.ts +7 -0
- package/dist/utilities/isUIExtension.cjs.js +1 -0
- package/dist/utilities/isUIExtension.d.ts +1 -0
- package/dist/utilities/isUIExtension.es.js +6 -0
- package/dist/utilities/isValidSurface.cjs.js +1 -0
- package/dist/utilities/isValidSurface.d.ts +2 -0
- package/dist/utilities/isValidSurface.es.js +7 -0
- package/dist/utilities/noop.cjs.js +1 -0
- package/dist/utilities/noop.d.ts +1 -0
- package/dist/utilities/noop.es.js +5 -0
- package/dist/utilities/replaceUpdated.cjs.js +1 -0
- package/dist/utilities/replaceUpdated.d.ts +1 -0
- package/dist/utilities/replaceUpdated.es.js +14 -0
- package/dist/utilities/replaceUpdated.test.d.ts +1 -0
- package/dist/utilities/set.cjs.js +1 -0
- package/dist/utilities/set.d.ts +4 -0
- package/dist/utilities/set.es.js +18 -0
- package/dist/utilities/set.test.d.ts +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.mjs +1 -0
- package/node_modules/@shopify/react-testing/LICENSE.md +21 -0
- package/node_modules/@shopify/react-testing/README.md +711 -0
- package/node_modules/@shopify/react-testing/build/cjs/TestWrapper.js +52 -0
- package/node_modules/@shopify/react-testing/build/cjs/_virtual/_rollupPluginBabelHelpers.js +47 -0
- package/node_modules/@shopify/react-testing/build/cjs/compat.js +14 -0
- package/node_modules/@shopify/react-testing/build/cjs/destroy.js +13 -0
- package/node_modules/@shopify/react-testing/build/cjs/element.js +225 -0
- package/node_modules/@shopify/react-testing/build/cjs/index.js +21 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/components.js +46 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/context.js +25 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/index.js +16 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/props.js +38 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/strings.js +42 -0
- package/node_modules/@shopify/react-testing/build/cjs/matchers/utilities.js +110 -0
- package/node_modules/@shopify/react-testing/build/cjs/mount.js +76 -0
- package/node_modules/@shopify/react-testing/build/cjs/root.js +284 -0
- package/node_modules/@shopify/react-testing/build/cjs/toReactString.js +86 -0
- package/node_modules/@shopify/react-testing/build/cjs/types.js +28 -0
- package/node_modules/@shopify/react-testing/build/esm/TestWrapper.mjs +44 -0
- package/node_modules/@shopify/react-testing/build/esm/_virtual/_rollupPluginBabelHelpers.mjs +42 -0
- package/node_modules/@shopify/react-testing/build/esm/compat.mjs +10 -0
- package/node_modules/@shopify/react-testing/build/esm/destroy.mjs +9 -0
- package/node_modules/@shopify/react-testing/build/esm/element.mjs +221 -0
- package/node_modules/@shopify/react-testing/build/esm/index.mjs +5 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/components.mjs +41 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/context.mjs +21 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/index.mjs +14 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/props.mjs +33 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/strings.mjs +37 -0
- package/node_modules/@shopify/react-testing/build/esm/matchers/utilities.mjs +101 -0
- package/node_modules/@shopify/react-testing/build/esm/mount.mjs +70 -0
- package/node_modules/@shopify/react-testing/build/esm/root.mjs +275 -0
- package/node_modules/@shopify/react-testing/build/esm/toReactString.mjs +80 -0
- package/node_modules/@shopify/react-testing/build/esm/types.mjs +26 -0
- package/node_modules/@shopify/react-testing/build/esnext/TestWrapper.esnext +44 -0
- package/node_modules/@shopify/react-testing/build/esnext/compat.esnext +10 -0
- package/node_modules/@shopify/react-testing/build/esnext/destroy.esnext +9 -0
- package/node_modules/@shopify/react-testing/build/esnext/element.esnext +221 -0
- package/node_modules/@shopify/react-testing/build/esnext/index.esnext +5 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/components.esnext +41 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/context.esnext +21 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/index.esnext +14 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/props.esnext +33 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/strings.esnext +37 -0
- package/node_modules/@shopify/react-testing/build/esnext/matchers/utilities.esnext +99 -0
- package/node_modules/@shopify/react-testing/build/esnext/mount.esnext +71 -0
- package/node_modules/@shopify/react-testing/build/esnext/root.esnext +275 -0
- package/node_modules/@shopify/react-testing/build/esnext/toReactString.esnext +80 -0
- package/node_modules/@shopify/react-testing/build/esnext/types.esnext +26 -0
- package/node_modules/@shopify/react-testing/build/ts/TestWrapper.d.ts +17 -0
- package/node_modules/@shopify/react-testing/build/ts/TestWrapper.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/compat.d.ts +3 -0
- package/node_modules/@shopify/react-testing/build/ts/compat.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/destroy.d.ts +2 -0
- package/node_modules/@shopify/react-testing/build/ts/destroy.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/element.d.ts +42 -0
- package/node_modules/@shopify/react-testing/build/ts/element.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/index.d.ts +7 -0
- package/node_modules/@shopify/react-testing/build/ts/index.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/components.d.ts +12 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/components.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/context.d.ts +8 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/context.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/index.d.ts +20 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/index.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/props.d.ts +10 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/props.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/strings.d.ts +11 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/strings.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/utilities.d.ts +17 -0
- package/node_modules/@shopify/react-testing/build/ts/matchers/utilities.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/mount.d.ts +39 -0
- package/node_modules/@shopify/react-testing/build/ts/mount.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/root.d.ts +55 -0
- package/node_modules/@shopify/react-testing/build/ts/root.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/toReactString.d.ts +5 -0
- package/node_modules/@shopify/react-testing/build/ts/toReactString.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/build/ts/types.d.ts +89 -0
- package/node_modules/@shopify/react-testing/build/ts/types.d.ts.map +1 -0
- package/node_modules/@shopify/react-testing/index.esnext +1 -0
- package/node_modules/@shopify/react-testing/index.js +1 -0
- package/node_modules/@shopify/react-testing/index.mjs +1 -0
- package/node_modules/@shopify/react-testing/matchers.esnext +1 -0
- package/node_modules/@shopify/react-testing/matchers.js +1 -0
- package/node_modules/@shopify/react-testing/matchers.mjs +1 -0
- package/node_modules/@shopify/react-testing/package.json +69 -0
- package/node_modules/@shopify/ui-extensions-test-utils/CHANGELOG.md +66 -0
- package/node_modules/@shopify/ui-extensions-test-utils/dist/index.js +3 -0
- package/node_modules/@shopify/ui-extensions-test-utils/dist/render.js +5 -0
- package/node_modules/@shopify/ui-extensions-test-utils/dist/renderHook.js +20 -0
- package/node_modules/@shopify/ui-extensions-test-utils/dist/withProviders.js +6 -0
- package/node_modules/@shopify/ui-extensions-test-utils/package.json +41 -0
- package/node_modules/@shopify/ui-extensions-test-utils/project.json +39 -0
- package/node_modules/@types/node/LICENSE +21 -0
- package/node_modules/@types/node/README.md +15 -0
- package/node_modules/@types/node/assert/strict.d.ts +8 -0
- package/node_modules/@types/node/assert.d.ts +985 -0
- package/node_modules/@types/node/async_hooks.d.ts +522 -0
- package/node_modules/@types/node/buffer.d.ts +2321 -0
- package/node_modules/@types/node/child_process.d.ts +1544 -0
- package/node_modules/@types/node/cluster.d.ts +432 -0
- package/node_modules/@types/node/console.d.ts +412 -0
- package/node_modules/@types/node/constants.d.ts +19 -0
- package/node_modules/@types/node/crypto.d.ts +4451 -0
- package/node_modules/@types/node/dgram.d.ts +586 -0
- package/node_modules/@types/node/diagnostics_channel.d.ts +192 -0
- package/node_modules/@types/node/dns/promises.d.ts +381 -0
- package/node_modules/@types/node/dns.d.ts +809 -0
- package/node_modules/@types/node/dom-events.d.ts +122 -0
- package/node_modules/@types/node/domain.d.ts +170 -0
- package/node_modules/@types/node/events.d.ts +803 -0
- package/node_modules/@types/node/fs/promises.d.ts +1205 -0
- package/node_modules/@types/node/fs.d.ts +4211 -0
- package/node_modules/@types/node/globals.d.ts +377 -0
- package/node_modules/@types/node/globals.global.d.ts +1 -0
- package/node_modules/@types/node/http.d.ts +1801 -0
- package/node_modules/@types/node/http2.d.ts +2386 -0
- package/node_modules/@types/node/https.d.ts +544 -0
- package/node_modules/@types/node/index.d.ts +88 -0
- package/node_modules/@types/node/inspector.d.ts +2739 -0
- package/node_modules/@types/node/module.d.ts +298 -0
- package/node_modules/@types/node/net.d.ts +913 -0
- package/node_modules/@types/node/os.d.ts +473 -0
- package/node_modules/@types/node/package.json +235 -0
- package/node_modules/@types/node/path.d.ts +191 -0
- package/node_modules/@types/node/perf_hooks.d.ts +626 -0
- package/node_modules/@types/node/process.d.ts +1531 -0
- package/node_modules/@types/node/punycode.d.ts +117 -0
- package/node_modules/@types/node/querystring.d.ts +141 -0
- package/node_modules/@types/node/readline/promises.d.ts +143 -0
- package/node_modules/@types/node/readline.d.ts +666 -0
- package/node_modules/@types/node/repl.d.ts +430 -0
- package/node_modules/@types/node/stream/consumers.d.ts +12 -0
- package/node_modules/@types/node/stream/promises.d.ts +83 -0
- package/node_modules/@types/node/stream/web.d.ts +336 -0
- package/node_modules/@types/node/stream.d.ts +1731 -0
- package/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/node_modules/@types/node/test.d.ts +1113 -0
- package/node_modules/@types/node/timers/promises.d.ts +93 -0
- package/node_modules/@types/node/timers.d.ts +126 -0
- package/node_modules/@types/node/tls.d.ts +1203 -0
- package/node_modules/@types/node/trace_events.d.ts +171 -0
- package/node_modules/@types/node/ts4.8/assert/strict.d.ts +8 -0
- package/node_modules/@types/node/ts4.8/assert.d.ts +985 -0
- package/node_modules/@types/node/ts4.8/async_hooks.d.ts +522 -0
- package/node_modules/@types/node/ts4.8/buffer.d.ts +2321 -0
- package/node_modules/@types/node/ts4.8/child_process.d.ts +1544 -0
- package/node_modules/@types/node/ts4.8/cluster.d.ts +432 -0
- package/node_modules/@types/node/ts4.8/console.d.ts +412 -0
- package/node_modules/@types/node/ts4.8/constants.d.ts +19 -0
- package/node_modules/@types/node/ts4.8/crypto.d.ts +4450 -0
- package/node_modules/@types/node/ts4.8/dgram.d.ts +586 -0
- package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +192 -0
- package/node_modules/@types/node/ts4.8/dns/promises.d.ts +381 -0
- package/node_modules/@types/node/ts4.8/dns.d.ts +809 -0
- package/node_modules/@types/node/ts4.8/dom-events.d.ts +122 -0
- package/node_modules/@types/node/ts4.8/domain.d.ts +170 -0
- package/node_modules/@types/node/ts4.8/events.d.ts +754 -0
- package/node_modules/@types/node/ts4.8/fs/promises.d.ts +1205 -0
- package/node_modules/@types/node/ts4.8/fs.d.ts +4211 -0
- package/node_modules/@types/node/ts4.8/globals.d.ts +377 -0
- package/node_modules/@types/node/ts4.8/globals.global.d.ts +1 -0
- package/node_modules/@types/node/ts4.8/http.d.ts +1801 -0
- package/node_modules/@types/node/ts4.8/http2.d.ts +2386 -0
- package/node_modules/@types/node/ts4.8/https.d.ts +544 -0
- package/node_modules/@types/node/ts4.8/index.d.ts +88 -0
- package/node_modules/@types/node/ts4.8/inspector.d.ts +2739 -0
- package/node_modules/@types/node/ts4.8/module.d.ts +298 -0
- package/node_modules/@types/node/ts4.8/net.d.ts +913 -0
- package/node_modules/@types/node/ts4.8/os.d.ts +473 -0
- package/node_modules/@types/node/ts4.8/path.d.ts +191 -0
- package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +626 -0
- package/node_modules/@types/node/ts4.8/process.d.ts +1531 -0
- package/node_modules/@types/node/ts4.8/punycode.d.ts +117 -0
- package/node_modules/@types/node/ts4.8/querystring.d.ts +141 -0
- package/node_modules/@types/node/ts4.8/readline/promises.d.ts +143 -0
- package/node_modules/@types/node/ts4.8/readline.d.ts +666 -0
- package/node_modules/@types/node/ts4.8/repl.d.ts +430 -0
- package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +12 -0
- package/node_modules/@types/node/ts4.8/stream/promises.d.ts +83 -0
- package/node_modules/@types/node/ts4.8/stream/web.d.ts +336 -0
- package/node_modules/@types/node/ts4.8/stream.d.ts +1731 -0
- package/node_modules/@types/node/ts4.8/string_decoder.d.ts +67 -0
- package/node_modules/@types/node/ts4.8/test.d.ts +1113 -0
- package/node_modules/@types/node/ts4.8/timers/promises.d.ts +93 -0
- package/node_modules/@types/node/ts4.8/timers.d.ts +126 -0
- package/node_modules/@types/node/ts4.8/tls.d.ts +1203 -0
- package/node_modules/@types/node/ts4.8/trace_events.d.ts +171 -0
- package/node_modules/@types/node/ts4.8/tty.d.ts +206 -0
- package/node_modules/@types/node/ts4.8/url.d.ts +937 -0
- package/node_modules/@types/node/ts4.8/util.d.ts +2075 -0
- package/node_modules/@types/node/ts4.8/v8.d.ts +541 -0
- package/node_modules/@types/node/ts4.8/vm.d.ts +667 -0
- package/node_modules/@types/node/ts4.8/wasi.d.ts +158 -0
- package/node_modules/@types/node/ts4.8/worker_threads.d.ts +692 -0
- package/node_modules/@types/node/ts4.8/zlib.d.ts +517 -0
- package/node_modules/@types/node/tty.d.ts +206 -0
- package/node_modules/@types/node/url.d.ts +937 -0
- package/node_modules/@types/node/util.d.ts +2075 -0
- package/node_modules/@types/node/v8.d.ts +541 -0
- package/node_modules/@types/node/vm.d.ts +667 -0
- package/node_modules/@types/node/wasi.d.ts +158 -0
- package/node_modules/@types/node/worker_threads.d.ts +692 -0
- package/node_modules/@types/node/zlib.d.ts +517 -0
- package/node_modules/@types/react/LICENSE +21 -0
- package/node_modules/@types/react/README.md +16 -0
- package/node_modules/@types/react/experimental.d.ts +192 -0
- package/node_modules/@types/react/global.d.ts +151 -0
- package/node_modules/@types/react/index.d.ts +3175 -0
- package/node_modules/@types/react/jsx-dev-runtime.d.ts +2 -0
- package/node_modules/@types/react/jsx-runtime.d.ts +2 -0
- package/node_modules/@types/react/package.json +149 -0
- package/node_modules/@vitejs/plugin-react-refresh/LICENSE +21 -0
- package/node_modules/@vitejs/plugin-react-refresh/README.md +73 -0
- package/node_modules/@vitejs/plugin-react-refresh/index.d.ts +14 -0
- package/node_modules/@vitejs/plugin-react-refresh/index.js +239 -0
- package/node_modules/@vitejs/plugin-react-refresh/package.json +35 -0
- package/package.json +65 -0
- package/project.json +74 -0
- package/scripts/create-entry-files.ts +44 -0
- package/src/ExtensionServerClient/ExtensionServerClient.test.ts +730 -0
- package/src/ExtensionServerClient/ExtensionServerClient.ts +310 -0
- package/src/ExtensionServerClient/index.ts +2 -0
- package/src/ExtensionServerClient/types.ts +159 -0
- package/src/context/ExtensionServerProvider.test.tsx +173 -0
- package/src/context/ExtensionServerProvider.tsx +46 -0
- package/src/context/constants.ts +15 -0
- package/src/context/index.ts +3 -0
- package/src/context/types.ts +13 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useExtensionClient.ts +6 -0
- package/src/hooks/useExtensionServerContext.ts +4 -0
- package/src/hooks/useExtensionServerEvent.ts +11 -0
- package/src/hooks/useExtensionServerState.ts +6 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +6 -0
- package/src/i18n.test.ts +417 -0
- package/src/i18n.ts +208 -0
- package/src/index.ts +7 -0
- package/src/state/actions/actions.ts +36 -0
- package/src/state/actions/index.ts +2 -0
- package/src/state/actions/types.ts +26 -0
- package/src/state/index.ts +2 -0
- package/src/state/reducers/constants.ts +6 -0
- package/src/state/reducers/extensionServerReducer.test.ts +160 -0
- package/src/state/reducers/extensionServerReducer.ts +87 -0
- package/src/state/reducers/index.ts +3 -0
- package/src/state/reducers/types.ts +7 -0
- package/src/testing/MockExtensionServerProvider.tsx +36 -0
- package/src/testing/app.ts +15 -0
- package/src/testing/extensions.ts +70 -0
- package/src/testing/index.ts +3 -0
- package/src/types.ts +172 -0
- package/src/utilities/assetToString.test.ts +16 -0
- package/src/utilities/assetToString.ts +8 -0
- package/src/utilities/groupByKey.ts +3 -0
- package/src/utilities/index.ts +7 -0
- package/src/utilities/isUIExtension.ts +7 -0
- package/src/utilities/isValidSurface.ts +7 -0
- package/src/utilities/noop.ts +1 -0
- package/src/utilities/replaceUpdated.test.ts +26 -0
- package/src/utilities/replaceUpdated.ts +16 -0
- package/src/utilities/set.test.ts +19 -0
- package/src/utilities/set.ts +29 -0
- package/testing.d.ts +1 -0
- package/testing.js +1 -0
- package/testing.mjs +1 -0
- package/tests/setup.ts +6 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {ExtensionServerClient} from '../ExtensionServerClient'
|
|
2
|
+
import {INITIAL_STATE} from '../state'
|
|
3
|
+
import {noop} from '../utilities'
|
|
4
|
+
import {createContext} from 'react'
|
|
5
|
+
|
|
6
|
+
import type {ExtensionServerContext} from './types'
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_VALUE: ExtensionServerContext = {
|
|
9
|
+
connect: noop,
|
|
10
|
+
dispatch: noop,
|
|
11
|
+
state: INITIAL_STATE,
|
|
12
|
+
client: new ExtensionServerClient(),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const extensionServerContext = createContext<ExtensionServerContext>(DEFAULT_VALUE)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type {ExtensionServerState, ExtensionServerActions} from '../state'
|
|
2
|
+
|
|
3
|
+
export interface ExtensionServerContext {
|
|
4
|
+
client: ExtensionServer.Client
|
|
5
|
+
state: ExtensionServerState
|
|
6
|
+
connect(options?: ExtensionServer.Options): void
|
|
7
|
+
dispatch(action: ExtensionServerActions): void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExtensionServerProviderProps {
|
|
11
|
+
children?: React.ReactNode
|
|
12
|
+
options: ExtensionServer.Options
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {useExtensionServerContext} from './useExtensionServerContext'
|
|
2
|
+
import {useIsomorphicLayoutEffect} from './useIsomorphicLayoutEffect'
|
|
3
|
+
|
|
4
|
+
export function useExtensionServerEvent<TEvent extends keyof ExtensionServer.InboundEvents>(
|
|
5
|
+
event: TEvent,
|
|
6
|
+
listener: ExtensionServer.EventListener<TEvent>,
|
|
7
|
+
): void {
|
|
8
|
+
const {client} = useExtensionServerContext()
|
|
9
|
+
|
|
10
|
+
useIsomorphicLayoutEffect(() => client.on(event, listener), [client, event, listener])
|
|
11
|
+
}
|
package/src/i18n.test.ts
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import {flattenDevExtensionTranslations, resolveDevExtensionLocale, getFlattenedLocalization} from './i18n'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* These tests were adapted from https://github.com/Shopify/checkout-web/blob/master/app/utilities/development-mode/tests/i18n-utilities.test.tsx
|
|
5
|
+
* */
|
|
6
|
+
|
|
7
|
+
describe('resolveDevExtensionLocale()', () => {
|
|
8
|
+
test('returns the user locale if it is provided as a supported locale', () => {
|
|
9
|
+
const userLocale = 'fr-FR'
|
|
10
|
+
|
|
11
|
+
const localization = {
|
|
12
|
+
defaultLocale: 'en',
|
|
13
|
+
lastUpdated: Date.now(),
|
|
14
|
+
translations: {
|
|
15
|
+
en: {
|
|
16
|
+
greetings: {
|
|
17
|
+
hello: 'Hello',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
de: {
|
|
21
|
+
greetings: {
|
|
22
|
+
hello: 'Hallo',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
'fr-FR': {
|
|
26
|
+
greetings: {
|
|
27
|
+
hello: 'Bonjour',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const extensionLocale = resolveDevExtensionLocale(localization, {user: userLocale})
|
|
34
|
+
|
|
35
|
+
expect(extensionLocale).toBe(userLocale)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('returns the non-regional user locale if there is no exact match with user locale', async () => {
|
|
39
|
+
const userLocale = 'de-DE'
|
|
40
|
+
|
|
41
|
+
const localization = {
|
|
42
|
+
defaultLocale: 'en',
|
|
43
|
+
lastUpdated: Date.now(),
|
|
44
|
+
translations: {
|
|
45
|
+
en: {
|
|
46
|
+
greetings: {
|
|
47
|
+
hello: 'Hello',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
de: {
|
|
51
|
+
greetings: {
|
|
52
|
+
hello: 'Hallo',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
'fr-FR': {
|
|
56
|
+
greetings: {
|
|
57
|
+
hello: 'Bonjour',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const extensionLocale = resolveDevExtensionLocale(localization, {user: userLocale})
|
|
64
|
+
|
|
65
|
+
expect(extensionLocale).toBe(userLocale.split('-')[0])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test("returns the shop locale if it is provided as a supported locale and there isn't a match for the user locale", () => {
|
|
69
|
+
const shopLocale = 'fr-FR'
|
|
70
|
+
const userLocale = 'de-DE'
|
|
71
|
+
|
|
72
|
+
const localization = {
|
|
73
|
+
defaultLocale: 'en',
|
|
74
|
+
lastUpdated: Date.now(),
|
|
75
|
+
translations: {
|
|
76
|
+
en: {
|
|
77
|
+
greetings: {
|
|
78
|
+
hello: 'Hello',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
'fr-FR': {
|
|
82
|
+
greetings: {
|
|
83
|
+
hello: 'Bonjour',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const extensionLocale = resolveDevExtensionLocale(localization, {user: userLocale, shop: shopLocale})
|
|
90
|
+
|
|
91
|
+
expect(extensionLocale).toBe(shopLocale)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test("returns the non-regional shop locale if it is provided as a supported locale and there isn't a match for the user locale", async () => {
|
|
95
|
+
const userLocale = 'ja-JP'
|
|
96
|
+
const shopLocale = 'de-DE'
|
|
97
|
+
|
|
98
|
+
const localization = {
|
|
99
|
+
defaultLocale: 'en',
|
|
100
|
+
lastUpdated: Date.now(),
|
|
101
|
+
translations: {
|
|
102
|
+
en: {
|
|
103
|
+
greetings: {
|
|
104
|
+
hello: 'Hello',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
de: {
|
|
108
|
+
greetings: {
|
|
109
|
+
hello: 'Hallo',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const extensionLocale = resolveDevExtensionLocale(localization, {user: userLocale, shop: shopLocale})
|
|
116
|
+
|
|
117
|
+
expect(extensionLocale).toBe(shopLocale.split('-')[0])
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('returns the default translation locale when no full or partial match can be for neither user nor shop locale made', async () => {
|
|
121
|
+
const userLocale = 'en-US'
|
|
122
|
+
const shopLocale = 'ja'
|
|
123
|
+
const defaultLocale = 'fi'
|
|
124
|
+
|
|
125
|
+
const localization = {
|
|
126
|
+
defaultLocale,
|
|
127
|
+
lastUpdated: Date.now(),
|
|
128
|
+
translations: {
|
|
129
|
+
'en-CA': {
|
|
130
|
+
greetings: {
|
|
131
|
+
hello: 'Hello',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
de: {
|
|
135
|
+
greetings: {
|
|
136
|
+
hello: 'Hallo',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
fi: {
|
|
140
|
+
greetings: {
|
|
141
|
+
hello: 'Hei',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const extensionLocale = resolveDevExtensionLocale(localization, {user: userLocale, shop: shopLocale})
|
|
148
|
+
|
|
149
|
+
expect(extensionLocale).toBe(defaultLocale)
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
describe('flattenDevExtensionTranslations()', () => {
|
|
154
|
+
test('returns flattened translation keys using a single locale', () => {
|
|
155
|
+
const resolvedLocale = 'en'
|
|
156
|
+
|
|
157
|
+
const localization = {
|
|
158
|
+
defaultLocale: 'en',
|
|
159
|
+
lastUpdated: Date.now(),
|
|
160
|
+
translations: {
|
|
161
|
+
en: {
|
|
162
|
+
greetings: {
|
|
163
|
+
hello: 'Hello',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
170
|
+
|
|
171
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
172
|
+
'greetings.hello': 'Hello',
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test('returns flattened and merged translations with fallbacks for missing keys from the default locale', () => {
|
|
177
|
+
const resolvedLocale = 'en-GB'
|
|
178
|
+
|
|
179
|
+
const localization = {
|
|
180
|
+
defaultLocale: 'en',
|
|
181
|
+
lastUpdated: Date.now(),
|
|
182
|
+
translations: {
|
|
183
|
+
en: {
|
|
184
|
+
greetings: {
|
|
185
|
+
hello: 'Hello',
|
|
186
|
+
goodbye: 'Goodbye',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
'en-GB': {
|
|
190
|
+
greetings: {
|
|
191
|
+
hello: 'Hello, UK',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
fr: {
|
|
195
|
+
greetings: {
|
|
196
|
+
hello: 'Bonjour',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
203
|
+
|
|
204
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
205
|
+
'greetings.hello': 'Hello, UK',
|
|
206
|
+
'greetings.goodbye': 'Goodbye',
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
test('returns flattened and merged translations based on exact match for locale translation', () => {
|
|
211
|
+
const resolvedLocale = 'fr-CA'
|
|
212
|
+
|
|
213
|
+
const localization = {
|
|
214
|
+
defaultLocale: 'en',
|
|
215
|
+
lastUpdated: Date.now(),
|
|
216
|
+
translations: {
|
|
217
|
+
en: {
|
|
218
|
+
greetings: {
|
|
219
|
+
hello: 'Hello',
|
|
220
|
+
goodbye: 'Goodbye',
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
fr: {
|
|
224
|
+
greetings: {
|
|
225
|
+
hello: 'Bonjour',
|
|
226
|
+
goodbye: 'Au revoir',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
'fr-CA': {
|
|
230
|
+
greetings: {
|
|
231
|
+
hello: 'Bonjour, Canada',
|
|
232
|
+
goodbye: 'Au revoir, Canada',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
239
|
+
|
|
240
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
241
|
+
'greetings.hello': 'Bonjour, Canada',
|
|
242
|
+
'greetings.goodbye': 'Au revoir, Canada',
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
test('returns flattened and merged translations based on non-regional match for locale translation', () => {
|
|
247
|
+
const resolvedLocale = 'fr-CA'
|
|
248
|
+
|
|
249
|
+
const localization = {
|
|
250
|
+
defaultLocale: 'en',
|
|
251
|
+
lastUpdated: Date.now(),
|
|
252
|
+
translations: {
|
|
253
|
+
en: {
|
|
254
|
+
greetings: {
|
|
255
|
+
hello: 'Hello',
|
|
256
|
+
goodbye: 'Goodbye',
|
|
257
|
+
sorry: 'Sorry',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
fr: {
|
|
261
|
+
greetings: {
|
|
262
|
+
hello: 'Bonjour',
|
|
263
|
+
goodbye: 'Au revoir',
|
|
264
|
+
sorry: 'Désolé',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
271
|
+
|
|
272
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
273
|
+
'greetings.hello': 'Bonjour',
|
|
274
|
+
'greetings.goodbye': 'Au revoir',
|
|
275
|
+
'greetings.sorry': 'Désolé',
|
|
276
|
+
})
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
test('returns the flattened default locale where no locale match is possible (full or non-regional)', () => {
|
|
280
|
+
const resolvedLocale = 'de'
|
|
281
|
+
|
|
282
|
+
const localization = {
|
|
283
|
+
defaultLocale: 'en',
|
|
284
|
+
lastUpdated: Date.now(),
|
|
285
|
+
translations: {
|
|
286
|
+
en: {
|
|
287
|
+
greetings: {
|
|
288
|
+
hello: 'Hello',
|
|
289
|
+
goodbye: 'Goodbye',
|
|
290
|
+
sorry: 'Sorry',
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
fr: {
|
|
294
|
+
greetings: {
|
|
295
|
+
hello: 'Bonjour',
|
|
296
|
+
goodbye: 'Au revoir',
|
|
297
|
+
sorry: 'Désolé',
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
'de-DE': {
|
|
301
|
+
greetings: {
|
|
302
|
+
hello: 'Hallo',
|
|
303
|
+
goodbye: 'Auf Wiedersehen',
|
|
304
|
+
sorry: ' Entschuldigung',
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
311
|
+
|
|
312
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
313
|
+
'greetings.hello': 'Hello',
|
|
314
|
+
'greetings.goodbye': 'Goodbye',
|
|
315
|
+
'greetings.sorry': 'Sorry',
|
|
316
|
+
})
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
test('returns flattened translations with pluralizations', () => {
|
|
320
|
+
const resolvedLocale = 'en'
|
|
321
|
+
|
|
322
|
+
const localization = {
|
|
323
|
+
defaultLocale: 'en',
|
|
324
|
+
lastUpdated: Date.now(),
|
|
325
|
+
translations: {
|
|
326
|
+
en: {
|
|
327
|
+
pluralExample: {
|
|
328
|
+
one: 'You have {{count}} apple',
|
|
329
|
+
other: 'You have {{count}} apples',
|
|
330
|
+
},
|
|
331
|
+
example: {
|
|
332
|
+
of: {
|
|
333
|
+
nestedTranslation: 'This is a nested translation only in the default locale',
|
|
334
|
+
anotherNestedTranslation: 'This is another nested translation defined in the default locale',
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const flattenedTranslations = flattenDevExtensionTranslations(localization, resolvedLocale)
|
|
342
|
+
|
|
343
|
+
expect(flattenedTranslations).toStrictEqual({
|
|
344
|
+
'pluralExample.one': 'You have {{count}} apple',
|
|
345
|
+
'pluralExample.other': 'You have {{count}} apples',
|
|
346
|
+
'example.of.nestedTranslation': 'This is a nested translation only in the default locale',
|
|
347
|
+
'example.of.anotherNestedTranslation': 'This is another nested translation defined in the default locale',
|
|
348
|
+
})
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
describe('getFlattenedLocalization()', () => {
|
|
353
|
+
test('returns flattened translations string and resolved extension locale when locales options are provided', () => {
|
|
354
|
+
const userLocale = 'en'
|
|
355
|
+
|
|
356
|
+
const localization = {
|
|
357
|
+
defaultLocale: 'en',
|
|
358
|
+
lastUpdated: Date.now(),
|
|
359
|
+
translations: {
|
|
360
|
+
en: {
|
|
361
|
+
greetings: {
|
|
362
|
+
hello: 'Hello',
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const flattenedLocalization = getFlattenedLocalization(localization, {user: userLocale})
|
|
369
|
+
|
|
370
|
+
expect(flattenedLocalization).toStrictEqual({
|
|
371
|
+
extensionLocale: userLocale,
|
|
372
|
+
translations: '{"greetings.hello":"Hello"}',
|
|
373
|
+
lastUpdated: localization.lastUpdated,
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
test('return undefined when locales options are not provided', () => {
|
|
378
|
+
const userLocale = 'en'
|
|
379
|
+
|
|
380
|
+
const localization = {
|
|
381
|
+
defaultLocale: 'en',
|
|
382
|
+
lastUpdated: Date.now(),
|
|
383
|
+
translations: {
|
|
384
|
+
en: {
|
|
385
|
+
greetings: {
|
|
386
|
+
hello: 'Hello',
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const flattenedLocalization = getFlattenedLocalization(localization)
|
|
393
|
+
|
|
394
|
+
expect(flattenedLocalization).toBeUndefined()
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
test('return undefined when localization is null', () => {
|
|
398
|
+
const userLocale = 'en'
|
|
399
|
+
const flattenedLocalization = getFlattenedLocalization(null, {user: userLocale})
|
|
400
|
+
|
|
401
|
+
expect(flattenedLocalization).toBeUndefined()
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
test('return flattened localization if localization is already flattened', () => {
|
|
405
|
+
const userLocale = 'en'
|
|
406
|
+
|
|
407
|
+
const localization = {
|
|
408
|
+
extensionLocale: userLocale,
|
|
409
|
+
lastUpdated: Date.now(),
|
|
410
|
+
translations: '{"greetings.hello":"Hello"}',
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
const flattenedLocalization = getFlattenedLocalization(localization, {user: userLocale})
|
|
414
|
+
|
|
415
|
+
expect(flattenedLocalization).toStrictEqual(localization)
|
|
416
|
+
})
|
|
417
|
+
})
|
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* These translation utilities were adapted from https://github.com/Shopify/checkout-web/blob/master/app/utilities/development-mode/i18n-utilities.tsx
|
|
3
|
+
* */
|
|
4
|
+
|
|
5
|
+
type Translation = string | {[key: string]: Translation}
|
|
6
|
+
|
|
7
|
+
export interface Localization {
|
|
8
|
+
defaultLocale: string
|
|
9
|
+
translations: {[key: string]: {[key: string]: Translation}}
|
|
10
|
+
lastUpdated: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FlattenedLocalization {
|
|
14
|
+
extensionLocale: string
|
|
15
|
+
translations: string
|
|
16
|
+
lastUpdated: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface LocalesOptions {
|
|
20
|
+
user: string
|
|
21
|
+
shop?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TranslationDictionary {
|
|
25
|
+
[key: string]: string | TranslationDictionary
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* This is a flattened dictionary of extension translations for the active locale.
|
|
30
|
+
*
|
|
31
|
+
* Here are some examples for the 'en' locale.
|
|
32
|
+
*
|
|
33
|
+
* Nested keys are dot separated. Consider this translation definition:
|
|
34
|
+
*
|
|
35
|
+
* ```
|
|
36
|
+
* {
|
|
37
|
+
* "greetings": {
|
|
38
|
+
* "hello": "Hello {{user}}"
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* It would be represented in this flattened dictionary as:
|
|
44
|
+
* ```
|
|
45
|
+
* {
|
|
46
|
+
* "greetings.hello": "Hello {{user}}"
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
* Pluralized translations will also be flattened. Consider this definition:
|
|
50
|
+
* ```
|
|
51
|
+
* {
|
|
52
|
+
* "loyaltyPointsRemaining": {
|
|
53
|
+
* "one": "You have {{count}} loyalty point",
|
|
54
|
+
* "other": "You have {{count}} loyalty points",
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
* It would be represented in this flattened dictionary as:
|
|
59
|
+
* ```
|
|
60
|
+
* {
|
|
61
|
+
* "loyaltyPointsRemaining.one": "You have {{count}} loyalty point",
|
|
62
|
+
* "loyaltyPointsRemaining.other": "You have {{count}} loyalty points",
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export interface ExtensionTranslationMap {
|
|
67
|
+
[key: string]: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const TRANSLATED_KEYS = ['localization', 'name', 'description']
|
|
71
|
+
/**
|
|
72
|
+
* From a nested dictionary like the following :
|
|
73
|
+
*
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const dictionary = {
|
|
76
|
+
* Foo: {
|
|
77
|
+
* Bar: {
|
|
78
|
+
* fooBar: 'something'
|
|
79
|
+
* }
|
|
80
|
+
* }
|
|
81
|
+
* }
|
|
82
|
+
*
|
|
83
|
+
* Returns a map containing this pair : {'Foo.Bar.fooBar': 'something'}
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export function dictionaryToFlatMap(dictionary: TranslationDictionary) {
|
|
87
|
+
const map = new Map<string, string>()
|
|
88
|
+
|
|
89
|
+
traverseDictionary(dictionary, (key, value) => map.set(key, value))
|
|
90
|
+
|
|
91
|
+
return map
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function traverseDictionary(
|
|
95
|
+
dictionary: TranslationDictionary,
|
|
96
|
+
callback: (key: string, value: string) => void,
|
|
97
|
+
keyPrefix?: string,
|
|
98
|
+
) {
|
|
99
|
+
Object.keys(dictionary).forEach((key: string) => {
|
|
100
|
+
const value = dictionary[key]
|
|
101
|
+
const translationKey = keyPrefix ? `${keyPrefix}.${key}` : key
|
|
102
|
+
|
|
103
|
+
if (value == null) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (typeof value === 'string') {
|
|
108
|
+
// eslint-disable-next-line node/callback-return
|
|
109
|
+
callback(translationKey, value)
|
|
110
|
+
} else {
|
|
111
|
+
traverseDictionary(value, callback, translationKey)
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function flattenDevExtensionTranslations(localization: Localization, locale: string): ExtensionTranslationMap {
|
|
117
|
+
const defaultTranslations = getFlatMap(localization.translations[localization.defaultLocale])
|
|
118
|
+
|
|
119
|
+
const nonRegionalLocale = getNonRegionalLocale(locale)
|
|
120
|
+
const nonRegionalTranslations = getFlatMap(localization.translations[nonRegionalLocale])
|
|
121
|
+
|
|
122
|
+
const userLocaleTranslations = getFlatMap(localization.translations[locale])
|
|
123
|
+
|
|
124
|
+
return convertMapToExtensionTranslationMap(
|
|
125
|
+
new Map([...defaultTranslations, ...nonRegionalTranslations, ...userLocaleTranslations]),
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getFlatMap(translationDictionary: TranslationDictionary | undefined) {
|
|
130
|
+
if (translationDictionary) {
|
|
131
|
+
return dictionaryToFlatMap(translationDictionary)
|
|
132
|
+
}
|
|
133
|
+
return new Map<string, string>()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function resolveDevExtensionLocale(
|
|
137
|
+
localization: Localization,
|
|
138
|
+
locales: {
|
|
139
|
+
user: string
|
|
140
|
+
shop?: string
|
|
141
|
+
},
|
|
142
|
+
): string {
|
|
143
|
+
const extensionLocales = new Set(Object.keys(localization.translations))
|
|
144
|
+
|
|
145
|
+
// 0. If no translations, use the user's locale
|
|
146
|
+
if (extensionLocales.size === 0) return locales.user
|
|
147
|
+
|
|
148
|
+
// 1. Attempt to match the user's locale exactly
|
|
149
|
+
if (extensionLocales.has(locales.user)) return locales.user
|
|
150
|
+
|
|
151
|
+
// 2. Attempt to match the non-regional part of the user's locale (i.e. 'fr-CA' becomes 'fr')
|
|
152
|
+
const nonRegionalUserLocale = getNonRegionalLocale(locales.user)
|
|
153
|
+
if (extensionLocales.has(nonRegionalUserLocale)) return nonRegionalUserLocale
|
|
154
|
+
|
|
155
|
+
// 3. Attempt to match the shop's default locale exactly
|
|
156
|
+
if (locales.shop && extensionLocales.has(locales.shop)) return locales.shop
|
|
157
|
+
|
|
158
|
+
// 4. Attempt to match the non-regional part of the shop's default locale (i.e. 'fr-CA' becomes 'fr')
|
|
159
|
+
const nonRegionalShopLocale = locales.shop && getNonRegionalLocale(locales.shop)
|
|
160
|
+
if (nonRegionalShopLocale && extensionLocales.has(nonRegionalShopLocale)) return nonRegionalShopLocale
|
|
161
|
+
|
|
162
|
+
// 5. Finally, return the default locale as a fallback
|
|
163
|
+
return localization.defaultLocale
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function convertMapToExtensionTranslationMap(map: Map<string, string>): ExtensionTranslationMap {
|
|
167
|
+
const extTransMap: ExtensionTranslationMap = {}
|
|
168
|
+
for (const [key, value] of map) {
|
|
169
|
+
extTransMap[key] = value
|
|
170
|
+
}
|
|
171
|
+
return extTransMap
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function getNonRegionalLocale(locale: string): string {
|
|
175
|
+
return locale.split('-')[0]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function getFlattenedLocalization(
|
|
179
|
+
localization?: FlattenedLocalization | Localization | null,
|
|
180
|
+
locales?: LocalesOptions,
|
|
181
|
+
) {
|
|
182
|
+
if (!localization || !locales) {
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (isFlattenedTranslations(localization)) {
|
|
187
|
+
return localization
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const extensionLocale = resolveDevExtensionLocale(localization, locales)
|
|
191
|
+
const translations = JSON.stringify(flattenDevExtensionTranslations(localization, extensionLocale))
|
|
192
|
+
|
|
193
|
+
const flattenedLocalization: FlattenedLocalization = {
|
|
194
|
+
extensionLocale,
|
|
195
|
+
translations,
|
|
196
|
+
lastUpdated: localization.lastUpdated,
|
|
197
|
+
}
|
|
198
|
+
return flattenedLocalization
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function isFlattenedTranslations(
|
|
202
|
+
localization: Localization | FlattenedLocalization,
|
|
203
|
+
): localization is FlattenedLocalization {
|
|
204
|
+
return (
|
|
205
|
+
typeof localization.translations === 'string' &&
|
|
206
|
+
Object.prototype.hasOwnProperty.call(localization, 'extensionLocale')
|
|
207
|
+
)
|
|
208
|
+
}
|